Add initial implementation for HTML Template & Document Fragment

https://html.spec.whatwg.org/multipage/scripting.html#the-template-element
This commit is contained in:
iska
2015-04-16 00:13:15 +02:00
parent 01adbf4437
commit 654dffcc92
9 changed files with 213 additions and 22 deletions
+20
View File
@@ -7,6 +7,12 @@
objects = {
/* Begin PBXBuildFile section */
623406E11ADB04F9004677A3 /* HTMLTemplate.h in Headers */ = {isa = PBXBuildFile; fileRef = 623406DF1ADB04F9004677A3 /* HTMLTemplate.h */; };
623406E21ADB04F9004677A3 /* HTMLTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = 623406E01ADB04F9004677A3 /* HTMLTemplate.m */; };
623406E31ADB04F9004677A3 /* HTMLTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = 623406E01ADB04F9004677A3 /* HTMLTemplate.m */; };
623406E61ADB05AD004677A3 /* HTMLDocumentFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = 623406E41ADB05AD004677A3 /* HTMLDocumentFragment.h */; };
623406E71ADB05AD004677A3 /* HTMLDocumentFragment.m in Sources */ = {isa = PBXBuildFile; fileRef = 623406E51ADB05AD004677A3 /* HTMLDocumentFragment.m */; };
623406E81ADB05AD004677A3 /* HTMLDocumentFragment.m in Sources */ = {isa = PBXBuildFile; fileRef = 623406E51ADB05AD004677A3 /* HTMLDocumentFragment.m */; };
623424881AB467B200726190 /* HTMLOrderedDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 623424861AB467B200726190 /* HTMLOrderedDictionary.h */; };
623424891AB467B200726190 /* HTMLOrderedDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 623424871AB467B200726190 /* HTMLOrderedDictionary.m */; };
6234248A1AB467B200726190 /* HTMLOrderedDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 623424871AB467B200726190 /* HTMLOrderedDictionary.m */; };
@@ -146,6 +152,10 @@
/* Begin PBXFileReference section */
6223211D1A969B9300BACED5 /* HTMLElementTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLElementTypes.h; sourceTree = "<group>"; };
623406DF1ADB04F9004677A3 /* HTMLTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLTemplate.h; sourceTree = "<group>"; };
623406E01ADB04F9004677A3 /* HTMLTemplate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLTemplate.m; sourceTree = "<group>"; };
623406E41ADB05AD004677A3 /* HTMLDocumentFragment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLDocumentFragment.h; sourceTree = "<group>"; };
623406E51ADB05AD004677A3 /* HTMLDocumentFragment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLDocumentFragment.m; sourceTree = "<group>"; };
623424861AB467B200726190 /* HTMLOrderedDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLOrderedDictionary.h; sourceTree = "<group>"; };
623424871AB467B200726190 /* HTMLOrderedDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLOrderedDictionary.m; sourceTree = "<group>"; };
6234584C1A9D2FA4009BD491 /* HTMLNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNode.h; sourceTree = "<group>"; };
@@ -300,6 +310,10 @@
6238579A1A9E8934003A45D9 /* HTMLComment.m */,
62362A3A1A9FA70400301989 /* HTMLText.h */,
62362A3B1A9FA70400301989 /* HTMLText.m */,
623406DF1ADB04F9004677A3 /* HTMLTemplate.h */,
623406E01ADB04F9004677A3 /* HTMLTemplate.m */,
623406E41ADB05AD004677A3 /* HTMLDocumentFragment.h */,
623406E51ADB05AD004677A3 /* HTMLDocumentFragment.m */,
623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */,
623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */,
);
@@ -492,6 +506,7 @@
624493AC19CD0CBE00BCDDF4 /* HTMLToken.h in Headers */,
6235CEA01AA5170A0026937B /* HTMLMarker.h in Headers */,
62F31FDD19E9DCCF007F0657 /* HTMLTokenizerEntities.h in Headers */,
623406E11ADB04F9004677A3 /* HTMLTemplate.h in Headers */,
6234BEEE1AABBF1400DEB15F /* HTMLStackOfOpenElements.h in Headers */,
6238C9851AB8D6330006512E /* HTMLKitExceptions.h in Headers */,
6238039F1AB63A8C008A53D0 /* HTMLEOFToken.h in Headers */,
@@ -507,6 +522,7 @@
62AE593519F97D880043F069 /* HTMLParseErrorToken.h in Headers */,
62AE594919F9948A0043F069 /* HTMLCharacterToken.h in Headers */,
623857961A9E8606003A45D9 /* HTMLDocumentType.h in Headers */,
623406E61ADB05AD004677A3 /* HTMLDocumentFragment.h in Headers */,
62363C3D1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h in Headers */,
62362A3C1A9FA70400301989 /* HTMLText.h in Headers */,
6234584E1A9D2FA4009BD491 /* HTMLNode.h in Headers */,
@@ -671,12 +687,14 @@
62363C3F1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m in Sources */,
623916C51AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */,
62AE593C19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */,
623406E31ADB04F9004677A3 /* HTMLTemplate.m in Sources */,
6238C9871AB8D6330006512E /* HTMLKitExceptions.m in Sources */,
62F873ED19E088C90062683C /* HTMLParser.m in Sources */,
623803A11AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */,
6279F87619E1808D00F12EE5 /* HTMLElement.m in Sources */,
625A150A19C78ABA00AD0C32 /* HTMLInputStreamReader.m in Sources */,
623857931A9E772B003A45D9 /* HTMLDocument.m in Sources */,
623406E81ADB05AD004677A3 /* HTMLDocumentFragment.m in Sources */,
624493A819CCC54100BCDDF4 /* HTMLTokenizer.m in Sources */,
625A14BE19C7829400AD0C32 /* HTMLKit.m in Sources */,
623857981A9E8606003A45D9 /* HTMLDocumentType.m in Sources */,
@@ -717,12 +735,14 @@
62363C3E1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m in Sources */,
623916C41AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */,
62AE593B19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */,
623406E21ADB04F9004677A3 /* HTMLTemplate.m in Sources */,
6238C9861AB8D6330006512E /* HTMLKitExceptions.m in Sources */,
62F873EC19E088C90062683C /* HTMLParser.m in Sources */,
623803A01AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */,
6279F87519E1808D00F12EE5 /* HTMLElement.m in Sources */,
625A150919C78ABA00AD0C32 /* HTMLInputStreamReader.m in Sources */,
623857921A9E772B003A45D9 /* HTMLDocument.m in Sources */,
623406E71ADB05AD004677A3 /* HTMLDocumentFragment.m in Sources */,
624493A719CCC54100BCDDF4 /* HTMLTokenizer.m in Sources */,
625A150219C783DE00AD0C32 /* HTMLKit.m in Sources */,
623857971A9E8606003A45D9 /* HTMLDocumentType.m in Sources */,
+2
View File
@@ -29,4 +29,6 @@ typedef NS_ENUM(short, HTMLDocumentReadyState)
- (HTMLNode *)adoptNode:(HTMLNode *)node;
- (HTMLDocument *)associatedInertTemplateDocument;
@end
+28
View File
@@ -10,15 +10,21 @@
#import "HTMLKitExceptions.h"
@interface HTMLNode (Private)
@property (nonatomic, weak) HTMLDocument *ownerDocument;
@property (nonatomic, weak) HTMLNode *parentNode;
@end
@interface HTMLDocument ()
{
HTMLDocument *_inertTemplateDocument;
}
@property (nonatomic, assign) HTMLDocumentReadyState readyState;
@end
@implementation HTMLDocument
#pragma mark - Init
- (instancetype)init
{
self = [super initWithName:@"#document" type:HTMLNodeDocument];
@@ -28,6 +34,13 @@
return self;
}
#pragma mark - Accessors
- (void)setOwnerDocument:(HTMLDocument *)ownerDocument
{
[self doesNotRecognizeSelector:_cmd];
}
- (void)setDocumentType:(HTMLDocumentType *)documentType
{
if (documentType == nil) {
@@ -44,6 +57,8 @@
}
}
#pragma mark - Mutation Algorithms
- (HTMLNode *)adoptNode:(HTMLNode *)node
{
if (node == nil) {
@@ -56,9 +71,22 @@
}
[node.parentNode removeChildNode:node];
node.ownerDocument = self;
return node;
}
#pragma mark - Template
- (HTMLDocument *)associatedInertTemplateDocument
{
if (_inertTemplateDocument == nil) {
_inertTemplateDocument = [HTMLDocument new];
_inertTemplateDocument.readyState = HTMLDocumentComplete;
}
return _inertTemplateDocument;
}
#pragma mark - Description
- (id)debugQuickLookObject
+15
View File
@@ -0,0 +1,15 @@
//
// HTMLDocumentFragment.h
// HTMLKit
//
// Created by Iska on 12/04/15.
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
#import "HTMLNode.h"
@interface HTMLDocumentFragment : HTMLNode
- (instancetype)initWithDocument:(HTMLDocument *)document;
@end
+44
View File
@@ -0,0 +1,44 @@
//
// HTMLDocumentFragment.m
// HTMLKit
//
// Created by Iska on 12/04/15.
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
#import "HTMLDocumentFragment.h"
#import "HTMLText.h"
@interface HTMLNode ()
@property (nonatomic, weak) HTMLDocument *ownerDocument;
@end
@implementation HTMLDocumentFragment
- (instancetype)initWithDocument:(HTMLDocument *)document
{
self = [super initWithName:@"#document-fragment" type:HTMLNodeDocumentFragment];
if (self) {
self.ownerDocument = document;
}
return self;
}
- (NSString *)textContent
{
NSMutableString *content = [NSMutableString string];
for (HTMLNode *node in self.treeEnumerator) {
if (node.type == HTMLNodeText) {
[content appendString:[(HTMLText *)node data]];
}
}
return content;
}
- (void)setTextContent:(NSString *)textContent
{
HTMLText *node = [[HTMLText alloc] initWithData:textContent];
[self replaceAllChildNodesWithNode:node];
}
@end
+52 -22
View File
@@ -19,9 +19,11 @@
{
NSMutableOrderedSet *_childNodes;
}
@property (nonatomic, weak) HTMLDocument *ownerDocument;
@end
@implementation HTMLNode
@synthesize ownerDocument = _ownerDocument;
#pragma mark - Init
@@ -42,17 +44,21 @@
{
if (_type == HTMLNodeDocument) {
return (HTMLDocument *)self;
} else if (_parentNode == nil) {
return nil;
} else {
return _parentNode.ownerDocument;
return _ownerDocument;
}
}
- (void)setOwnerDocument:(HTMLDocument *)ownerDocument
{
_ownerDocument = ownerDocument;
[self.childNodes.array makeObjectsPerformSelector:@selector(setOwnerDocument:) withObject:ownerDocument];
}
- (void)setBaseURI:(NSString *)baseURI
{
_baseURI = [baseURI copy];
[_childNodes.array makeObjectsPerformSelector:@selector(setBaseURI:) withObject:baseURI];
[self.childNodes.array makeObjectsPerformSelector:@selector(setBaseURI:) withObject:baseURI];
}
- (void)setParentNode:(HTMLNode *)parentNode
@@ -67,12 +73,12 @@
- (HTMLNode *)firstChiledNode
{
return _childNodes.firstObject;
return self.childNodes.firstObject;
}
- (HTMLNode *)lastChildNode
{
return _childNodes.lastObject;
return self.childNodes.lastObject;
}
- (HTMLNode *)previousSibling
@@ -102,12 +108,12 @@
- (BOOL)hasChildNodes
{
return _childNodes.count > 0;
return self.childNodes.count > 0;
}
- (BOOL)hasChildNodeOfType:(HTMLNodeType)type
{
NSUInteger index = [_childNodes indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
NSUInteger index = [self.childNodes indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
if ([(HTMLNode *)obj type] == type) {
*stop = YES;
return YES;
@@ -120,17 +126,17 @@
- (NSUInteger)childNodesCount
{
return _childNodes.count;
return self.childNodes.count;
}
- (HTMLNode *)childNodeAtIndex:(NSUInteger)index
{
return [_childNodes objectAtIndex:index];
return [self.childNodes objectAtIndex:index];
}
- (NSUInteger)indexOfChildNode:(HTMLNode *)node
{
return [_childNodes indexOfObject:node];
return [self.childNodes indexOfObject:node];
}
- (HTMLNode *)insertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child
@@ -161,7 +167,7 @@
[self.ownerDocument adoptNode:node];
NSUInteger index = [self indexOfChildNode:child];
node.parentNode = self;
[_childNodes replaceObjectAtIndex:index withObject:node];
[(NSMutableOrderedSet *)self.childNodes replaceObjectAtIndex:index withObject:node];
return child;
}
@@ -183,7 +189,7 @@
NSStringFromSelector(_cmd), child];
}
[_childNodes removeObject:child];
[(NSMutableOrderedSet *)self.childNodes removeObject:child];
child.parentNode = nil;
return child;
}
@@ -196,7 +202,7 @@
- (void)reparentChildNodesIntoNode:(HTMLNode *)node
{
for (HTMLNode *child in _childNodes.array) {
for (HTMLNode *child in self.childNodes.array) {
[node appendNode:child];
}
[self removeAllChildNodes];
@@ -204,7 +210,7 @@
- (void)removeAllChildNodes
{
[_childNodes removeAllObjects];
[(NSMutableOrderedSet *)self.childNodes removeAllObjects];
}
#pragma mark - Enumeration
@@ -215,7 +221,7 @@
return;
}
[_childNodes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[self.childNodes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
block(obj, idx, stop);
}];
}
@@ -238,9 +244,9 @@
[self.ownerDocument adoptNode:node];
NSUInteger index = [self indexOfChildNode:child];
if (index != NSNotFound) {
[_childNodes insertObject:node atIndex:index];
[(NSMutableOrderedSet *)self.childNodes insertObject:node atIndex:index];
} else {
[_childNodes addObject:node];
[(NSMutableOrderedSet *)self.childNodes addObject:node];
}
return node;
@@ -249,6 +255,7 @@
NS_INLINE void CheckParentValid(HTMLNode *node, NSString *cmd)
{
if (node.type != HTMLNodeDocument &&
node.type != HTMLNodeDocumentFragment &&
node.type != HTMLNodeElement) {
[NSException raise:HTMLKitHierarchyRequestError
format:@"%@: Hierarchy Request Error, inserting into %@ is not allowed. The operation would yield an incorrect node tree.",
@@ -268,8 +275,8 @@ NS_INLINE void CheckChildsParent(HTMLNode *parent, HTMLNode *child, NSString *cm
NS_INLINE void CheckInsertedNodeValid(HTMLNode *node, NSString *cmd)
{
if (node.type != HTMLNodeDocumentType &&
node.type != HTMLNodeElement &&
if (node.type != HTMLNodeDocumentFragment &&
node.type != HTMLNodeDocumentType &&
node.type != HTMLNodeElement &&
node.type != HTMLNodeText &&
node.type != HTMLNodeComment) {
@@ -312,6 +319,18 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin
if (self.type == HTMLNodeDocument) {
switch (node.type) {
case HTMLNodeDocumentFragment:
if (self.childNodesCount > 1 ||
[self hasChildNodeOfType:HTMLNodeText]) {
hierarchyError();
} else if (self.childNodesCount == 1) {
if (self.hasChildNodes ||
child.type == HTMLNodeDocumentType ||
child.nextSibling.type == HTMLNodeDocumentType) {
hierarchyError();
}
}
break;
case HTMLNodeElement:
if ([self hasChildNodeOfType:HTMLNodeElement] ||
child.type == HTMLNodeDocumentType ||
@@ -332,7 +351,7 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin
}
}
- (void)ensureReplacementValidityOfChildNode:(HTMLNode *)node withNode:(HTMLNode *)child
- (void)ensureReplacementValidityOfChildNode:(HTMLNode *)child withNode:(HTMLNode *)node
{
CheckParentValid(self, NSStringFromSelector(_cmd));
@@ -350,6 +369,17 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin
if (self.type == HTMLNodeDocument) {
switch (node.type) {
case HTMLNodeDocumentFragment:
if (self.childNodesCount > 1 ||
[self hasChildNodeOfType:HTMLNodeText]) {
hierarchyError();
} else if (self.childNodesCount == 1) {
if (self.firstChiledNode != node ||
child.nextSibling.type == HTMLNodeDocumentType) {
hierarchyError();
}
}
break;
case HTMLNodeElement:
{
if (child.nextSibling.type == HTMLNodeDocumentType) {
@@ -400,7 +430,7 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin
- (NSString *)innerHTML
{
return [[_childNodes.array valueForKey:@"outerHTML"] componentsJoinedByString:@""];
return [[self.childNodes.array valueForKey:@"outerHTML"] componentsJoinedByString:@""];
}
#pragma mark - Description
+2
View File
@@ -12,3 +12,5 @@
#import "HTMLElement.h"
#import "HTMLComment.h"
#import "HTMLText.h"
#import "HTMLTemplate.h"
#import "HTMLDocumentFragment.h"
+16
View File
@@ -0,0 +1,16 @@
//
// HTMLTemplate.h
// HTMLKit
//
// Created by Iska on 12/04/15.
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
#import "HTMLElement.h"
#import "HTMLDocumentFragment.h"
@interface HTMLTemplate : HTMLElement
@property (nonatomic, strong) HTMLDocumentFragment *content;
@end
+34
View File
@@ -0,0 +1,34 @@
//
// HTMLTemplate.m
// HTMLKit
//
// Created by Iska on 12/04/15.
// Copyright (c) 2015 BrainCookie. All rights reserved.
//
#import "HTMLTemplate.h"
#import "HTMLDocument.h"
@implementation HTMLTemplate
- (instancetype)init
{
self = [super initWithTagName:@"template"];
return self;
}
- (HTMLDocumentFragment *)content
{
if (_content == nil) {
_content = [[HTMLDocumentFragment alloc] initWithDocument:self.ownerDocument.associatedInertTemplateDocument];
}
return _content;
}
- (NSOrderedSet *)childNodes
{
return self.content.childNodes;
}
@end