Move source code to Sources directory
This commit is contained in:
@@ -0,0 +1,329 @@
|
||||
//
|
||||
// HTMLStackOfOpenElements.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 08/03/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLStackOfOpenElements.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
#import "HTMLElementTypes.h"
|
||||
#import "HTMLTemplate.h"
|
||||
|
||||
@interface HTMLStackOfOpenElements ()
|
||||
{
|
||||
NSMutableArray *_stack;
|
||||
NSDictionary *_specificScopeElementTypes;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLStackOfOpenElements
|
||||
|
||||
#pragma mark - Init
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_stack = [NSMutableArray new];
|
||||
_specificScopeElementTypes = @{
|
||||
@"applet": @(HTMLNamespaceHTML),
|
||||
@"caption": @(HTMLNamespaceHTML),
|
||||
@"html": @(HTMLNamespaceHTML),
|
||||
@"table": @(HTMLNamespaceHTML),
|
||||
@"td": @(HTMLNamespaceHTML),
|
||||
@"th": @(HTMLNamespaceHTML),
|
||||
@"marquee": @(HTMLNamespaceHTML),
|
||||
@"object": @(HTMLNamespaceHTML),
|
||||
@"template": @(HTMLNamespaceHTML),
|
||||
@"mi": @(HTMLNamespaceMathML),
|
||||
@"mo": @(HTMLNamespaceMathML),
|
||||
@"mn": @(HTMLNamespaceMathML),
|
||||
@"ms": @(HTMLNamespaceMathML),
|
||||
@"mtext": @(HTMLNamespaceMathML),
|
||||
@"annotation-xml": @(HTMLNamespaceMathML),
|
||||
@"foreignObject": @(HTMLNamespaceSVG),
|
||||
@"desc": @(HTMLNamespaceSVG),
|
||||
@"title": @(HTMLNamespaceSVG)
|
||||
};
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Node Access
|
||||
|
||||
- (HTMLElement *)currentNode
|
||||
{
|
||||
return _stack.lastObject;
|
||||
}
|
||||
|
||||
- (HTMLElement *)firstNode
|
||||
{
|
||||
return _stack.firstObject;
|
||||
}
|
||||
|
||||
- (HTMLElement *)lastNode
|
||||
{
|
||||
return _stack.lastObject;
|
||||
}
|
||||
|
||||
- (id)objectAtIndexedSubscript:(NSUInteger)index;
|
||||
{
|
||||
return [_stack objectAtIndex:index];
|
||||
}
|
||||
|
||||
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx
|
||||
{
|
||||
[_stack setObject:obj atIndexedSubscript:idx];
|
||||
}
|
||||
|
||||
- (NSUInteger)indexOfElement:(id)node
|
||||
{
|
||||
return [_stack indexOfObject:node];
|
||||
}
|
||||
|
||||
- (void)pushElement:(HTMLElement *)element
|
||||
{
|
||||
[_stack addObject:element];
|
||||
}
|
||||
|
||||
- (void)removeElement:(id)element
|
||||
{
|
||||
[_stack removeObject:element];
|
||||
}
|
||||
|
||||
- (BOOL)containsElement:(id)element
|
||||
{
|
||||
return [_stack containsObject:element];
|
||||
}
|
||||
|
||||
- (BOOL)containsElementWithTagName:(NSString *)tagName
|
||||
{
|
||||
NSUInteger index = [_stack indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
|
||||
if ([[(HTMLElement *)obj tagName] isEqualToString:tagName]) {
|
||||
*stop = YES;
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}];
|
||||
return index != NSNotFound;
|
||||
}
|
||||
|
||||
- (void)insertElement:(HTMLElement *)element atIndex:(NSUInteger)index
|
||||
{
|
||||
[_stack insertObject:element atIndex:index];
|
||||
}
|
||||
|
||||
- (void)replaceElementAtIndex:(NSUInteger)index withElement:(HTMLElement *)element
|
||||
{
|
||||
[_stack replaceObjectAtIndex:index withObject:element];
|
||||
}
|
||||
|
||||
#pragma mark - Pops
|
||||
|
||||
- (void)popCurrentNode
|
||||
{
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
|
||||
- (void)popElementsUntilElementPoppedWithTagName:(NSString *)tagName
|
||||
{
|
||||
while (self.currentNode) {
|
||||
if (self.currentNode.htmlNamespace == HTMLNamespaceHTML &&
|
||||
[self.currentNode.tagName isEqualToString:tagName]) {
|
||||
break;
|
||||
}
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
|
||||
- (void)popElementsUntilAnElementPoppedWithAnyOfTagNames:(NSArray *)tagNames
|
||||
{
|
||||
while (self.currentNode) {
|
||||
if (self.currentNode.htmlNamespace == HTMLNamespaceHTML &&
|
||||
[tagNames containsObject:self.currentNode.tagName]) {
|
||||
break;
|
||||
}
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
|
||||
- (void)popElementsUntilElementPopped:(HTMLElement *)element
|
||||
{
|
||||
while (self.currentNode && ![self.currentNode isEqual:element]) {
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
|
||||
- (void)popElementsUntilTemplateElementPopped
|
||||
{
|
||||
while (self.currentNode && ![self.currentNode isKindOfClass:[HTMLTemplate class]]) {
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
|
||||
- (void)clearBackToTableContext
|
||||
{
|
||||
while (self.currentNode && ![self.currentNode.tagName isEqualToAny:@"table", @"template", @"html", nil]) {
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clearBackToTableBodyContext
|
||||
{
|
||||
while (![self.currentNode.tagName isEqualToAny:@"tbody", @"tfoot", @"thead", @"template", @"html", nil]) {
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clearBackToTableRowContext
|
||||
{
|
||||
while (![self.currentNode.tagName isEqualToAny:@"tr", @"template", @"html", nil]) {
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)popAll
|
||||
{
|
||||
[_stack removeAllObjects];
|
||||
}
|
||||
|
||||
#pragma mark - Element Scope
|
||||
|
||||
- (HTMLElement *)hasElementInScopeWithTagName:(NSString *)tagName;
|
||||
{
|
||||
return [self hasAnyElementInSpecificScopeWithTagNames:@[tagName] andElementTypes:_specificScopeElementTypes];
|
||||
}
|
||||
|
||||
- (HTMLElement *)hasAnyElementInScopeWithAnyOfTagNames:(NSArray *)tagNames
|
||||
{
|
||||
return [self hasAnyElementInSpecificScopeWithTagNames:tagNames andElementTypes:_specificScopeElementTypes];
|
||||
}
|
||||
|
||||
- (HTMLElement *)hasElementInListItemScopeWithTagName:(NSString *)tagName
|
||||
{
|
||||
NSMutableDictionary *elementTypes = [NSMutableDictionary dictionaryWithDictionary:_specificScopeElementTypes];
|
||||
[elementTypes addEntriesFromDictionary:@{@"ol": @(HTMLNamespaceHTML),
|
||||
@"ul": @(HTMLNamespaceHTML)}];
|
||||
|
||||
return [self hasElementInSpecificScopeWithTagName:tagName
|
||||
andElementTypes:elementTypes];
|
||||
}
|
||||
|
||||
- (HTMLElement *)hasElementInButtonScopeWithTagName:(NSString *)tagName
|
||||
{
|
||||
NSMutableDictionary *elementTypes = [NSMutableDictionary dictionaryWithDictionary:_specificScopeElementTypes];
|
||||
[elementTypes addEntriesFromDictionary:@{@"button": @(HTMLNamespaceHTML)}];
|
||||
|
||||
return [self hasElementInSpecificScopeWithTagName:tagName
|
||||
andElementTypes:elementTypes];
|
||||
}
|
||||
|
||||
- (HTMLElement *)hasElementInTableScopeWithTagName:(NSString *)tagName
|
||||
{
|
||||
return [self hasElementInSpecificScopeWithTagName:tagName
|
||||
andElementTypes:@{@"html": @(HTMLNamespaceHTML),
|
||||
@"table": @(HTMLNamespaceHTML),
|
||||
@"template": @(HTMLNamespaceHTML)}];
|
||||
}
|
||||
|
||||
- (HTMLElement *)hasElementInTableScopeWithAnyOfTagNames:(NSArray *)tagNames
|
||||
{
|
||||
return [self hasAnyElementInSpecificScopeWithTagNames:tagNames
|
||||
andElementTypes:@{@"html": @(HTMLNamespaceHTML),
|
||||
@"table": @(HTMLNamespaceHTML),
|
||||
@"template": @(HTMLNamespaceHTML)}];
|
||||
}
|
||||
|
||||
- (HTMLElement *)hasElementInSelectScopeWithTagName:(NSString *)tagName
|
||||
{
|
||||
for (HTMLElement *node in _stack.reverseObjectEnumerator) {
|
||||
if ([node.tagName isEqualToString:tagName]) {
|
||||
return node;
|
||||
}
|
||||
if (!(node.htmlNamespace == HTMLNamespaceHTML &&
|
||||
[node.tagName isEqualToAny:@"optgroup", @"option", nil])) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (HTMLElement *)hasElementInSpecificScopeWithTagName:(NSString *)tagName
|
||||
andElementTypes:(NSDictionary *)elementTypes
|
||||
{
|
||||
return [self hasAnyElementInSpecificScopeWithTagNames:@[tagName] andElementTypes:elementTypes];
|
||||
}
|
||||
|
||||
- (HTMLElement *)hasAnyElementInSpecificScopeWithTagNames:(NSArray *)tagNames
|
||||
andElementTypes:(NSDictionary *)elementTypes
|
||||
{
|
||||
for (HTMLElement *node in _stack.reverseObjectEnumerator) {
|
||||
if ([tagNames containsObject:node.tagName]) {
|
||||
NSNumber *namespace = elementTypes[node.tagName] ?: @(HTMLNamespaceHTML);
|
||||
if ([namespace isEqual:@(node.htmlNamespace)]) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
if ([elementTypes[node.tagName] isEqual:@(node.htmlNamespace)]) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (HTMLElement *)furthestBlockAfterIndex:(NSUInteger)index
|
||||
{
|
||||
for (NSUInteger i = index; i < _stack.count; i++) {
|
||||
HTMLElement *element = _stack[i];
|
||||
if (IsSpecialElement(element)) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - Count
|
||||
|
||||
- (NSUInteger)count
|
||||
{
|
||||
return _stack.count;
|
||||
}
|
||||
|
||||
- (BOOL)isEmpy
|
||||
{
|
||||
return _stack.count == 0;
|
||||
}
|
||||
|
||||
#pragma mark - Enumeraiton
|
||||
|
||||
- (NSEnumerator *)enumerator
|
||||
{
|
||||
return _stack.objectEnumerator;
|
||||
}
|
||||
|
||||
- (NSEnumerator *)reverseObjectEnumerator
|
||||
{
|
||||
return _stack.reverseObjectEnumerator;
|
||||
}
|
||||
|
||||
#pragma mark - NSFastEnumeration
|
||||
|
||||
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len
|
||||
{
|
||||
return [_stack countByEnumeratingWithState:state objects:buffer count:len];
|
||||
}
|
||||
|
||||
#pragma mark - Description
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return _stack.description;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user