diff --git a/HTMLKit/HTMLCharacterToken.h b/HTMLKit/HTMLCharacterToken.h index 54841d8..f03dc58 100644 --- a/HTMLKit/HTMLCharacterToken.h +++ b/HTMLKit/HTMLCharacterToken.h @@ -17,4 +17,5 @@ - (void)appendString:(NSString *)string; +- (BOOL)isWhitespaceToken; @end diff --git a/HTMLKit/HTMLCharacterToken.m b/HTMLKit/HTMLCharacterToken.m index 47bceb9..33c4da3 100644 --- a/HTMLKit/HTMLCharacterToken.m +++ b/HTMLKit/HTMLCharacterToken.m @@ -33,6 +33,12 @@ [_characters appendString:string]; } +- (BOOL)isWhitespaceToken +{ + NSCharacterSet *set = [[NSCharacterSet characterSetWithCharactersInString:@" \t\n\f"] invertedSet]; + return [_characters rangeOfCharacterFromSet:set].location == NSNotFound; +} + #pragma mark - NSObject - (BOOL)isEqual:(id)other diff --git a/HTMLKit/HTMLElement.h b/HTMLKit/HTMLElement.h index 012b88d..0ddbafd 100644 --- a/HTMLKit/HTMLElement.h +++ b/HTMLKit/HTMLElement.h @@ -13,5 +13,6 @@ @property (nonatomic, strong, readonly) NSString *tagName; @property (nonatomic, assign, readonly) HTMLNamespace namespace; +@property (nonatomic, strong, readonly) id parentNode; @end diff --git a/HTMLKit/HTMLParser.m b/HTMLKit/HTMLParser.m index e4ff477..c0479d4 100644 --- a/HTMLKit/HTMLParser.m +++ b/HTMLKit/HTMLParser.m @@ -9,6 +9,7 @@ #import "HTMLParser.h" #import "HTMLTokenizer.h" #import "HTMLTokens.h" +#import "HTMLCharacterToken.h" #import "HTMLParserInsertionModes.h" #import "HTMLElement.h" #import "HTMLElementTypes.h" @@ -17,6 +18,8 @@ { HTMLTokenizer *_tokenizer; + NSMutableArray *_errors; + NSMutableDictionary *_insertionModes; HTMLInsertionMode _insertionMode; HTMLInsertionMode _originalInsertionMode; @@ -31,6 +34,7 @@ BOOL _scriptingFlag; BOOL _fragmentParsingAlgorithm; + BOOL _fosterParting; } @end @@ -42,6 +46,8 @@ { self = [super init]; if (self) { + _errors = [NSMutableArray new]; + _insertionModes = [NSMutableDictionary new]; _insertionMode = HTMLInsertionModeInitial; [self setupStateMachine]; @@ -76,6 +82,17 @@ return [self currentNode]; } +#pragma mark - Emits + +- (void)emitParseError:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2) +{ + va_list args; + va_start(args, format); + NSString *message = [[NSString alloc] initWithFormat:format arguments:args]; + [_errors addObject:message]; + va_end(args); +} + #pragma mark - State Machine - (void)switchInsertionMode:(HTMLInsertionMode)mode @@ -206,12 +223,13 @@ - (id)parse { for (HTMLToken *token in _tokenizer) { - [self handleToken:token]; + [self processToken:token]; } return nil; } -- (void)handleToken:(HTMLToken *)token + +- (void)processToken:(HTMLToken *)token { BOOL (^ treeConstructionDispatcher)(HTMLElement *node) = ^BOOL(HTMLElement *node){ @@ -245,13 +263,18 @@ }; if (treeConstructionDispatcher(self.adjustedCurrentNode)) { - [self handleToken:token byApplyingRulesForInsertionMode:_insertionMode]; + [self processToken:token byApplyingRulesForInsertionMode:_insertionMode]; } else { - [self handleTokenByApplyingRulesForParsingTokensInForeignContent:token]; + [self processTokenByApplyingRulesForParsingTokensInForeignContent:token]; } } -- (void)handleToken:(HTMLToken *)token byApplyingRulesForInsertionMode:(HTMLInsertionMode)insertionMode +- (void)reprocessToken:(HTMLToken *)token +{ + [self processToken:token]; +} + +- (void)processToken:(HTMLToken *)token byApplyingRulesForInsertionMode:(HTMLInsertionMode)insertionMode { SEL selector = [[_insertionModes objectForKey:@(_insertionMode)] pointerValue]; if ([self respondsToSelector:selector]) { @@ -263,9 +286,49 @@ } } -- (void)handleTokenByApplyingRulesForParsingTokensInForeignContent:(HTMLToken *)token +- (void)processTokenByApplyingRulesForParsingTokensInForeignContent:(HTMLToken *)token { + +#pragma mark - + +- (HTMLElement *)appropriatePlaceForInsertingANodeWithOverrideTarget:(id)overrideTarget +{ + HTMLElement *target = self.currentNode; + if (overrideTarget == nil) { + target = overrideTarget; + } + + if (_fosterParting && matches(target.tagName, @"table", @"tbody", @"tfoot", @"thead", @"tr")) { + HTMLElement *lastTemplate = nil; + HTMLElement *lastTable = nil; + for (HTMLElement *element in _stackOfOpenElements.reverseObjectEnumerator) { + if ([element.tagName isEqualToString:@"template"]) { + lastTemplate = element; + break; + } + if ([element.tagName isEqualToString:@"table"]) { + lastTable = element; + break; + } + } + if (lastTemplate != nil) { +#warning Implement HTML Template + return nil; + } + if (lastTable == nil) { + HTMLElement *htmlElement = _stackOfOpenElements.firstObject; + return htmlElement; + } + if (lastTable.parentNode != nil) { + return lastTable.parentNode; + } + NSUInteger lastTableIndex = [_stackOfOpenElements indexOfObject:lastTable]; + HTMLElement *previousNode = _stackOfOpenElements[lastTableIndex]; + return previousNode; + } else { + return target; + } } #pragma mark - Insertion Modes diff --git a/HTMLKit/HTMLParserInsertionModes.h b/HTMLKit/HTMLParserInsertionModes.h index 7b89ee8..838e164 100644 --- a/HTMLKit/HTMLParserInsertionModes.h +++ b/HTMLKit/HTMLParserInsertionModes.h @@ -29,7 +29,9 @@ MODE_ENTRY( HTMLInsertionModeInFrameset, ) \ MODE_ENTRY( HTMLInsertionModeAfterFrameset, ) \ MODE_ENTRY( HTMLInsertionModeAfterAfterBody, ) \ - MODE_ENTRY( HTMLInsertionModeAfterAfterFrameset, ) + MODE_ENTRY( HTMLInsertionModeAfterAfterFrameset, ) \ + MODE_ENTRY( HTMLInsertionModeCurrentTemplate, ) \ + MODE_ENTRY( HTMLInsertionModesCount, ) typedef NS_ENUM(NSUInteger, HTMLInsertionMode) { @@ -37,3 +39,9 @@ typedef NS_ENUM(NSUInteger, HTMLInsertionMode) INSERTION_MODES #undef MODE_ENTRY }; + +static NSString * HTMLInsertionModesTable[] = { +#define MODE_ENTRY( name, value ) [name] = @#name, + INSERTION_MODES +#undef MODE_ENTRY +};