Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8aabc94fdb | |||
| c2acbb6344 | |||
| a6e4aac937 | |||
| 899438fa24 | |||
| 137fa8617e | |||
| 70abd998f7 | |||
| bb948e0ef8 | |||
| b0bad5068f | |||
| a01f1c1c5b | |||
| 6967798823 | |||
| 58b60dd390 | |||
| 4441b7decd | |||
| 0b2681f8a8 | |||
| 1e07acd032 | |||
| 432df997b3 | |||
| c9d72646bc | |||
| 1af25abadb | |||
| 75138cc35f | |||
| 93401e4054 | |||
| 25ad5a3f82 |
+129
@@ -0,0 +1,129 @@
|
||||
# Change Log
|
||||
|
||||
## [0.9.2](https://github.com/iabudiab/HTMLKit/releases/tag/0.9.2)
|
||||
|
||||
Released on 2016.05.18
|
||||
|
||||
This release passes all html5lib-tests as of 2016.05.18
|
||||
|
||||
### Added
|
||||
|
||||
- Handling for `<menu>` and `<menuitem>`
|
||||
- Changelog
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated adoption agency algorithm according to the latest specification, see:
|
||||
- [whatwg/html@22ce3c3](https://github.com/whatwg/html/commit/22ce3c3)
|
||||
- [Mozilla Bug 901319](https://bugzilla.mozilla.org/show_bug.cgi?id=901319)
|
||||
- [Chrome Issue 268121](https://bugs.chromium.org/p/chromium/issues/detail?id=268121)
|
||||
- [WebKit Bug 119478](https://bugs.webkit.org/show_bug.cgi?id=119478)
|
||||
- `<isindex>` is completely removed from the spec now, therefore it is dropped from the implementation
|
||||
- `Tokenizer` and `Tree-Construction` tests are now generated dynamically
|
||||
- Test failures are collected by a `XCTestObservation` for better reporting
|
||||
|
||||
- `<isindex>` is completely removed from the spec now, therefore it is dropped from the implementation
|
||||
- `Tokenizer` and `Tree-Construction` tests are now generated dynamically
|
||||
- Test failures are collected by a `XCTestObservation` for better reporting
|
||||
|
||||
### Fixed
|
||||
|
||||
- Parser now checks the qualified name instead of the local name when handling elements in the `MathML` and `SVG` namespaces
|
||||
|
||||
|
||||
## [0.9.1](https://github.com/iabudiab/HTMLKit/releases/tag/0.9.1)
|
||||
|
||||
Released on 2016.01.29
|
||||
|
||||
### Added
|
||||
|
||||
- Travis-CI integration.
|
||||
- CocoaPods spec.
|
||||
|
||||
|
||||
### Changed
|
||||
|
||||
- Warnings are treated as errors.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Warnings related to format specifier and loss of precision due to NS(U)-integer usage.
|
||||
- Replaced `@returns` with `@return` throughout the documentation to play nicely with Jazzy.
|
||||
- Some README examples used Swift syntax.
|
||||
|
||||
## [0.9.0](https://github.com/iabudiab/HTMLKit/releases/tag/0.9.0)
|
||||
|
||||
Released on 2015.12.23
|
||||
|
||||
This is the first public release of `HTMLKit`.
|
||||
|
||||
### Added
|
||||
|
||||
- `iOS` & `OSX` Frameworks.
|
||||
- Source code documentation.
|
||||
- CSS Selectors extension (analogous to jQuery selectors).
|
||||
- `DOMTokenList` for malipulating `HTMLElements` attributes as a list, e.g. `class`.
|
||||
- Handling for `<ruby>` elements in the Parser implementation.
|
||||
- Updated HTML5Lib-Tests submodule (56c435f)
|
||||
- Xcode Playground with Swift documentation.
|
||||
|
||||
### Removed
|
||||
|
||||
- Unused namespaces.
|
||||
- Historical node types.
|
||||
|
||||
|
||||
### Fixed
|
||||
|
||||
- `lt`, `gt` & `eq` CSS Selectors method declarations.
|
||||
|
||||
## [0.3.0](https://github.com/iabudiab/HTMLKit/releases/tag/0.3.0)
|
||||
|
||||
Released on 2015.11.29
|
||||
|
||||
### Added
|
||||
|
||||
- CSS3 Selectors support.
|
||||
- Nullability annotations.
|
||||
- `HTMLNode` properties for previous and next sibling elements.
|
||||
- `HTMLNode` methods for accessing child elements (analogous to child nodes).
|
||||
- `NSCharacterSet` category for HTML-related character sets.
|
||||
|
||||
### Fixed
|
||||
|
||||
- `InputStreaReader`'s reconsume-logic that is required by the CSS Parser.
|
||||
|
||||
## [0.2.0](https://github.com/iabudiab/HTMLKit/releases/tag/0.1.0)
|
||||
|
||||
Released on 2015.06.06
|
||||
|
||||
### Added
|
||||
|
||||
- `HTMLDocument` methods to access `root`, `head` & `body` elements.
|
||||
- `innerHTML` implementation for the `HTMLElement`.
|
||||
- `HTMLNode` methods to append, prepend, check containment and descendancy of nodes.
|
||||
- `HTMLNode` methods to enumerate child nodes.
|
||||
- Implementations for `NodeIterator` and `NodeFilter`
|
||||
- Implementation for `TreeWalker`
|
||||
- Validation for DOM manipulations.
|
||||
- Tests for the DOM implementation.
|
||||
|
||||
### Changed
|
||||
|
||||
- `type` property renamed to `nodeType` in `HTMLNode`.
|
||||
- `firstChildNode` and `lastChildNode` renamed to `firtChild` and `lastChild` in `HTMLNode`.
|
||||
|
||||
### Removed
|
||||
|
||||
- `baseURI` proeprty from `HTMLNode`
|
||||
- `HTMLNodeTreeEnumerator` is superseded by the `HTMLNodeIterator`.
|
||||
|
||||
## [0.1.0](https://github.com/iabudiab/HTMLKit/releases/tag/0.1.0)
|
||||
|
||||
Released on 2015.04.20
|
||||
|
||||
### Added
|
||||
|
||||
- Initial release.
|
||||
- Initial DOM implementation.
|
||||
- Tokenizer and Parser pass all [HTML5Lib](https://github.com/html5lib/html5lib-tests) tokenizer and tree construction tests except for `<ruby>` elements.
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "HTMLKit"
|
||||
s.version = "0.9.1"
|
||||
s.version = "0.9.2"
|
||||
s.summary = "HTMLKit, an Objective-C framework for your everyday HTML needs."
|
||||
s.license = "MIT"
|
||||
s.homepage = "https://github.com/iabudiab/HTMLKit"
|
||||
|
||||
@@ -40,6 +40,10 @@
|
||||
625A14CF19C7829400AD0C32 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 625A14CD19C7829400AD0C32 /* InfoPlist.strings */; };
|
||||
625D0F031C2717DE00D7BEB0 /* HTMLNode+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 625D0F011C2717DE00D7BEB0 /* HTMLNode+Private.h */; };
|
||||
625D0F041C2717DE00D7BEB0 /* HTMLNode+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 625D0F011C2717DE00D7BEB0 /* HTMLNode+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
625EE4571CBAA41D00F2CC8E /* HTMLKitTestObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 625EE4561CBAA41D00F2CC8E /* HTMLKitTestObserver.m */; };
|
||||
625EE4581CBAA41D00F2CC8E /* HTMLKitTestObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 625EE4561CBAA41D00F2CC8E /* HTMLKitTestObserver.m */; };
|
||||
625EE45B1CBB171300F2CC8E /* HTMLKitTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 625EE45A1CBB171300F2CC8E /* HTMLKitTestUtil.m */; };
|
||||
625EE45C1CBB171300F2CC8E /* HTMLKitTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 625EE45A1CBB171300F2CC8E /* HTMLKitTestUtil.m */; };
|
||||
628AF6301BC99A6C00496128 /* CSSNthExpressionsParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 628AF62E1BC99A6C00496128 /* CSSNthExpressionsParserTests.m */; };
|
||||
62D8345A19FB1AC4009205A9 /* HTML5LibTokenizerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 62D8345819FB1AC4009205A9 /* HTML5LibTokenizerTest.m */; };
|
||||
62EC7AE71AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */; };
|
||||
@@ -393,6 +397,10 @@
|
||||
625A150619C78ABA00AD0C32 /* HTMLInputStreamReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLInputStreamReader.h; sourceTree = "<group>"; };
|
||||
625A150719C78ABA00AD0C32 /* HTMLInputStreamReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLInputStreamReader.m; sourceTree = "<group>"; };
|
||||
625D0F011C2717DE00D7BEB0 /* HTMLNode+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "HTMLNode+Private.h"; sourceTree = "<group>"; };
|
||||
625EE4551CBAA41D00F2CC8E /* HTMLKitTestObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLKitTestObserver.h; sourceTree = "<group>"; };
|
||||
625EE4561CBAA41D00F2CC8E /* HTMLKitTestObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTestObserver.m; sourceTree = "<group>"; };
|
||||
625EE4591CBB171300F2CC8E /* HTMLKitTestUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLKitTestUtil.h; sourceTree = "<group>"; };
|
||||
625EE45A1CBB171300F2CC8E /* HTMLKitTestUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTestUtil.m; sourceTree = "<group>"; };
|
||||
626652F81C03D30F00C3F121 /* HTMLKitErrorDomain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLKitErrorDomain.h; sourceTree = "<group>"; };
|
||||
6279F87119E17DC700F12EE5 /* HTMLParserInsertionModes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLParserInsertionModes.h; sourceTree = "<group>"; };
|
||||
6279F87219E1808D00F12EE5 /* HTMLElement.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 4; path = HTMLElement.h; sourceTree = "<group>"; };
|
||||
@@ -653,6 +661,10 @@
|
||||
624E1A2D1B1D1C8A00E66AAC /* Structures */,
|
||||
62FF516C1C0A430A009BFDFE /* Selectors */,
|
||||
625A14CB19C7829400AD0C32 /* Supporting Files */,
|
||||
625EE4551CBAA41D00F2CC8E /* HTMLKitTestObserver.h */,
|
||||
625EE4561CBAA41D00F2CC8E /* HTMLKitTestObserver.m */,
|
||||
625EE4591CBB171300F2CC8E /* HTMLKitTestUtil.h */,
|
||||
625EE45A1CBB171300F2CC8E /* HTMLKitTestUtil.m */,
|
||||
);
|
||||
name = Tests;
|
||||
path = HTMLKitTests;
|
||||
@@ -1153,6 +1165,7 @@
|
||||
6239755B1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */,
|
||||
62F658711BD83C8E0045F137 /* CSSNThExpressionSelectorTests.m in Sources */,
|
||||
623CAF9E1AD88BEA00E34C32 /* HTMLKitParserPerformance.m in Sources */,
|
||||
625EE4571CBAA41D00F2CC8E /* HTMLKitTestObserver.m in Sources */,
|
||||
6247171D1B2240B800C11912 /* HTMLTreeWalkerTests.m in Sources */,
|
||||
62EC7AE71AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */,
|
||||
624AB31B1B050A4D00F3830D /* CSSAttributeSelectorTests.m in Sources */,
|
||||
@@ -1168,6 +1181,7 @@
|
||||
624FC37B1AE591D80015DDF9 /* HTMLKitNodesTests.m in Sources */,
|
||||
621FBE5B1BDAD68700BC9555 /* CSSSelectorParserTests.m in Sources */,
|
||||
621FBE5E1BDAD90200BC9555 /* CSSCombinatorSelectorTests.m in Sources */,
|
||||
625EE45B1CBB171300F2CC8E /* HTMLKitTestUtil.m in Sources */,
|
||||
628AF6301BC99A6C00496128 /* CSSNthExpressionsParserTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1233,6 +1247,7 @@
|
||||
62ECBFCB1C0B6E2E00AF847B /* HTMLKitTokenizerTests.m in Sources */,
|
||||
62ECBFCC1C0B6E2E00AF847B /* HTMLKitTokenizerPerformance.m in Sources */,
|
||||
62ECBFCD1C0B6E2E00AF847B /* HTML5LibTreeConstructionTest.m in Sources */,
|
||||
625EE4581CBAA41D00F2CC8E /* HTMLKitTestObserver.m in Sources */,
|
||||
62ECBFCE1C0B6E2E00AF847B /* HTMLKitTreeConstructionTests.m in Sources */,
|
||||
62ECBFCF1C0B6E2E00AF847B /* HTMLKitParserPerformance.m in Sources */,
|
||||
62ECBFD01C0B6E2E00AF847B /* HTMLKitNodeIteratorTests.m in Sources */,
|
||||
@@ -1248,6 +1263,7 @@
|
||||
62ECBFD91C0B6E2E00AF847B /* CSSTypeSelectorTests.m in Sources */,
|
||||
62ECBFDA1C0B6E2E00AF847B /* CSSAttributeSelectorTests.m in Sources */,
|
||||
62ECBFDB1C0B6E2E00AF847B /* CSSNThExpressionSelectorTests.m in Sources */,
|
||||
625EE45C1CBB171300F2CC8E /* HTMLKitTestUtil.m in Sources */,
|
||||
62ECBFDC1C0B6E2E00AF847B /* CSSCombinatorSelectorTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
||||
@@ -39,8 +39,8 @@ NS_INLINE BOOL IsSpecialElement(HTMLElement *element)
|
||||
@"dir", @"div", @"dl", @"dt", @"embed", @"fieldset", @"figcaption",
|
||||
@"figure", @"footer", @"form", @"frame", @"frameset", @"h1", @"h2", @"h3",
|
||||
@"h4", @"h5", @"h6", @"head", @"header", @"hgroup", @"hr", @"html", @"iframe",
|
||||
@"img", @"input", @"isindex", @"li", @"link", @"listing", @"main", @"marquee",
|
||||
@"menu", @"menuitem", @"meta", @"nav", @"noembed", @"noframes", @"noscript",
|
||||
@"img", @"input", @"li", @"link", @"listing", @"main", @"marquee",
|
||||
@"menu", @"meta", @"nav", @"noembed", @"noframes", @"noscript",
|
||||
@"object", @"ol", @"p", @"param", @"plaintext", @"pre", @"script", @"section",
|
||||
@"select", @"source", @"style", @"summary", @"table", @"tbody", @"td",
|
||||
@"template", @"textarea", @"tfoot", @"th", @"thead", @"title", @"tr",
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.9.1</string>
|
||||
<string>0.9.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
+39
-59
@@ -519,7 +519,7 @@
|
||||
|
||||
- (void)generateImpliedEndTagsExceptForElement:(NSString *)tagName
|
||||
{
|
||||
while ([self.currentNode.tagName isEqualToAny:@"dd", @"dt", @"li", @"option", @"optgroup", @"p", @"rb", @"rp", @"rt", @"rtc", nil] &&
|
||||
while ([self.currentNode.tagName isEqualToAny:@"dd", @"dt", @"li", @"menuitem", @"option", @"optgroup", @"p", @"rb", @"rp", @"rt", @"rtc", nil] &&
|
||||
![self.currentNode.tagName isEqualToString:tagName]) {
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
}
|
||||
@@ -588,20 +588,29 @@
|
||||
HTMLElement *lastNode = furthestBlock;
|
||||
|
||||
NSUInteger index = [_stackOfOpenElements indexOfElement:node];
|
||||
for (int innerLoopCounter = 0; innerLoopCounter < 3; innerLoopCounter ++) {
|
||||
|
||||
index--;
|
||||
int innerLoopCounter = 0;
|
||||
while (YES) {
|
||||
|
||||
innerLoopCounter += 1;
|
||||
index -= 1;
|
||||
|
||||
node = _stackOfOpenElements[index];
|
||||
|
||||
if ([node isEqual:formattingElement]) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (innerLoopCounter > 3 && [_listOfActiveFormattingElements containsElement:node]) {
|
||||
[_listOfActiveFormattingElements removeElement:node];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (![_listOfActiveFormattingElements containsElement:node]) {
|
||||
[_stackOfOpenElements removeElement:node];
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([node isEqual:formattingElement]) {
|
||||
break;
|
||||
}
|
||||
|
||||
HTMLElement *newElement = [node copy];
|
||||
[_listOfActiveFormattingElements replaceElementAtIndex:[_listOfActiveFormattingElements indexOfElement:node]
|
||||
withElement:newElement];
|
||||
@@ -1158,8 +1167,8 @@
|
||||
[self HTMLInsertionModeInTemplate:token];
|
||||
} else {
|
||||
for (HTMLElement *node in _stackOfOpenElements) {
|
||||
if ([node.tagName isEqualToAny:@"dd", @"dt", @"li", @"optgroup", @"option", @"p", @"rb", @"rp",
|
||||
@"rt", @"rtc", @"tbody", @"td", @"tfoot", @"th", @"thead", @"tr", @"body", @"html", nil]) {
|
||||
if ([node.tagName isEqualToAny:@"dd", @"dt", @"li", @"menuitem", @"optgroup", @"option", @"p", @"rb",
|
||||
@"rp", @"rt", @"rtc", @"tbody", @"td", @"tfoot", @"th", @"thead", @"tr", @"body", @"html", nil]) {
|
||||
[self emitParseError:@"EOF reached with unclosed element <%@> in <body>", node.tagName];
|
||||
break;
|
||||
}
|
||||
@@ -1222,12 +1231,20 @@
|
||||
[self switchInsertionMode:HTMLInsertionModeInFrameset];
|
||||
} else if ([tagName isEqualToAny:@"address", @"article", @"aside", @"blockquote", @"center",
|
||||
@"details", @"dialog", @"dir", @"div", @"dl", @"fieldset", @"figcaption", @"figure",
|
||||
@"footer", @"header", @"hgroup", @"main", @"menu", @"nav", @"ol", @"p", @"section",
|
||||
@"footer", @"header", @"hgroup", @"main", @"nav", @"ol", @"p", @"section",
|
||||
@"summary", @"ul", nil]) {
|
||||
if ([_stackOfOpenElements hasElementInButtonScopeWithTagName:@"p"]) {
|
||||
[self closePElement];
|
||||
}
|
||||
[self insertElementForToken:token];
|
||||
} else if ([tagName isEqualToString:@"menu"]) {
|
||||
if ([_stackOfOpenElements hasElementInButtonScopeWithTagName:@"p"]) {
|
||||
[self closePElement];
|
||||
}
|
||||
if ([self.currentNode.tagName isEqualToString:@"menuitem"]) {
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
}
|
||||
[self insertElementForToken:token];
|
||||
} else if ([tagName isEqualToAny:@"h1", @"h2", @"h3", @"h4", @"h5", @"h6", nil]) {
|
||||
if ([_stackOfOpenElements hasElementInButtonScopeWithTagName:@"p"]) {
|
||||
[self closePElement];
|
||||
@@ -1364,13 +1381,16 @@
|
||||
if (type == nil || ![type isEqualToStringIgnoringCase:@"hidden"]) {
|
||||
_framesetOkFlag = NO;
|
||||
}
|
||||
} else if ([tagName isEqualToAny:@"menuitem", @"param", @"source", @"track", nil]) {
|
||||
} else if ([tagName isEqualToAny:@"param", @"source", @"track", nil]) {
|
||||
[self insertElementForToken:token];
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
} else if ([tagName isEqualToString:@"hr"]) {
|
||||
if ([_stackOfOpenElements hasElementInButtonScopeWithTagName:@"p"]) {
|
||||
[self closePElement];
|
||||
}
|
||||
if ([self.currentNode.tagName isEqualToString:@"menuitem"]) {
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
}
|
||||
[self insertElementForToken:token];
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
_framesetOkFlag = NO;
|
||||
@@ -1378,52 +1398,6 @@
|
||||
[self emitParseError:@"Image Start Tag Token with tagname <image> should be <img>. Don't ask."];
|
||||
token.tagName = @"img";
|
||||
[self reprocessToken:token];
|
||||
} else if ([tagName isEqualToString:@"isindex"]) {
|
||||
[self emitParseError:@"Unexpected start tag <isindex> in <body>"];
|
||||
if (_formElementPointer != nil && ![_stackOfOpenElements containsElementWithTagName:@"template"]) {
|
||||
return;
|
||||
}
|
||||
_framesetOkFlag = NO;
|
||||
if ([_stackOfOpenElements hasElementInButtonScopeWithTagName:@"p"]) {
|
||||
[self closePElement];
|
||||
}
|
||||
|
||||
HTMLStartTagToken *formToken = [[HTMLStartTagToken alloc] initWithTagName:@"form"];
|
||||
HTMLElement *form = [self insertElementForToken:formToken];
|
||||
if (![_stackOfOpenElements containsElementWithTagName:@"template"]) {
|
||||
_formElementPointer = form;
|
||||
}
|
||||
NSString *action = token.attributes[@"action"];
|
||||
if (action != nil) {
|
||||
form.attributes[@"action"] = action;
|
||||
}
|
||||
|
||||
HTMLStartTagToken *hrToken = [[HTMLStartTagToken alloc] initWithTagName:@"hr"];
|
||||
[self insertElementForToken:hrToken];
|
||||
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
[self reconstructActiveFormattingElements];
|
||||
|
||||
HTMLStartTagToken *labelToken = [[HTMLStartTagToken alloc] initWithTagName:@"label"];
|
||||
[self insertElementForToken:labelToken];
|
||||
|
||||
NSString *prompt = token.attributes[@"prompt"] ?: @"This is a searchable index. Enter search keywords: ";
|
||||
[self insertCharacters:prompt];
|
||||
|
||||
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithDictionary:token.attributes];
|
||||
attributes[@"name"] = @"isindex";
|
||||
[attributes removeObjectForKey:@"action"];
|
||||
[attributes removeObjectForKey:@"prompt"];
|
||||
|
||||
HTMLStartTagToken *inputToken = [[HTMLStartTagToken alloc] initWithTagName:@"input" attributes:attributes];
|
||||
[self insertElementForToken:inputToken];
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
[self insertElementForToken:hrToken];
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
_formElementPointer = nil;
|
||||
} else if ([tagName isEqualToString:@"textarea"]) {
|
||||
[self insertElementForToken:token];
|
||||
_ignoreNextLineFeedCharacterToken = YES;
|
||||
@@ -1462,6 +1436,12 @@
|
||||
}
|
||||
[self reconstructActiveFormattingElements];
|
||||
[self insertElementForToken:token];
|
||||
} else if ([tagName isEqualToString:@"menuitem"]) {
|
||||
if ([self.currentNode.tagName isEqualToString:@"menuitem"]) {
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
}
|
||||
[self reconstructActiveFormattingElements];
|
||||
[self insertElementForToken:token];
|
||||
} else if ([tagName isEqualToAny:@"rb", @"rtc", nil]) {
|
||||
if ([_stackOfOpenElements hasElementInScopeWithTagName:@"ruby"]) {
|
||||
[self generateImpliedEndTagsExceptForElement:nil];
|
||||
@@ -1516,8 +1496,8 @@
|
||||
[self emitParseError:@"Unexpected end tag </body> without body element in scope in <body>"];
|
||||
}
|
||||
for (HTMLElement *node in _stackOfOpenElements) {
|
||||
if ([node.tagName isEqualToAny:@"dd", @"dt", @"li", @"optgroup", @"option", @"p", @"rb", @"rp", @"rt",
|
||||
@"rtc", @"tbody", @"td", @"tfoot", @"th", @"thead", @"tr", @"body", @"html", nil]) {
|
||||
if ([node.tagName isEqualToAny:@"dd", @"dt", @"li", @"menuitem", @"optgroup", @"option", @"p", @"rb", @"rp",
|
||||
@"rt", @"rtc", @"tbody", @"td", @"tfoot", @"th", @"thead", @"tr", @"body", @"html", nil]) {
|
||||
[self emitParseError:@"Misnested end tag </%@> with open element <%@> in <body>", tagName, node.tagName];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -129,7 +129,11 @@
|
||||
|
||||
- (void)popElementsUntilElementPoppedWithTagName:(NSString *)tagName
|
||||
{
|
||||
while (self.currentNode && ![self.currentNode.tagName isEqualToString:tagName]) {
|
||||
while (self.currentNode) {
|
||||
if (self.currentNode.htmlNamespace == HTMLNamespaceHTML &&
|
||||
[self.currentNode.tagName isEqualToString:tagName]) {
|
||||
break;
|
||||
}
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
[_stack removeLastObject];
|
||||
@@ -137,7 +141,11 @@
|
||||
|
||||
- (void)popElementsUntilAnElementPoppedWithAnyOfTagNames:(NSArray *)tagNames
|
||||
{
|
||||
while (self.currentNode && ![tagNames containsObject:self.currentNode.tagName]) {
|
||||
while (self.currentNode) {
|
||||
if (self.currentNode.htmlNamespace == HTMLNamespaceHTML &&
|
||||
[tagNames containsObject:self.currentNode.tagName]) {
|
||||
break;
|
||||
}
|
||||
[_stack removeLastObject];
|
||||
}
|
||||
[_stack removeLastObject];
|
||||
@@ -257,7 +265,10 @@
|
||||
{
|
||||
for (HTMLElement *node in _stack.reverseObjectEnumerator) {
|
||||
if ([tagNames containsObject:node.tagName]) {
|
||||
return node;
|
||||
NSNumber *namespace = elementTypes[node.tagName] ?: @(HTMLNamespaceHTML);
|
||||
if ([namespace isEqual:@(node.htmlNamespace)]) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
if ([elementTypes[node.tagName] isEqual:@(node.htmlNamespace)]) {
|
||||
return nil;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
@interface HTML5LibTokenizerTest : NSObject
|
||||
|
||||
@property (nonatomic, copy) NSString *testName;
|
||||
@property (nonatomic, copy) NSString *testFile;
|
||||
@property (nonatomic, copy) NSString *title;
|
||||
@property (nonatomic, copy) NSString *input;
|
||||
@property (nonatomic, strong) NSArray *output;
|
||||
|
||||
@@ -39,7 +39,7 @@ static NSString * const TOKENIZER = @"tokenizer";
|
||||
|
||||
+ (NSArray *)loadTestsWithFileAtPath:(NSString *)filePath
|
||||
{
|
||||
NSString *testName = filePath.lastPathComponent.stringByDeletingLastPathComponent;
|
||||
NSString *testFile = filePath.lastPathComponent;
|
||||
|
||||
NSString *json = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
|
||||
NSData *data = [json dataUsingEncoding:NSUTF8StringEncoding];
|
||||
@@ -52,7 +52,7 @@ static NSString * const TOKENIZER = @"tokenizer";
|
||||
|
||||
for (NSDictionary *test in jsonTests) {
|
||||
HTML5LibTokenizerTest *html5libTest = [[HTML5LibTokenizerTest alloc] initWithTestDictionary:test];
|
||||
html5libTest.testName = testName;
|
||||
html5libTest.testFile = testFile;
|
||||
[tests addObject:html5libTest];
|
||||
}
|
||||
return tests;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// HTMLKitTestObserver.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 10/04/16.
|
||||
// Copyright © 2016 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
@interface HTMLKitTestReport : NSObject
|
||||
@property (assign, readonly) NSUInteger totalCount;
|
||||
@property (assign, readonly) NSUInteger failureCount;
|
||||
@property (copy, readonly) NSString *failureReport;
|
||||
@end
|
||||
|
||||
@interface HTMLKitTestObserver<TestCase: XCTestCase *> : NSObject <XCTestObservation>
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name;
|
||||
|
||||
- (void)addCaseForHTML5LibTestWithInput:(NSString *)input;
|
||||
- (HTMLKitTestReport *)generateReport;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// HTMLKitTestObserver.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 10/04/16.
|
||||
// Copyright © 2016 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLKitTestObserver.h"
|
||||
|
||||
#pragma mark - HTMLKitTestReport
|
||||
|
||||
@interface HTMLKitTestReport ()
|
||||
@property (assign) NSUInteger totalCount;
|
||||
@property (assign) NSUInteger failureCount;
|
||||
@property (copy) NSString *failureReport;
|
||||
@end
|
||||
|
||||
@implementation HTMLKitTestReport
|
||||
@synthesize totalCount, failureCount, failureReport;
|
||||
@end
|
||||
|
||||
#pragma mark - HTMLKitTestObserver
|
||||
|
||||
@interface HTMLKitTestObserver ()
|
||||
{
|
||||
NSString *_name;
|
||||
NSMutableArray *_cases;
|
||||
NSMutableDictionary *_currentCase;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLKitTestObserver
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_name = [name copy];
|
||||
_cases = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)addCaseForHTML5LibTestWithInput:(NSString *)input
|
||||
{
|
||||
_currentCase = [NSMutableDictionary new];
|
||||
_currentCase[@"input"] = input;
|
||||
_currentCase[@"status"] = @"Passed";
|
||||
[_cases addObject:_currentCase];
|
||||
}
|
||||
|
||||
- (void)testCase:(XCTestCase *)testCase didFailWithDescription:(NSString *)description inFile:(NSString *)filePath atLine:(NSUInteger)lineNumber
|
||||
{
|
||||
_currentCase[@"status"] = @"Failed";
|
||||
}
|
||||
|
||||
- (HTMLKitTestReport *)generateReport
|
||||
{
|
||||
NSMutableString *reportDescription = [NSMutableString string];
|
||||
|
||||
NSIndexSet *failedIndexes = [_cases indexesOfObjectsPassingTest:^BOOL(NSDictionary *testCase, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
return [testCase[@"status"] isEqualToString:@"Failed"];
|
||||
}];
|
||||
|
||||
NSArray *failedTests = [_cases objectsAtIndexes:failedIndexes];
|
||||
|
||||
NSUInteger totalCount = _cases.count;
|
||||
NSUInteger failureCount = failedTests.count;
|
||||
|
||||
[reportDescription appendFormat:@"HTML5Lib test %@ failed [%lu] out of [%lu] total tests\n", _name, failureCount, _cases.count];
|
||||
|
||||
for (NSDictionary *testCase in failedTests) {
|
||||
[reportDescription appendFormat:@"Failed test for input: %@\n", testCase[@"input"]];
|
||||
}
|
||||
|
||||
HTMLKitTestReport *report = [HTMLKitTestReport new];
|
||||
report.totalCount = totalCount;
|
||||
report.failureCount = failureCount;
|
||||
report.failureReport = reportDescription;
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// HTMLKitTestUtil.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 11/04/16.
|
||||
// Copyright © 2016 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface HTMLKitTestUtil : NSObject
|
||||
|
||||
+ (NSInvocation *)addTestToClass:(Class)cls withName:(NSString *)name block:(id)block;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// HTMLKitTestUtil.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 11/04/16.
|
||||
// Copyright © 2016 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLKitTestUtil.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation HTMLKitTestUtil
|
||||
|
||||
+ (NSInvocation *)addTestToClass:(Class)cls withName:(NSString *)name block:(id)block
|
||||
{
|
||||
IMP implementation = imp_implementationWithBlock(block);
|
||||
const char *types = [[NSString stringWithFormat:@"%s%s%s", @encode(id), @encode(id), @encode(SEL)] UTF8String];
|
||||
|
||||
SEL selector = NSSelectorFromString(name);
|
||||
class_addMethod(cls, selector, implementation, types);
|
||||
|
||||
NSMethodSignature *signature = [cls instanceMethodSignatureForSelector:selector];
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||
invocation.selector = selector;
|
||||
|
||||
return invocation;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -7,8 +7,10 @@
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "HTML5LibTokenizerTest.h"
|
||||
|
||||
#import "HTMLKitTestUtil.h"
|
||||
|
||||
#import "HTML5LibTokenizerTest.h"
|
||||
#import "HTMLTokenizer.h"
|
||||
#import "HTMLTokenizerStates.h"
|
||||
#import "HTMLTokens.h"
|
||||
@@ -30,7 +32,6 @@
|
||||
#pragma mark - HTML5Lib Test Suite
|
||||
|
||||
@interface HTMLKitTokenizerTests : XCTestCase
|
||||
@property (nonatomic, strong) NSString *testName;
|
||||
@property (nonatomic, strong) NSArray *testsList;
|
||||
@end
|
||||
|
||||
@@ -50,44 +51,31 @@
|
||||
|
||||
+ (void)addTestCaseForTestFile:(NSString *)testFile withTests:(NSArray *)tests toTestSuite:(XCTestSuite *)suite
|
||||
{
|
||||
NSArray *allInvocations = [self testInvocations];
|
||||
for (NSInvocation *invocation in allInvocations) {
|
||||
XCTestCase *testCase = [[self alloc] initWithInvocation:invocation
|
||||
testName:testFile
|
||||
tests:tests];
|
||||
[suite addTest:testCase];
|
||||
}
|
||||
NSString *testName = [testFile.stringByDeletingPathExtension stringByReplacingOccurrencesOfString:@"-" withString:@"_"];
|
||||
testName = [NSString stringWithFormat:@"testTokenizer__%@", testName];
|
||||
|
||||
NSInvocation *invocation = [HTMLKitTestUtil addTestToClass:self withName:testName block:^ (HTMLKitTokenizerTests *instance){
|
||||
[instance runTests];
|
||||
}];
|
||||
|
||||
XCTestCase *testCase = [[self alloc] initWithInvocation:invocation tests:tests];
|
||||
[suite addTest:testCase];
|
||||
}
|
||||
|
||||
#pragma mark - Instance
|
||||
|
||||
- (instancetype)initWithInvocation:(NSInvocation *)invocation
|
||||
testName:(NSString *)testName
|
||||
tests:(NSArray *)tests
|
||||
- (instancetype)initWithInvocation:(NSInvocation *)invocation tests:(NSArray *)tests
|
||||
{
|
||||
self = [super initWithInvocation:invocation];
|
||||
if (self) {
|
||||
_testName = testName;
|
||||
_testsList = tests;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)name
|
||||
{
|
||||
NSInvocation *invocation = [self invocation];
|
||||
NSString *title = self.testName.stringByDeletingPathExtension;
|
||||
return [NSString stringWithFormat:@"-[%@ %@_%@]", self.class, NSStringFromSelector(invocation.selector), title];
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return self.name;
|
||||
}
|
||||
|
||||
#pragma mark - Tests
|
||||
|
||||
- (void)testTokenizer
|
||||
- (void)runTests
|
||||
{
|
||||
for (HTML5LibTokenizerTest *test in self.testsList) {
|
||||
|
||||
@@ -101,7 +89,7 @@
|
||||
NSArray *tokens = tokenizer.allObjects;
|
||||
|
||||
NSString *message = [NSString stringWithFormat:@"HTML5Lib test in file: \'%@\' Title: '%@'\nInput: '%@'\nExpected:\n%@\nActual:\n%@\n",
|
||||
self.testName,
|
||||
test.testFile,
|
||||
test.title,
|
||||
test.input,
|
||||
expectedTokens,
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "HTMLKitTestUtil.h"
|
||||
|
||||
#import "HTMLKitTestObserver.h"
|
||||
#import "HTML5LibTreeConstructionTest.h"
|
||||
#import "HTMLDOM.h"
|
||||
#import "HTMLParser.h"
|
||||
@@ -26,7 +29,9 @@
|
||||
#pragma mark - HTML5Lib Test Suite
|
||||
|
||||
@interface HTMLKitTreeConstructionTests : XCTestCase
|
||||
@property (nonatomic, strong) NSString *testName;
|
||||
{
|
||||
HTMLKitTestObserver<HTMLKitTreeConstructionTests *> *_observer;
|
||||
}
|
||||
@property (nonatomic, strong) NSArray *testsList;
|
||||
@end
|
||||
|
||||
@@ -45,50 +50,58 @@
|
||||
|
||||
+ (void)addTestCaseForTestFile:(NSString *)testFile withTests:(NSArray *)tests toTestSuite:(XCTestSuite *)suite
|
||||
{
|
||||
NSArray *allInvocations = [self testInvocations];
|
||||
for (NSInvocation *invocation in allInvocations) {
|
||||
XCTestCase *testCase = [[self alloc] initWithInvocation:invocation
|
||||
testName:testFile
|
||||
tests:tests];
|
||||
[suite addTest:testCase];
|
||||
}
|
||||
NSString *testName = [testFile.stringByDeletingPathExtension stringByReplacingOccurrencesOfString:@"-" withString:@"_"];
|
||||
testName = [NSString stringWithFormat:@"testPareser__%@", testName];
|
||||
|
||||
NSInvocation *invocation = [HTMLKitTestUtil addTestToClass:self withName:testName block:^ (HTMLKitTreeConstructionTests *instance){
|
||||
[instance runTests];
|
||||
}];
|
||||
|
||||
XCTestCase *testCase = [[self alloc] initWithInvocation:invocation tests:tests];
|
||||
[suite addTest:testCase];
|
||||
}
|
||||
|
||||
#pragma mark - Instance
|
||||
|
||||
- (instancetype)initWithInvocation:(NSInvocation *)invocation
|
||||
testName:(NSString *)testName
|
||||
tests:(NSArray *)tests
|
||||
- (instancetype)initWithInvocation:(NSInvocation *)invocation tests:(NSArray *)tests
|
||||
{
|
||||
self = [super initWithInvocation:invocation];
|
||||
if (self) {
|
||||
_testName = testName;
|
||||
_testsList = tests;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)name
|
||||
#pragma mark - Setup
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
NSInvocation *invocation = [self invocation];
|
||||
NSString *title = self.testName.stringByDeletingPathExtension;
|
||||
return [NSString stringWithFormat:@"-[%@ %@_%@]", self.class, NSStringFromSelector(invocation.selector), title];
|
||||
_observer = [[HTMLKitTestObserver alloc] initWithName:self.name];
|
||||
[[XCTestObservationCenter sharedTestObservationCenter] addTestObserver:_observer];
|
||||
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
- (void)tearDown
|
||||
{
|
||||
return self.name;
|
||||
HTMLKitTestReport *testReport = [_observer generateReport];
|
||||
XCTAssertTrue(testReport.failureCount == 0, @"%@", testReport.failureReport);
|
||||
|
||||
[[XCTestObservationCenter sharedTestObservationCenter] removeTestObserver:_observer];
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
#pragma mark - Tests
|
||||
|
||||
- (void)testParser
|
||||
- (void)runTests
|
||||
{
|
||||
for (HTML5LibTreeConstructionTest *test in self.testsList) {
|
||||
NSString *testInput = test.data;
|
||||
|
||||
[_observer addCaseForHTML5LibTestWithInput:testInput];
|
||||
|
||||
HTMLParser *parser = [[HTMLParser alloc] initWithString:testInput];
|
||||
HTMLElement *contextElement = test.documentFragment;
|
||||
|
||||
HTMLParser *parser = [[HTMLParser alloc] initWithString:test.data];
|
||||
|
||||
NSArray *actual = nil;
|
||||
if (contextElement == nil) {
|
||||
actual = [parser parseDocument].childNodes.array;
|
||||
|
||||
Submodule HTMLKitTests/html5lib-tests updated: 56c435f033...b2f4f58441
@@ -1,10 +1,15 @@
|
||||
# HTMLKit
|
||||
|
||||

|
||||

|
||||
|
||||
An Objective-C framework for your everyday HTML needs.
|
||||
|
||||
[](https://travis-ci.org/iabudiab/HTMLKit) [](https://github.com/Carthage/Carthage) [](https://opensource.org/licenses/MIT)
|
||||
[](https://travis-ci.org/iabudiab/HTMLKit)
|
||||
[](https://github.com/Carthage/Carthage)
|
||||
[](https://cocoapods.org/pods/HTMLKit)
|
||||
[](http://cocoadocs.org/docsets/HTMLKit)
|
||||
[](http://cocoadocs.org/docsets/HTMLKit)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
|
||||
# Quick Overview
|
||||
|
||||
@@ -18,7 +23,7 @@ DOM mutations are validated as described in the [WHATWG DOM Standard](https://do
|
||||
|
||||
## Tests
|
||||
|
||||
HTMLKit passes all of the [HTML5Lib](https://github.com/html5lib/html5lib-tests) Tokenizer and Tree Construction tests except for the Blink changes introduced on the 16.09.2015. The `html5lib-tests` is configured as a git-submodule. If you plan to run the tests, do not forget to pull it too.
|
||||
HTMLKit passes all of the [HTML5Lib](https://github.com/html5lib/html5lib-tests) Tokenizer and Tree Construction tests. The `html5lib-tests` is configured as a git-submodule. If you plan to run the tests, do not forget to pull it too.
|
||||
|
||||
The CSS3 Selector implementation is tested with an adapted version of the [CSS3 Selectors Test Suite](http://www.w3.org/Style/CSS/Test/CSS3/Selectors/current/html/full/flat/index.html), ignoring the tests that require user interaction, session history, and scripting.
|
||||
|
||||
@@ -214,6 +219,10 @@ CSSSelector *myAwesomeSelector = namedBlockSelector(@"myAwesomeSelector", ^BOOL
|
||||
notParagraphAndNotDiv = [firstDivElement elementsMatchingSelector:myAwesomeSelector];
|
||||
```
|
||||
|
||||
# Change Log
|
||||
|
||||
See the [CHANGELOG.md](CHANGELOG.md) for more info.
|
||||
|
||||
# License
|
||||
|
||||
HTMLKit is available under the MIT license. See the LICENSE file for more info.
|
||||
HTMLKit is available under the MIT license. See the [LICENSE](LICENSE) file for more info.
|
||||
|
||||
Reference in New Issue
Block a user