diff --git a/HTMLKit.xcodeproj/project.pbxproj b/HTMLKit.xcodeproj/project.pbxproj
index 909fc1f..a852c15 100644
--- a/HTMLKit.xcodeproj/project.pbxproj
+++ b/HTMLKit.xcodeproj/project.pbxproj
@@ -7,6 +7,9 @@
objects = {
/* Begin PBXBuildFile section */
+ 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 */; };
6234584E1A9D2FA4009BD491 /* HTMLNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 6234584C1A9D2FA4009BD491 /* HTMLNode.h */; };
6234584F1A9D2FA4009BD491 /* HTMLNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 6234584D1A9D2FA4009BD491 /* HTMLNode.m */; };
623458501A9D2FA4009BD491 /* HTMLNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 6234584D1A9D2FA4009BD491 /* HTMLNode.m */; };
@@ -123,10 +126,13 @@
/* Begin PBXFileReference section */
6223211D1A969B9300BACED5 /* HTMLElementTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLElementTypes.h; sourceTree = ""; };
+ 623424861AB467B200726190 /* HTMLOrderedDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLOrderedDictionary.h; sourceTree = ""; };
+ 623424871AB467B200726190 /* HTMLOrderedDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLOrderedDictionary.m; sourceTree = ""; };
6234584C1A9D2FA4009BD491 /* HTMLNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNode.h; sourceTree = ""; };
6234584D1A9D2FA4009BD491 /* HTMLNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNode.m; sourceTree = ""; };
6234BEEC1AABBF1400DEB15F /* HTMLStackOfOpenElements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLStackOfOpenElements.h; sourceTree = ""; };
6234BEED1AABBF1400DEB15F /* HTMLStackOfOpenElements.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLStackOfOpenElements.m; sourceTree = ""; };
+ 6234C3361AB3BF710046F527 /* HTMLElementAdjustment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLElementAdjustment.h; sourceTree = ""; };
6235CE991AA509430026937B /* NSString+HTMLKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+HTMLKit.h"; sourceTree = ""; };
6235CE9A1AA509430026937B /* NSString+HTMLKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+HTMLKit.m"; sourceTree = ""; };
6235CE9E1AA5170A0026937B /* HTMLMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLMarker.h; sourceTree = ""; };
@@ -309,9 +315,12 @@
6234BEED1AABBF1400DEB15F /* HTMLStackOfOpenElements.m */,
628B7CE61A080E1000602C87 /* HTMLNamespaces.h */,
6223211D1A969B9300BACED5 /* HTMLElementTypes.h */,
+ 6234C3361AB3BF710046F527 /* HTMLElementAdjustment.h */,
6279F87119E17DC700F12EE5 /* HTMLParserInsertionModes.h */,
6235CE9E1AA5170A0026937B /* HTMLMarker.h */,
6235CE9F1AA5170A0026937B /* HTMLMarker.m */,
+ 623424861AB467B200726190 /* HTMLOrderedDictionary.h */,
+ 623424871AB467B200726190 /* HTMLOrderedDictionary.m */,
6235CE991AA509430026937B /* NSString+HTMLKit.h */,
6235CE9A1AA509430026937B /* NSString+HTMLKit.m */,
623719441AA1472B002E03C8 /* Nodes */,
@@ -404,6 +413,7 @@
623857911A9E772B003A45D9 /* HTMLDocument.h in Headers */,
624493A619CCC54100BCDDF4 /* HTMLTokenizer.h in Headers */,
62AE593A19F97E1C0043F069 /* HTMLDOCTYPEToken.h in Headers */,
+ 623424881AB467B200726190 /* HTMLOrderedDictionary.h in Headers */,
625A150419C783EB00AD0C32 /* HTMLKit.h in Headers */,
625A150819C78ABA00AD0C32 /* HTMLInputStreamReader.h in Headers */,
6238579B1A9E8934003A45D9 /* HTMLComment.h in Headers */,
@@ -567,6 +577,7 @@
6234BEF01AABBF1400DEB15F /* HTMLStackOfOpenElements.m in Sources */,
624493AE19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */,
6235CEA21AA5170A0026937B /* HTMLMarker.m in Sources */,
+ 6234248A1AB467B200726190 /* HTMLOrderedDictionary.m in Sources */,
62AE594119F9907C0043F069 /* HTMLTagToken.m in Sources */,
62AE594619F992F30043F069 /* HTMLCommentToken.m in Sources */,
62AE593C19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */,
@@ -604,6 +615,7 @@
6234BEEF1AABBF1400DEB15F /* HTMLStackOfOpenElements.m in Sources */,
624493AD19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */,
6235CEA11AA5170A0026937B /* HTMLMarker.m in Sources */,
+ 623424891AB467B200726190 /* HTMLOrderedDictionary.m in Sources */,
62AE594019F9907C0043F069 /* HTMLTagToken.m in Sources */,
62AE594519F992F30043F069 /* HTMLCommentToken.m in Sources */,
62AE593B19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */,
diff --git a/HTMLKit/HTMLElementAdjustment.h b/HTMLKit/HTMLElementAdjustment.h
new file mode 100644
index 0000000..138f30d
--- /dev/null
+++ b/HTMLKit/HTMLElementAdjustment.h
@@ -0,0 +1,13 @@
+//
+// HTMLElementAdjustment.h
+// HTMLKit
+//
+// Created by Iska on 14/03/15.
+// Copyright (c) 2015 BrainCookie. All rights reserved.
+//
+
+#ifndef HTMLKit_HTMLElementAdjustment_h
+#define HTMLKit_HTMLElementAdjustment_h
+
+
+#endif
diff --git a/HTMLKit/HTMLOrderedDictionary.h b/HTMLKit/HTMLOrderedDictionary.h
new file mode 100644
index 0000000..d936243
--- /dev/null
+++ b/HTMLKit/HTMLOrderedDictionary.h
@@ -0,0 +1,25 @@
+//
+// HTMLOrderedDictionary.h
+// HTMLKit
+//
+// Created by Iska on 14/03/15.
+// Copyright (c) 2015 BrainCookie. All rights reserved.
+//
+
+#import
+
+@interface HTMLOrderedDictionary : NSMutableDictionary
+
+- (id)objectAtIndex:(NSUInteger)index;
+- (void)setObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)index;
+- (void)removeObjectAtIndex:(NSUInteger)index;
+- (void)replaceKeyValueAtIndex:(NSUInteger)index withObject:(id)anObject andKey:(id)aKey;
+- (void)replaceKey:(id)aKey withKey:(id)newKey;
+- (NSUInteger)indexOfKey:(id)aKey;
+
+- (id)objectAtIndexedSubscript:(NSUInteger)index;
+- (void)setObject:(id)obj forIndexedSubscript:(NSUInteger)index;
+
+- (NSEnumerator *)reverseKeyEnumerator;
+
+@end
diff --git a/HTMLKit/HTMLOrderedDictionary.m b/HTMLKit/HTMLOrderedDictionary.m
new file mode 100644
index 0000000..0354201
--- /dev/null
+++ b/HTMLKit/HTMLOrderedDictionary.m
@@ -0,0 +1,172 @@
+//
+// HTMLOrderedDictionary.m
+// HTMLKit
+//
+// Created by Iska on 14/03/15.
+// Copyright (c) 2015 BrainCookie. All rights reserved.
+//
+
+#import "HTMLOrderedDictionary.h"
+
+@interface HTMLOrderedDictionary ()
+{
+ NSMutableDictionary *_dictionary;
+ NSMutableArray *_keys;
+}
+@end
+
+@implementation HTMLOrderedDictionary
+
+#pragma mark - Init
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wobjc-designated-initializers"
+- (instancetype)init
+{
+ return [self initWithCapacity:0];
+}
+#pragma clang diagnostic pop
+
+- (instancetype)initWithCapacity:(NSUInteger)capacity
+{
+ self = [super init];
+ if (self) {
+ _dictionary = [[NSMutableDictionary alloc] initWithCapacity:capacity];
+ _keys = [[NSMutableArray alloc] initWithCapacity:capacity];
+ }
+ return self;
+}
+
+- (instancetype)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys
+{
+ self = [self initWithCapacity:objects.count];
+ if (self) {
+ [objects enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+ _dictionary[keys[idx]] = obj;
+ }];
+ }
+ return self;
+}
+
+#pragma mark - Access
+
+- (id)objectForKey:(id)aKey
+{
+ return _dictionary[aKey];
+}
+
+- (void)setObject:(id)anObject forKey:(id)aKey
+{
+ if (_dictionary[aKey] != nil) {
+ [_keys addObject:aKey];
+ }
+ _dictionary[aKey] = anObject;
+}
+
+- (void)removeObjectForKey:(id)aKey
+{
+ [_keys removeObject:aKey];
+ [_dictionary removeObjectForKey:aKey];
+}
+
+- (NSUInteger)count
+{
+ return _keys.count;
+}
+
+#pragma mark - Indexed Access
+
+- (id)objectAtIndex:(NSUInteger)index
+{
+ if (index >= _keys.count) {
+ return nil;
+ }
+ return _dictionary[_keys[index]];
+}
+
+- (void)setObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)index
+{
+ if (index >= _keys.count) {
+ return;
+ }
+ [_keys replaceObjectAtIndex:index withObject:aKey];
+ _dictionary[aKey] = anObject;
+}
+
+- (void)removeObjectAtIndex:(NSUInteger)index
+{
+ if (index >= _keys.count) {
+ return;
+ }
+ if (_dictionary[_keys[index]]){
+ [_dictionary removeObjectForKey:_keys[index]];
+ [_keys removeObjectAtIndex:index];
+ }
+}
+
+- (void)replaceKeyValueAtIndex:(NSUInteger)index withObject:(id)anObject andKey:(id)aKey
+{
+ if (index >= _keys.count) {
+ return;
+ }
+ [_dictionary removeObjectForKey:_keys[index]];
+ [_keys replaceObjectAtIndex:index withObject:aKey];
+ _dictionary[aKey] = anObject;
+}
+
+- (void)replaceKey:(id)aKey withKey:(id)newKey
+{
+ id value = _dictionary[aKey];
+ if (value != nil) {
+ NSUInteger index = [_keys indexOfObject:aKey];
+ [_keys replaceObjectAtIndex:index withObject:newKey];
+ [_dictionary removeObjectForKey:aKey];
+ _dictionary[newKey] = value;
+ }
+}
+
+- (NSUInteger)indexOfKey:(id)aKey
+{
+ return [_keys indexOfObject:aKey];
+}
+
+#pragma mark - Subscript
+
+- (id)objectAtIndexedSubscript:(NSUInteger)index
+{
+ if (index >= _keys.count) {
+ return nil;
+ }
+ return _dictionary[_keys[index]];
+}
+
+- (void)setObject:(id)obj forIndexedSubscript:(NSUInteger)index
+{
+ if (index < _keys.count) {
+ _dictionary[_keys[index]] = obj;
+ }
+}
+
+- (void)setObject:(id)obj forKeyedSubscript:(id)key
+{
+ [self setObject:obj forKey:key];
+}
+
+#pragma mark - Enumeration
+
+- (NSEnumerator *)keyEnumerator
+{
+ return _keys.objectEnumerator;
+}
+
+- (NSEnumerator *)reverseKeyEnumerator
+{
+ return _keys.reverseObjectEnumerator;
+}
+
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id [])buffer count:(NSUInteger)len
+{
+ return [_keys countByEnumeratingWithState:state objects:buffer count:len];
+}
+
+@end
diff --git a/HTMLKit/HTMLTagToken.h b/HTMLKit/HTMLTagToken.h
index 7b9987f..2107f58 100644
--- a/HTMLKit/HTMLTagToken.h
+++ b/HTMLKit/HTMLTagToken.h
@@ -8,12 +8,12 @@
#import
#import "HTMLToken.h"
+#import "HTMLOrderedDictionary.h"
@interface HTMLTagToken : HTMLToken
@property (nonatomic, copy) NSString *tagName;
-#warning Implement Ordered Dictionary
-@property (nonatomic, strong) NSMutableDictionary *attributes;
+@property (nonatomic, strong) HTMLOrderedDictionary *attributes;
@property (nonatomic, assign, getter = isSelfClosing) BOOL selfClosing;
- (instancetype)initWithTagName:(NSString *)tagName;
diff --git a/HTMLKit/HTMLTagToken.m b/HTMLKit/HTMLTagToken.m
index 39eee74..31be545 100644
--- a/HTMLKit/HTMLTagToken.m
+++ b/HTMLKit/HTMLTagToken.m
@@ -11,8 +11,7 @@
@interface HTMLTagToken ()
{
NSMutableString *_tagName;
-#warning Implement Ordered Dictionary
- NSMutableDictionary *_attributes;
+ HTMLOrderedDictionary *_attributes;
}
@end
@@ -30,8 +29,8 @@
self = [super init];
if (self) {
_tagName = [tagName mutableCopy];
- _attributes = [NSMutableDictionary new];
if (attributes != nil) {
+ _attributes = [HTMLOrderedDictionary new];
[_attributes addEntriesFromDictionary:attributes];
}
}
@@ -48,6 +47,7 @@
@end
+#pragma mark - Start Tag Token
@implementation HTMLStartTagToken
@@ -65,8 +65,6 @@
return self;
}
-#pragma mark - NSObject
-
- (BOOL)isEqual:(id)other
{
if ([other isKindOfClass:[self class]]) {
@@ -90,6 +88,8 @@
@end
+#pragma mark - End Tag Token
+
@implementation HTMLEndTagToken
- (instancetype)initWithTagName:(NSString *)tagName
@@ -106,8 +106,6 @@
return self;
}
-#pragma mark - NSObject
-
- (BOOL)isEqual:(id)other
{
if ([other isKindOfClass:[self class]]) {
diff --git a/HTMLKit/HTMLTokenizer.m b/HTMLKit/HTMLTokenizer.m
index ef41dad..a4c4df4 100644
--- a/HTMLKit/HTMLTokenizer.m
+++ b/HTMLKit/HTMLTokenizer.m
@@ -241,7 +241,7 @@
{
if (_currentAttributeName != nil) {
if (_currentTagToken.attributes == nil) {
- _currentTagToken.attributes = [NSMutableDictionary new];
+ _currentTagToken.attributes = [HTMLOrderedDictionary new];
}
if (_currentTagToken.attributes[_currentAttributeName] != nil) {
diff --git a/HTMLKitTests/HTML5LibTest.m b/HTMLKitTests/HTML5LibTest.m
index 2e6eff1..da12b7d 100644
--- a/HTMLKitTests/HTML5LibTest.m
+++ b/HTMLKitTests/HTML5LibTest.m
@@ -107,7 +107,7 @@
HTMLStartTagToken *token = [[HTMLStartTagToken alloc] initWithTagName:data];
NSDictionary *attributes = output[2];
if (attributes && attributes.allKeys.count > 0) {
- token.attributes = [NSMutableDictionary new];
+ token.attributes = [HTMLOrderedDictionary new];
}
for (NSString *name in attributes) {
NSString *value = [attributes objectForKey:name];
diff --git a/HTMLKitTests/HTMLTokenizerTests.m b/HTMLKitTests/HTMLTokenizerTests.m
index fa9ddd9..d5a369b 100644
--- a/HTMLKitTests/HTMLTokenizerTests.m
+++ b/HTMLKitTests/HTMLTokenizerTests.m
@@ -58,7 +58,7 @@ static NSString * const TOKENIZER = @"tokenizer";
NSArray *expectedTokens = test.output;
NSArray *tokens = [tokenizer allTokens];
- XCTAssertEqualObjects(tokens, expectedTokens, @"%@", test.description);
+ XCTAssertEqualObjects(tokens, expectedTokens, @"%@", test.title);
}
}
}