Compare commits
166 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e788c832c6 | |||
| a33f4e0834 | |||
| 9e4007dcba | |||
| 50b67cfa94 | |||
| 47d244289e | |||
| 6b81d6e465 | |||
| 13b8fe7808 | |||
| 94fed8afa1 | |||
| 30dc6cf343 | |||
| badf070907 | |||
| 3443321459 | |||
| 60dc6bfc43 | |||
| 60a5821a2c | |||
| 621dbe36d6 | |||
| 50ae2c5283 | |||
| 0cb374681c | |||
| c09adc2f96 | |||
| 09991a149f | |||
| f735fcdfd6 | |||
| 5a3c1063e7 | |||
| 8cb088367d | |||
| 7ec90d6470 | |||
| 002564f9ae | |||
| 4c80c520d4 | |||
| 85abf35099 | |||
| 578806ec2f | |||
| 7923efb02b | |||
| f4d42e0753 | |||
| 56f99f9168 | |||
| c8dd1d7791 | |||
| c57d3453fc | |||
| a413156514 | |||
| 203d153487 | |||
| 4ceb913b9f | |||
| 7896f1687e | |||
| 55bb8effb2 | |||
| 2e10c23f52 | |||
| 4f47a750e0 | |||
| 46beae1b2d | |||
| 2e441727bc | |||
| cc101b9f4e | |||
| 0635744a2d | |||
| b5bb0a48b6 | |||
| 95ffccf67b | |||
| 6af01a1214 | |||
| 667693939f | |||
| f05adfb56b | |||
| bed2edf22a | |||
| 2574736359 | |||
| ab7de014cf | |||
| 15e768267a | |||
| ee82cacc48 | |||
| 61d7c683fb | |||
| bd84884bf7 | |||
| f248b39d26 | |||
| 118ea137f4 | |||
| 0366f39d1a | |||
| d107c05a44 | |||
| 5ca3bf1192 | |||
| 02393ddedd | |||
| 33df9e7fb2 | |||
| 6020b2bdd9 | |||
| c44c77d63d | |||
| 9905f45e27 | |||
| c868bd1a56 | |||
| 8f38aed6c6 | |||
| 1917fb1f1c | |||
| dc93bb07f6 | |||
| a74be4dfa9 | |||
| 7cd47486ac | |||
| ad902e3138 | |||
| 6cfe3b6f83 | |||
| a2096b0e54 | |||
| 79fda9fdbe | |||
| 1a05c41f86 | |||
| bf751d94b1 | |||
| 43705dac69 | |||
| 3c7e6e1913 | |||
| af4444e9a8 | |||
| 23d0d62295 | |||
| b0668e121e | |||
| aa95bbd9f2 | |||
| 1544f71c50 | |||
| b1ddbc5f75 | |||
| 576dc4dfb2 | |||
| c4aacfae2b | |||
| a54cae8829 | |||
| 852dfad19c | |||
| a5d53b3eef | |||
| 5e5b903c52 | |||
| 40b6e41e12 | |||
| 0401118657 | |||
| 045e4db9d1 | |||
| a7caa34762 | |||
| df53870880 | |||
| 7f25aacaf1 | |||
| 5e482788ce | |||
| a39890e6e9 | |||
| fd516c67ef | |||
| a390edf599 | |||
| 0c82f6891b | |||
| 0d7c57d755 | |||
| 40400864d8 | |||
| dc3de7a470 | |||
| c1b18f527c | |||
| d4bb3c6636 | |||
| 0baa343e95 | |||
| 2f1555e93d | |||
| a0fd89f417 | |||
| d002c6cedd | |||
| 71fefa2fa9 | |||
| 066bdeffa8 | |||
| 3df5a219e1 | |||
| e1c3533a1c | |||
| dfeebc7f7f | |||
| cd6e8bf4fc | |||
| 0fa394b911 | |||
| 13ed63017e | |||
| ac561570f3 | |||
| 165cdb5a75 | |||
| aece7138a4 | |||
| 45156d98fd | |||
| 7892a925c8 | |||
| f8ee4a38b4 | |||
| de597a51a4 | |||
| 470b9b8d37 | |||
| 915f4cc064 | |||
| 11af0509a3 | |||
| 2ee3b2d2b3 | |||
| 1e9118078f | |||
| 74aec57785 | |||
| 111acb4f8f | |||
| 05e224283a | |||
| 8490d4d2ca | |||
| 52b850317e | |||
| f5d970ba87 | |||
| 0c8fd754c3 | |||
| 4f03e00003 | |||
| 62b385d9b4 | |||
| a7a30a7cbf | |||
| 221b085fe5 | |||
| a2d9e65f0e | |||
| 745d0f72a7 | |||
| c401c3ca2c | |||
| 3cb5ed9a42 | |||
| acec99ffea | |||
| 7c58268dfd | |||
| c87076b470 | |||
| 81a20f0333 | |||
| 4fcaf4c810 | |||
| 2c9f68e2ea | |||
| 3d3e4d52b4 | |||
| bf061d6367 | |||
| 40baea8ece | |||
| a2c6f22495 | |||
| b2f1864c80 | |||
| cffe1cc703 | |||
| bc6bbf1d63 | |||
| 71aed89574 | |||
| 36960dceb3 | |||
| 3ddfa15b15 | |||
| 071742fb27 | |||
| 1bc896efc9 | |||
| 429f00adb6 | |||
| d08ac2100e | |||
| 62a6336dce |
+25
-6
@@ -1,8 +1,12 @@
|
||||
# OS X
|
||||
.DS_Store
|
||||
|
||||
# Xcode
|
||||
#
|
||||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||
|
||||
## Build generated
|
||||
build/
|
||||
DerivedData
|
||||
|
||||
## Various settings
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
@@ -12,13 +16,28 @@ build/
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
|
||||
## Other
|
||||
*.xccheckout
|
||||
profile
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
*.xcuserstate
|
||||
*.xcscmblueprint
|
||||
|
||||
## Obj-C/Swift specific
|
||||
*.hmap
|
||||
*.ipa
|
||||
|
||||
# CocoaPods
|
||||
Pods
|
||||
#
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||
#
|
||||
Pods/
|
||||
|
||||
# Carthage
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from Carthage dependencies.
|
||||
Carthage/Checkouts
|
||||
|
||||
Carthage/Build
|
||||
+401
-102
@@ -7,82 +7,101 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
623406E11ADB04F9004677A3 /* HTMLTemplate.h in Headers */ = {isa = PBXBuildFile; fileRef = 623406DF1ADB04F9004677A3 /* HTMLTemplate.h */; };
|
||||
620C877C1BD44CBE00FB3EEE /* CSSCompoundSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 620C877A1BD44CBE00FB3EEE /* CSSCompoundSelector.m */; };
|
||||
620C877D1BD44CBE00FB3EEE /* CSSCompoundSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 620C877A1BD44CBE00FB3EEE /* CSSCompoundSelector.m */; };
|
||||
620C877E1BD4519A00FB3EEE /* CSSPseudoFunctionSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 62ACB8DC1BC5C13E00E283C1 /* CSSPseudoFunctionSelector.m */; };
|
||||
620C877F1BD4519A00FB3EEE /* CSSPseudoFunctionSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 62ACB8DC1BC5C13E00E283C1 /* CSSPseudoFunctionSelector.m */; };
|
||||
620EE94A1BC46F2A0028ED34 /* CSSPseudoClassSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 620EE9481BC46F2A0028ED34 /* CSSPseudoClassSelector.m */; };
|
||||
620EE94B1BC46F2A0028ED34 /* CSSPseudoClassSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 620EE9481BC46F2A0028ED34 /* CSSPseudoClassSelector.m */; };
|
||||
62132E591C01F83200084175 /* CSSSelectorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 62132E581C01F83200084175 /* CSSSelectorTest.m */; };
|
||||
62132E5A1C01F83200084175 /* CSSSelectorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 62132E581C01F83200084175 /* CSSSelectorTest.m */; };
|
||||
62132E5C1C021FF200084175 /* css-tests in Resources */ = {isa = PBXBuildFile; fileRef = 62132E5B1C021FF200084175 /* css-tests */; };
|
||||
62132E5D1C021FF200084175 /* css-tests in Resources */ = {isa = PBXBuildFile; fileRef = 62132E5B1C021FF200084175 /* css-tests */; };
|
||||
621FBE5A1BDAD68700BC9555 /* CSSSelectorParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 621FBE591BDAD68700BC9555 /* CSSSelectorParserTests.m */; };
|
||||
621FBE5B1BDAD68700BC9555 /* CSSSelectorParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 621FBE591BDAD68700BC9555 /* CSSSelectorParserTests.m */; };
|
||||
621FBE5D1BDAD90200BC9555 /* CSSCombinatorSelectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 621FBE5C1BDAD90200BC9555 /* CSSCombinatorSelectorTests.m */; };
|
||||
621FBE5E1BDAD90200BC9555 /* CSSCombinatorSelectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 621FBE5C1BDAD90200BC9555 /* CSSCombinatorSelectorTests.m */; };
|
||||
622BF5821BBF2FD700363583 /* CSSSelectorParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 622BF5801BBF2FD700363583 /* CSSSelectorParser.m */; };
|
||||
622BF5831BBF2FD700363583 /* CSSSelectorParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 622BF5801BBF2FD700363583 /* CSSSelectorParser.m */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
6234BEEE1AABBF1400DEB15F /* HTMLStackOfOpenElements.h in Headers */ = {isa = PBXBuildFile; fileRef = 6234BEEC1AABBF1400DEB15F /* HTMLStackOfOpenElements.h */; };
|
||||
6234BEEF1AABBF1400DEB15F /* HTMLStackOfOpenElements.m in Sources */ = {isa = PBXBuildFile; fileRef = 6234BEED1AABBF1400DEB15F /* HTMLStackOfOpenElements.m */; };
|
||||
6234BEF01AABBF1400DEB15F /* HTMLStackOfOpenElements.m in Sources */ = {isa = PBXBuildFile; fileRef = 6234BEED1AABBF1400DEB15F /* HTMLStackOfOpenElements.m */; };
|
||||
6234CF571ABF892400B6077D /* libHTMLKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 625A14DE19C7834000AD0C32 /* libHTMLKit.a */; };
|
||||
6235CE9B1AA509430026937B /* NSString+HTMLKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 6235CE991AA509430026937B /* NSString+HTMLKit.h */; };
|
||||
6235CE9C1AA509430026937B /* NSString+HTMLKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 6235CE9A1AA509430026937B /* NSString+HTMLKit.m */; };
|
||||
6235CE9D1AA509430026937B /* NSString+HTMLKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 6235CE9A1AA509430026937B /* NSString+HTMLKit.m */; };
|
||||
6235CEA01AA5170A0026937B /* HTMLMarker.h in Headers */ = {isa = PBXBuildFile; fileRef = 6235CE9E1AA5170A0026937B /* HTMLMarker.h */; };
|
||||
6235CEA11AA5170A0026937B /* HTMLMarker.m in Sources */ = {isa = PBXBuildFile; fileRef = 6235CE9F1AA5170A0026937B /* HTMLMarker.m */; };
|
||||
6235CEA21AA5170A0026937B /* HTMLMarker.m in Sources */ = {isa = PBXBuildFile; fileRef = 6235CE9F1AA5170A0026937B /* HTMLMarker.m */; };
|
||||
62362A3C1A9FA70400301989 /* HTMLText.h in Headers */ = {isa = PBXBuildFile; fileRef = 62362A3A1A9FA70400301989 /* HTMLText.h */; };
|
||||
62362A3D1A9FA70400301989 /* HTMLText.m in Sources */ = {isa = PBXBuildFile; fileRef = 62362A3B1A9FA70400301989 /* HTMLText.m */; };
|
||||
62362A3E1A9FA70400301989 /* HTMLText.m in Sources */ = {isa = PBXBuildFile; fileRef = 62362A3B1A9FA70400301989 /* HTMLText.m */; };
|
||||
62363C3D1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h in Headers */ = {isa = PBXBuildFile; fileRef = 62363C3B1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h */; };
|
||||
62363C3E1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m in Sources */ = {isa = PBXBuildFile; fileRef = 62363C3C1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m */; };
|
||||
62363C3F1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m in Sources */ = {isa = PBXBuildFile; fileRef = 62363C3C1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m */; };
|
||||
6236738E1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m in Sources */ = {isa = PBXBuildFile; fileRef = 6236738D1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m */; };
|
||||
6236738F1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m in Sources */ = {isa = PBXBuildFile; fileRef = 6236738D1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m */; };
|
||||
6238039F1AB63A8C008A53D0 /* HTMLEOFToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 6238039D1AB63A8C008A53D0 /* HTMLEOFToken.h */; };
|
||||
623803A01AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238039E1AB63A8C008A53D0 /* HTMLEOFToken.m */; };
|
||||
623803A11AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238039E1AB63A8C008A53D0 /* HTMLEOFToken.m */; };
|
||||
623857911A9E772B003A45D9 /* HTMLDocument.h in Headers */ = {isa = PBXBuildFile; fileRef = 6238578F1A9E772B003A45D9 /* HTMLDocument.h */; };
|
||||
623857921A9E772B003A45D9 /* HTMLDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = 623857901A9E772B003A45D9 /* HTMLDocument.m */; };
|
||||
623857931A9E772B003A45D9 /* HTMLDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = 623857901A9E772B003A45D9 /* HTMLDocument.m */; };
|
||||
623857961A9E8606003A45D9 /* HTMLDocumentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 623857941A9E8606003A45D9 /* HTMLDocumentType.h */; };
|
||||
623857971A9E8606003A45D9 /* HTMLDocumentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 623857951A9E8606003A45D9 /* HTMLDocumentType.m */; };
|
||||
623857981A9E8606003A45D9 /* HTMLDocumentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 623857951A9E8606003A45D9 /* HTMLDocumentType.m */; };
|
||||
6238579B1A9E8934003A45D9 /* HTMLComment.h in Headers */ = {isa = PBXBuildFile; fileRef = 623857991A9E8934003A45D9 /* HTMLComment.h */; };
|
||||
6238579C1A9E8934003A45D9 /* HTMLComment.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238579A1A9E8934003A45D9 /* HTMLComment.m */; };
|
||||
6238579D1A9E8934003A45D9 /* HTMLComment.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238579A1A9E8934003A45D9 /* HTMLComment.m */; };
|
||||
6238C9851AB8D6330006512E /* HTMLKitExceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 6238C9831AB8D6330006512E /* HTMLKitExceptions.h */; };
|
||||
6238C9861AB8D6330006512E /* HTMLKitExceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238C9841AB8D6330006512E /* HTMLKitExceptions.m */; };
|
||||
6238C9871AB8D6330006512E /* HTMLKitExceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238C9841AB8D6330006512E /* HTMLKitExceptions.m */; };
|
||||
623916C31AC707250066B4FE /* HTMLNodeTreeEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */; };
|
||||
623916C41AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */; };
|
||||
623916C51AC707250066B4FE /* HTMLNodeTreeEnumerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */; };
|
||||
623916C71AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C61AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m */; };
|
||||
623916C81AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C61AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m */; };
|
||||
6238C9861AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */; };
|
||||
6238C9871AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */; };
|
||||
623916C71AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */; };
|
||||
623916C81AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */; };
|
||||
6239755A1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623975591AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m */; };
|
||||
6239755B1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 623975591AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m */; };
|
||||
6239755E1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6239755D1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.m */; };
|
||||
6239755F1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6239755D1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.m */; };
|
||||
623CAF9D1AD88BEA00E34C32 /* HTMLKitParserPerformance.m in Sources */ = {isa = PBXBuildFile; fileRef = 623CAF9C1AD88BEA00E34C32 /* HTMLKitParserPerformance.m */; };
|
||||
623CAF9E1AD88BEA00E34C32 /* HTMLKitParserPerformance.m in Sources */ = {isa = PBXBuildFile; fileRef = 623CAF9C1AD88BEA00E34C32 /* HTMLKitParserPerformance.m */; };
|
||||
624493A619CCC54100BCDDF4 /* HTMLTokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 624493A419CCC54100BCDDF4 /* HTMLTokenizer.h */; };
|
||||
624493A719CCC54100BCDDF4 /* HTMLTokenizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 624493A519CCC54100BCDDF4 /* HTMLTokenizer.m */; };
|
||||
624493A819CCC54100BCDDF4 /* HTMLTokenizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 624493A519CCC54100BCDDF4 /* HTMLTokenizer.m */; };
|
||||
624493AC19CD0CBE00BCDDF4 /* HTMLToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 624493AA19CD0CBE00BCDDF4 /* HTMLToken.h */; };
|
||||
624493AD19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */; };
|
||||
624493AE19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */; };
|
||||
624AC8FF19FBF59800BD3C4A /* HTMLTokens.h in Headers */ = {isa = PBXBuildFile; fileRef = 624AC8FE19FBF4F700BD3C4A /* HTMLTokens.h */; };
|
||||
624717191B22333200C11912 /* HTMLNodeTraversal.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717171B22333200C11912 /* HTMLNodeTraversal.m */; };
|
||||
6247171A1B22333200C11912 /* HTMLNodeTraversal.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717171B22333200C11912 /* HTMLNodeTraversal.m */; };
|
||||
6247171C1B2240B800C11912 /* HTMLTreeWalkerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6247171B1B2240B800C11912 /* HTMLTreeWalkerTests.m */; };
|
||||
6247171D1B2240B800C11912 /* HTMLTreeWalkerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6247171B1B2240B800C11912 /* HTMLTreeWalkerTests.m */; };
|
||||
624717B81B21FE5400B38302 /* HTMLNodeFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */; };
|
||||
624717B91B21FE5400B38302 /* HTMLNodeFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717B71B21FE5400B38302 /* HTMLNodeFilter.m */; };
|
||||
624717BD1B22009200B38302 /* HTMLTreeWalker.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717BB1B22009200B38302 /* HTMLTreeWalker.m */; };
|
||||
624717BE1B22009200B38302 /* HTMLTreeWalker.m in Sources */ = {isa = PBXBuildFile; fileRef = 624717BB1B22009200B38302 /* HTMLTreeWalker.m */; };
|
||||
6247A9441B152F4F00CCF25C /* HTMLNodeIterator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */; };
|
||||
6247A9451B152F4F00CCF25C /* HTMLNodeIterator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */; };
|
||||
624AB3171B0508AE00F3830D /* CSSTypeSelectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AB3161B0508AE00F3830D /* CSSTypeSelectorTests.m */; };
|
||||
624AB3181B0508AE00F3830D /* CSSTypeSelectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AB3161B0508AE00F3830D /* CSSTypeSelectorTests.m */; };
|
||||
624AB31A1B050A4D00F3830D /* CSSAttributeSelectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AB3191B050A4D00F3830D /* CSSAttributeSelectorTests.m */; };
|
||||
624AB31B1B050A4D00F3830D /* CSSAttributeSelectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AB3191B050A4D00F3830D /* CSSAttributeSelectorTests.m */; };
|
||||
624AC90119FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AC90019FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m */; };
|
||||
624AC90219FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624AC90019FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m */; };
|
||||
624AC90519FBFE9A00BD3C4A /* html5lib-tests in Resources */ = {isa = PBXBuildFile; fileRef = 624AC90419FBFE8A00BD3C4A /* html5lib-tests */; };
|
||||
624AC90619FBFEA000BD3C4A /* html5lib-tests in Resources */ = {isa = PBXBuildFile; fileRef = 624AC90419FBFE8A00BD3C4A /* html5lib-tests */; };
|
||||
624AC90E19FC702E00BD3C4A /* HTML Standard.html in Resources */ = {isa = PBXBuildFile; fileRef = 624AC90D19FC702E00BD3C4A /* HTML Standard.html */; };
|
||||
624AC90F19FC702E00BD3C4A /* HTML Standard.html in Resources */ = {isa = PBXBuildFile; fileRef = 624AC90D19FC702E00BD3C4A /* HTML Standard.html */; };
|
||||
624B28B91B03DA820048D328 /* CSSTypeSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B28B71B03DA820048D328 /* CSSTypeSelector.m */; };
|
||||
624B28BA1B03DA820048D328 /* CSSTypeSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B28B71B03DA820048D328 /* CSSTypeSelector.m */; };
|
||||
624B28C01B0413200048D328 /* CSSAttributeSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B28BE1B0413200048D328 /* CSSAttributeSelector.m */; };
|
||||
624B28C11B0413200048D328 /* CSSAttributeSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B28BE1B0413200048D328 /* CSSAttributeSelector.m */; };
|
||||
624B28C51B04190D0048D328 /* NSCharacterSet+HTMLKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B28C31B04190D0048D328 /* NSCharacterSet+HTMLKit.m */; };
|
||||
624B28C61B04190D0048D328 /* NSCharacterSet+HTMLKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B28C31B04190D0048D328 /* NSCharacterSet+HTMLKit.m */; };
|
||||
624B371F1B24E9BA0010BDDF /* CSSInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B371D1B24E9BA0010BDDF /* CSSInputStream.m */; };
|
||||
624B37201B24E9BA0010BDDF /* CSSInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B371D1B24E9BA0010BDDF /* CSSInputStream.m */; };
|
||||
624B9FB21AE0313300646C4C /* HTMLKitStringCategoryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B9FB11AE0313300646C4C /* HTMLKitStringCategoryTests.m */; };
|
||||
624B9FB31AE0313300646C4C /* HTMLKitStringCategoryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B9FB11AE0313300646C4C /* HTMLKitStringCategoryTests.m */; };
|
||||
624B9FB51AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B9FB41AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m */; };
|
||||
624B9FB61AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624B9FB41AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m */; };
|
||||
624FC37A1AE591D80015DDF9 /* HTMLKitNodesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624FC3791AE591D80015DDF9 /* HTMLKitNodesTests.m */; };
|
||||
624FC37B1AE591D80015DDF9 /* HTMLKitNodesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 624FC3791AE591D80015DDF9 /* HTMLKitNodesTests.m */; };
|
||||
625A14B019C7829400AD0C32 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 625A14AF19C7829400AD0C32 /* Cocoa.framework */; };
|
||||
625A14BA19C7829400AD0C32 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 625A14B819C7829400AD0C32 /* InfoPlist.strings */; };
|
||||
625A14BE19C7829400AD0C32 /* HTMLKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 625A14BD19C7829400AD0C32 /* HTMLKit.m */; };
|
||||
625A14C519C7829400AD0C32 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 625A14C419C7829400AD0C32 /* XCTest.framework */; };
|
||||
625A14C619C7829400AD0C32 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 625A14AF19C7829400AD0C32 /* Cocoa.framework */; };
|
||||
625A14C919C7829400AD0C32 /* HTMLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 625A14AC19C7829400AD0C32 /* HTMLKit.framework */; };
|
||||
@@ -90,38 +109,102 @@
|
||||
625A14E019C7834100AD0C32 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 625A14DF19C7834100AD0C32 /* Foundation.framework */; };
|
||||
625A14ED19C7834100AD0C32 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 625A14C419C7829400AD0C32 /* XCTest.framework */; };
|
||||
625A14EE19C7834100AD0C32 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 625A14DF19C7834100AD0C32 /* Foundation.framework */; };
|
||||
625A150219C783DE00AD0C32 /* HTMLKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 625A14BD19C7829400AD0C32 /* HTMLKit.m */; };
|
||||
625A150319C783E200AD0C32 /* HTMLKit.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 625A14BC19C7829400AD0C32 /* HTMLKit.h */; };
|
||||
625A150419C783EB00AD0C32 /* HTMLKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 625A14BC19C7829400AD0C32 /* HTMLKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
625A150819C78ABA00AD0C32 /* HTMLInputStreamReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 625A150619C78ABA00AD0C32 /* HTMLInputStreamReader.h */; };
|
||||
625A150919C78ABA00AD0C32 /* HTMLInputStreamReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 625A150719C78ABA00AD0C32 /* HTMLInputStreamReader.m */; };
|
||||
625A150A19C78ABA00AD0C32 /* HTMLInputStreamReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 625A150719C78ABA00AD0C32 /* HTMLInputStreamReader.m */; };
|
||||
6279F87419E1808D00F12EE5 /* HTMLElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 6279F87219E1808D00F12EE5 /* HTMLElement.h */; };
|
||||
626652F91C03D7AC00C3F121 /* HTMLKitErrorDomain.h in Headers */ = {isa = PBXBuildFile; fileRef = 626652F81C03D30F00C3F121 /* HTMLKitErrorDomain.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
6279F87519E1808D00F12EE5 /* HTMLElement.m in Sources */ = {isa = PBXBuildFile; fileRef = 6279F87319E1808D00F12EE5 /* HTMLElement.m */; };
|
||||
6279F87619E1808D00F12EE5 /* HTMLElement.m in Sources */ = {isa = PBXBuildFile; fileRef = 6279F87319E1808D00F12EE5 /* HTMLElement.m */; };
|
||||
62AE593519F97D880043F069 /* HTMLParseErrorToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 62AE593319F97D880043F069 /* HTMLParseErrorToken.h */; };
|
||||
628AF62F1BC99A6C00496128 /* CSSNthExpressionsParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 628AF62E1BC99A6C00496128 /* CSSNthExpressionsParserTests.m */; };
|
||||
628AF6301BC99A6C00496128 /* CSSNthExpressionsParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 628AF62E1BC99A6C00496128 /* CSSNthExpressionsParserTests.m */; };
|
||||
628AF6341BC9A63D00496128 /* CSSNthExpressionSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 628AF6321BC9A63D00496128 /* CSSNthExpressionSelector.m */; };
|
||||
628AF6351BC9A63D00496128 /* CSSNthExpressionSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 628AF6321BC9A63D00496128 /* CSSNthExpressionSelector.m */; };
|
||||
628AF63F1BC9D6FB00496128 /* CSSStructuralPseudoSelectors.m in Sources */ = {isa = PBXBuildFile; fileRef = 628AF63D1BC9D6FB00496128 /* CSSStructuralPseudoSelectors.m */; };
|
||||
628AF6401BC9D6FB00496128 /* CSSStructuralPseudoSelectors.m in Sources */ = {isa = PBXBuildFile; fileRef = 628AF63D1BC9D6FB00496128 /* CSSStructuralPseudoSelectors.m */; };
|
||||
629AA0EA1BDD9C2900D5CC98 /* HTMLKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 625A14BC19C7829400AD0C32 /* HTMLKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0EB1BDD9C2900D5CC98 /* HTMLParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 62F873E919E088C90062683C /* HTMLParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0EC1BDD9C2900D5CC98 /* HTMLDOM.h in Headers */ = {isa = PBXBuildFile; fileRef = 62362A3F1A9FDE8A00301989 /* HTMLDOM.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0ED1BDD9C2900D5CC98 /* HTMLNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 6234584C1A9D2FA4009BD491 /* HTMLNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0EE1BDD9C2900D5CC98 /* HTMLDocument.h in Headers */ = {isa = PBXBuildFile; fileRef = 6238578F1A9E772B003A45D9 /* HTMLDocument.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0EF1BDD9C2900D5CC98 /* HTMLDocumentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 623857941A9E8606003A45D9 /* HTMLDocumentType.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0F01BDD9C2900D5CC98 /* HTMLDocumentFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = 623406E41ADB05AD004677A3 /* HTMLDocumentFragment.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0F11BDD9C2900D5CC98 /* HTMLElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 6279F87219E1808D00F12EE5 /* HTMLElement.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0F21BDD9C2900D5CC98 /* HTMLComment.h in Headers */ = {isa = PBXBuildFile; fileRef = 623857991A9E8934003A45D9 /* HTMLComment.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0F31BDD9C2900D5CC98 /* HTMLText.h in Headers */ = {isa = PBXBuildFile; fileRef = 62362A3A1A9FA70400301989 /* HTMLText.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0F41BDD9C2A00D5CC98 /* HTMLTemplate.h in Headers */ = {isa = PBXBuildFile; fileRef = 623406DF1ADB04F9004677A3 /* HTMLTemplate.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0F51BDD9C2A00D5CC98 /* HTMLNodeIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0F61BDD9C2A00D5CC98 /* HTMLTreeWalker.h in Headers */ = {isa = PBXBuildFile; fileRef = 624717BA1B22009200B38302 /* HTMLTreeWalker.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0F71BDD9C2A00D5CC98 /* HTMLNodeTraversal.h in Headers */ = {isa = PBXBuildFile; fileRef = 624717161B22333200C11912 /* HTMLNodeTraversal.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0F81BDD9C2A00D5CC98 /* HTMLNodeFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0F91BDD9C2A00D5CC98 /* HTMLKitDOMExceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0FA1BDD9C2A00D5CC98 /* HTMLNamespaces.h in Headers */ = {isa = PBXBuildFile; fileRef = 628B7CE61A080E1000602C87 /* HTMLNamespaces.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0FB1BDD9C2A00D5CC98 /* HTMLQuirksMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 623719431AA12EE8002E03C8 /* HTMLQuirksMode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0FC1BDD9C2A00D5CC98 /* NSString+HTMLKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 6235CE991AA509430026937B /* NSString+HTMLKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0FD1BDD9C2A00D5CC98 /* NSCharacterSet+HTMLKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 624B28C21B04190D0048D328 /* NSCharacterSet+HTMLKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0FE1BDD9C2A00D5CC98 /* HTMLOrderedDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 623424861AB467B200726190 /* HTMLOrderedDictionary.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA0FF1BDD9C2A00D5CC98 /* CSSSelectors.h in Headers */ = {isa = PBXBuildFile; fileRef = 624AB3151B04EA4200F3830D /* CSSSelectors.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA1001BDD9C2A00D5CC98 /* CSSSelectorParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 622BF57F1BBF2FD700363583 /* CSSSelectorParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA1011BDD9C2A00D5CC98 /* CSSSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = 62079BE71AF56F1E00D3B402 /* CSSSelector.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA1021BDD9C2B00D5CC98 /* CSSSelectorBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 62FA98061BD5A7E200A2AF86 /* CSSSelectorBlock.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA1031BDD9C2B00D5CC98 /* CSSTypeSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = 624B28B61B03DA820048D328 /* CSSTypeSelector.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA1041BDD9C2B00D5CC98 /* CSSAttributeSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = 624B28BD1B0413200048D328 /* CSSAttributeSelector.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA1051BDD9C2B00D5CC98 /* CSSPseudoClassSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = 620EE9471BC46F2A0028ED34 /* CSSPseudoClassSelector.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA1061BDD9C2B00D5CC98 /* CSSStructuralPseudoSelectors.h in Headers */ = {isa = PBXBuildFile; fileRef = 628AF63C1BC9D6FB00496128 /* CSSStructuralPseudoSelectors.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA1071BDD9C2B00D5CC98 /* CSSNthExpressionSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = 628AF6311BC9A63D00496128 /* CSSNthExpressionSelector.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA1081BDD9C2B00D5CC98 /* CSSPseudoFunctionSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = 62ACB8DB1BC5C13E00E283C1 /* CSSPseudoFunctionSelector.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA1091BDD9C2B00D5CC98 /* CSSCombinatorSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = 62FA04E11BCC360D009ABF98 /* CSSCombinatorSelector.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA10A1BDD9C2B00D5CC98 /* CSSCompoundSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = 620C87791BD44CBE00FB3EEE /* CSSCompoundSelector.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
629AA10B1BDD9C5200D5CC98 /* HTMLTokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 624493A419CCC54100BCDDF4 /* HTMLTokenizer.h */; };
|
||||
629AA10C1BDD9C5200D5CC98 /* HTMLTokenizerStates.h in Headers */ = {isa = PBXBuildFile; fileRef = 624493A919CCE84A00BCDDF4 /* HTMLTokenizerStates.h */; };
|
||||
629AA10D1BDD9C5300D5CC98 /* HTMLTokenizerCharacters.h in Headers */ = {isa = PBXBuildFile; fileRef = 62E7CAAE19CDFFB500465A83 /* HTMLTokenizerCharacters.h */; };
|
||||
629AA10E1BDD9C5300D5CC98 /* HTMLTokenizerEntities.h in Headers */ = {isa = PBXBuildFile; fileRef = 62F31FDB19E9DCCF007F0657 /* HTMLTokenizerEntities.h */; };
|
||||
629AA10F1BDD9C5300D5CC98 /* HTMLTokens.h in Headers */ = {isa = PBXBuildFile; fileRef = 624AC8FE19FBF4F700BD3C4A /* HTMLTokens.h */; };
|
||||
629AA1101BDD9C5300D5CC98 /* HTMLToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 624493AA19CD0CBE00BCDDF4 /* HTMLToken.h */; };
|
||||
629AA1111BDD9C5300D5CC98 /* HTMLCharacterToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 62AE594719F9948A0043F069 /* HTMLCharacterToken.h */; };
|
||||
629AA1121BDD9C5300D5CC98 /* HTMLCommentToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 62AE594219F992F30043F069 /* HTMLCommentToken.h */; };
|
||||
629AA1131BDD9C5300D5CC98 /* HTMLDOCTYPEToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 62AE593819F97E1C0043F069 /* HTMLDOCTYPEToken.h */; };
|
||||
629AA1141BDD9C5400D5CC98 /* HTMLParseErrorToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 62AE593319F97D880043F069 /* HTMLParseErrorToken.h */; };
|
||||
629AA1151BDD9C5400D5CC98 /* HTMLTagToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 62AE593D19F9907C0043F069 /* HTMLTagToken.h */; };
|
||||
629AA1161BDD9C5400D5CC98 /* HTMLEOFToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 6238039D1AB63A8C008A53D0 /* HTMLEOFToken.h */; };
|
||||
629AA1171BDD9C5400D5CC98 /* HTMLStackOfOpenElements.h in Headers */ = {isa = PBXBuildFile; fileRef = 6234BEEC1AABBF1400DEB15F /* HTMLStackOfOpenElements.h */; };
|
||||
629AA1181BDD9C5400D5CC98 /* HTMLListOfActiveFormattingElements.h in Headers */ = {isa = PBXBuildFile; fileRef = 62363C3B1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h */; };
|
||||
629AA1191BDD9C5400D5CC98 /* HTMLElementTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 6223211D1A969B9300BACED5 /* HTMLElementTypes.h */; };
|
||||
629AA11A1BDD9C5400D5CC98 /* HTMLElementAdjustment.h in Headers */ = {isa = PBXBuildFile; fileRef = 6234C3361AB3BF710046F527 /* HTMLElementAdjustment.h */; };
|
||||
629AA11B1BDD9C5500D5CC98 /* HTMLParserInsertionModes.h in Headers */ = {isa = PBXBuildFile; fileRef = 6279F87119E17DC700F12EE5 /* HTMLParserInsertionModes.h */; };
|
||||
629AA11C1BDD9C5500D5CC98 /* HTMLMarker.h in Headers */ = {isa = PBXBuildFile; fileRef = 6235CE9E1AA5170A0026937B /* HTMLMarker.h */; };
|
||||
629AA11D1BDD9C5500D5CC98 /* CSSCodePoints.h in Headers */ = {isa = PBXBuildFile; fileRef = 624B37211B250BB50010BDDF /* CSSCodePoints.h */; };
|
||||
629AA11E1BDD9C5500D5CC98 /* CSSInputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 624B371C1B24E9BA0010BDDF /* CSSInputStream.h */; };
|
||||
629AA11F1BDD9C5E00D5CC98 /* CSSNthExpressionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 62F501631BC9576B0069F47B /* CSSNthExpressionParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
62AE593619F97D880043F069 /* HTMLParseErrorToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 62AE593419F97D880043F069 /* HTMLParseErrorToken.m */; };
|
||||
62AE593719F97D880043F069 /* HTMLParseErrorToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 62AE593419F97D880043F069 /* HTMLParseErrorToken.m */; };
|
||||
62AE593A19F97E1C0043F069 /* HTMLDOCTYPEToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 62AE593819F97E1C0043F069 /* HTMLDOCTYPEToken.h */; };
|
||||
62AE593B19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 62AE593919F97E1C0043F069 /* HTMLDOCTYPEToken.m */; };
|
||||
62AE593C19F97E1C0043F069 /* HTMLDOCTYPEToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 62AE593919F97E1C0043F069 /* HTMLDOCTYPEToken.m */; };
|
||||
62AE593F19F9907C0043F069 /* HTMLTagToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 62AE593D19F9907C0043F069 /* HTMLTagToken.h */; };
|
||||
62AE594019F9907C0043F069 /* HTMLTagToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 62AE593E19F9907C0043F069 /* HTMLTagToken.m */; };
|
||||
62AE594119F9907C0043F069 /* HTMLTagToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 62AE593E19F9907C0043F069 /* HTMLTagToken.m */; };
|
||||
62AE594419F992F30043F069 /* HTMLCommentToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 62AE594219F992F30043F069 /* HTMLCommentToken.h */; };
|
||||
62AE594519F992F30043F069 /* HTMLCommentToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 62AE594319F992F30043F069 /* HTMLCommentToken.m */; };
|
||||
62AE594619F992F30043F069 /* HTMLCommentToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 62AE594319F992F30043F069 /* HTMLCommentToken.m */; };
|
||||
62AE594919F9948A0043F069 /* HTMLCharacterToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 62AE594719F9948A0043F069 /* HTMLCharacterToken.h */; };
|
||||
62AE594A19F9948A0043F069 /* HTMLCharacterToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 62AE594819F9948A0043F069 /* HTMLCharacterToken.m */; };
|
||||
62AE594B19F9948A0043F069 /* HTMLCharacterToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 62AE594819F9948A0043F069 /* HTMLCharacterToken.m */; };
|
||||
62D8345919FB1AC4009205A9 /* HTML5LibTokenizerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 62D8345819FB1AC4009205A9 /* HTML5LibTokenizerTest.m */; };
|
||||
62D8345A19FB1AC4009205A9 /* HTML5LibTokenizerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 62D8345819FB1AC4009205A9 /* HTML5LibTokenizerTest.m */; };
|
||||
62F31FDD19E9DCCF007F0657 /* HTMLTokenizerEntities.h in Headers */ = {isa = PBXBuildFile; fileRef = 62F31FDB19E9DCCF007F0657 /* HTMLTokenizerEntities.h */; };
|
||||
62EC7AE61AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */; };
|
||||
62EC7AE71AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */; };
|
||||
62F31FDE19E9DCCF007F0657 /* HTMLTokenizerEntities.m in Sources */ = {isa = PBXBuildFile; fileRef = 62F31FDC19E9DCCF007F0657 /* HTMLTokenizerEntities.m */; };
|
||||
62F31FDF19E9DCCF007F0657 /* HTMLTokenizerEntities.m in Sources */ = {isa = PBXBuildFile; fileRef = 62F31FDC19E9DCCF007F0657 /* HTMLTokenizerEntities.m */; };
|
||||
62F873EB19E088C90062683C /* HTMLParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 62F873E919E088C90062683C /* HTMLParser.h */; };
|
||||
62F501661BC9576B0069F47B /* CSSNthExpressionParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 62F501641BC9576B0069F47B /* CSSNthExpressionParser.m */; };
|
||||
62F501671BC9576B0069F47B /* CSSNthExpressionParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 62F501641BC9576B0069F47B /* CSSNthExpressionParser.m */; };
|
||||
62F658701BD83C8E0045F137 /* CSSNThExpressionSelectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62F6586F1BD83C8E0045F137 /* CSSNThExpressionSelectorTests.m */; };
|
||||
62F658711BD83C8E0045F137 /* CSSNThExpressionSelectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62F6586F1BD83C8E0045F137 /* CSSNThExpressionSelectorTests.m */; };
|
||||
62F873EC19E088C90062683C /* HTMLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 62F873EA19E088C90062683C /* HTMLParser.m */; };
|
||||
62F873ED19E088C90062683C /* HTMLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 62F873EA19E088C90062683C /* HTMLParser.m */; };
|
||||
62FA04E41BCC360D009ABF98 /* CSSCombinatorSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 62FA04E21BCC360D009ABF98 /* CSSCombinatorSelector.m */; };
|
||||
62FA04E51BCC360D009ABF98 /* CSSCombinatorSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 62FA04E21BCC360D009ABF98 /* CSSCombinatorSelector.m */; };
|
||||
62FA98041BD57B6200A2AF86 /* CSSSelectors.m in Sources */ = {isa = PBXBuildFile; fileRef = 62FA98031BD57B6200A2AF86 /* CSSSelectors.m */; };
|
||||
62FA98051BD57B6200A2AF86 /* CSSSelectors.m in Sources */ = {isa = PBXBuildFile; fileRef = 62FA98031BD57B6200A2AF86 /* CSSSelectors.m */; };
|
||||
62FA98091BD5A7E200A2AF86 /* CSSSelectorBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 62FA98071BD5A7E200A2AF86 /* CSSSelectorBlock.m */; };
|
||||
62FA980A1BD5A7E200A2AF86 /* CSSSelectorBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 62FA98071BD5A7E200A2AF86 /* CSSSelectorBlock.m */; };
|
||||
62FC60461BD0519B0042BBE7 /* CSSSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 62FC60451BD0519B0042BBE7 /* CSSSelector.m */; };
|
||||
62FC60471BD0519B0042BBE7 /* CSSSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 62FC60451BD0519B0042BBE7 /* CSSSelector.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -155,7 +238,19 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
62079BE71AF56F1E00D3B402 /* CSSSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelector.h; sourceTree = "<group>"; };
|
||||
620C87791BD44CBE00FB3EEE /* CSSCompoundSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSCompoundSelector.h; sourceTree = "<group>"; };
|
||||
620C877A1BD44CBE00FB3EEE /* CSSCompoundSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSCompoundSelector.m; sourceTree = "<group>"; };
|
||||
620EE9471BC46F2A0028ED34 /* CSSPseudoClassSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSPseudoClassSelector.h; sourceTree = "<group>"; };
|
||||
620EE9481BC46F2A0028ED34 /* CSSPseudoClassSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSPseudoClassSelector.m; sourceTree = "<group>"; };
|
||||
62132E571C01F83200084175 /* CSSSelectorTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelectorTest.h; sourceTree = "<group>"; };
|
||||
62132E581C01F83200084175 /* CSSSelectorTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorTest.m; sourceTree = "<group>"; };
|
||||
62132E5B1C021FF200084175 /* css-tests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "css-tests"; sourceTree = "<group>"; };
|
||||
621FBE591BDAD68700BC9555 /* CSSSelectorParserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorParserTests.m; sourceTree = "<group>"; };
|
||||
621FBE5C1BDAD90200BC9555 /* CSSCombinatorSelectorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSCombinatorSelectorTests.m; sourceTree = "<group>"; };
|
||||
6223211D1A969B9300BACED5 /* HTMLElementTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLElementTypes.h; sourceTree = "<group>"; };
|
||||
622BF57F1BBF2FD700363583 /* CSSSelectorParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelectorParser.h; sourceTree = "<group>"; };
|
||||
622BF5801BBF2FD700363583 /* CSSSelectorParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorParser.m; 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>"; };
|
||||
@@ -173,7 +268,7 @@
|
||||
6235CE9F1AA5170A0026937B /* HTMLMarker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLMarker.m; sourceTree = "<group>"; };
|
||||
62362A3A1A9FA70400301989 /* HTMLText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLText.h; sourceTree = "<group>"; };
|
||||
62362A3B1A9FA70400301989 /* HTMLText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLText.m; sourceTree = "<group>"; };
|
||||
62362A3F1A9FDE8A00301989 /* HTMLNodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLNodes.h; sourceTree = "<group>"; };
|
||||
62362A3F1A9FDE8A00301989 /* HTMLDOM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLDOM.h; sourceTree = "<group>"; };
|
||||
62363C3B1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLListOfActiveFormattingElements.h; sourceTree = "<group>"; };
|
||||
62363C3C1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLListOfActiveFormattingElements.m; sourceTree = "<group>"; };
|
||||
6236738D1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTokenizerPerformance.m; sourceTree = "<group>"; };
|
||||
@@ -186,11 +281,9 @@
|
||||
623857951A9E8606003A45D9 /* HTMLDocumentType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLDocumentType.m; sourceTree = "<group>"; };
|
||||
623857991A9E8934003A45D9 /* HTMLComment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLComment.h; sourceTree = "<group>"; };
|
||||
6238579A1A9E8934003A45D9 /* HTMLComment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLComment.m; sourceTree = "<group>"; };
|
||||
6238C9831AB8D6330006512E /* HTMLKitExceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLKitExceptions.h; sourceTree = "<group>"; };
|
||||
6238C9841AB8D6330006512E /* HTMLKitExceptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitExceptions.m; sourceTree = "<group>"; };
|
||||
623916C11AC707250066B4FE /* HTMLNodeTreeEnumerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeTreeEnumerator.h; sourceTree = "<group>"; };
|
||||
623916C21AC707250066B4FE /* HTMLNodeTreeEnumerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeTreeEnumerator.m; sourceTree = "<group>"; };
|
||||
623916C61AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitNodeTreeEnumratorTests.m; sourceTree = "<group>"; };
|
||||
6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLKitDOMExceptions.h; sourceTree = "<group>"; };
|
||||
6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitDOMExceptions.m; sourceTree = "<group>"; };
|
||||
623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitNodeIteratorTests.m; sourceTree = "<group>"; };
|
||||
623975591AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTreeConstructionTests.m; sourceTree = "<group>"; };
|
||||
6239755C1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTML5LibTreeConstructionTest.h; sourceTree = "<group>"; };
|
||||
6239755D1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTML5LibTreeConstructionTest.m; sourceTree = "<group>"; };
|
||||
@@ -200,12 +293,34 @@
|
||||
624493A919CCE84A00BCDDF4 /* HTMLTokenizerStates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLTokenizerStates.h; sourceTree = "<group>"; };
|
||||
624493AA19CD0CBE00BCDDF4 /* HTMLToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLToken.h; sourceTree = "<group>"; };
|
||||
624493AB19CD0CBE00BCDDF4 /* HTMLToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLToken.m; sourceTree = "<group>"; };
|
||||
624717161B22333200C11912 /* HTMLNodeTraversal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeTraversal.h; sourceTree = "<group>"; };
|
||||
624717171B22333200C11912 /* HTMLNodeTraversal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeTraversal.m; sourceTree = "<group>"; };
|
||||
6247171B1B2240B800C11912 /* HTMLTreeWalkerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLTreeWalkerTests.m; sourceTree = "<group>"; };
|
||||
624717B71B21FE5400B38302 /* HTMLNodeFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeFilter.m; sourceTree = "<group>"; };
|
||||
624717BA1B22009200B38302 /* HTMLTreeWalker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLTreeWalker.h; sourceTree = "<group>"; };
|
||||
624717BB1B22009200B38302 /* HTMLTreeWalker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLTreeWalker.m; sourceTree = "<group>"; };
|
||||
6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeIterator.h; sourceTree = "<group>"; };
|
||||
6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLNodeIterator.m; sourceTree = "<group>"; };
|
||||
6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLNodeFilter.h; sourceTree = "<group>"; };
|
||||
624AB3151B04EA4200F3830D /* CSSSelectors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSSSelectors.h; sourceTree = "<group>"; };
|
||||
624AB3161B0508AE00F3830D /* CSSTypeSelectorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSTypeSelectorTests.m; sourceTree = "<group>"; };
|
||||
624AB3191B050A4D00F3830D /* CSSAttributeSelectorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSAttributeSelectorTests.m; sourceTree = "<group>"; };
|
||||
624AC8FE19FBF4F700BD3C4A /* HTMLTokens.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLTokens.h; sourceTree = "<group>"; };
|
||||
624AC90019FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitTokenizerTests.m; sourceTree = "<group>"; };
|
||||
624AC90419FBFE8A00BD3C4A /* html5lib-tests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "html5lib-tests"; sourceTree = "<group>"; };
|
||||
624AC90D19FC702E00BD3C4A /* HTML Standard.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "HTML Standard.html"; sourceTree = "<group>"; };
|
||||
624B28B61B03DA820048D328 /* CSSTypeSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSTypeSelector.h; sourceTree = "<group>"; };
|
||||
624B28B71B03DA820048D328 /* CSSTypeSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSTypeSelector.m; sourceTree = "<group>"; };
|
||||
624B28BD1B0413200048D328 /* CSSAttributeSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSAttributeSelector.h; sourceTree = "<group>"; };
|
||||
624B28BE1B0413200048D328 /* CSSAttributeSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSAttributeSelector.m; sourceTree = "<group>"; };
|
||||
624B28C21B04190D0048D328 /* NSCharacterSet+HTMLKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSCharacterSet+HTMLKit.h"; sourceTree = "<group>"; };
|
||||
624B28C31B04190D0048D328 /* NSCharacterSet+HTMLKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSCharacterSet+HTMLKit.m"; sourceTree = "<group>"; };
|
||||
624B371C1B24E9BA0010BDDF /* CSSInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSInputStream.h; sourceTree = "<group>"; };
|
||||
624B371D1B24E9BA0010BDDF /* CSSInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSInputStream.m; sourceTree = "<group>"; };
|
||||
624B37211B250BB50010BDDF /* CSSCodePoints.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSSCodePoints.h; sourceTree = "<group>"; };
|
||||
624B9FB11AE0313300646C4C /* HTMLKitStringCategoryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitStringCategoryTests.m; sourceTree = "<group>"; };
|
||||
624B9FB41AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitOrderedDictionaryTests.m; sourceTree = "<group>"; };
|
||||
624FC3791AE591D80015DDF9 /* HTMLKitNodesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitNodesTests.m; sourceTree = "<group>"; };
|
||||
625A14AC19C7829400AD0C32 /* HTMLKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = HTMLKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
625A14AF19C7829400AD0C32 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||
625A14B219C7829400AD0C32 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
@@ -215,7 +330,6 @@
|
||||
625A14B919C7829400AD0C32 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
625A14BB19C7829400AD0C32 /* HTMLKit-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "HTMLKit-Prefix.pch"; sourceTree = "<group>"; };
|
||||
625A14BC19C7829400AD0C32 /* HTMLKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLKit.h; sourceTree = "<group>"; };
|
||||
625A14BD19C7829400AD0C32 /* HTMLKit.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HTMLKit.m; sourceTree = "<group>"; };
|
||||
625A14C319C7829400AD0C32 /* HTMLKitFrameworkTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HTMLKitFrameworkTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
625A14C419C7829400AD0C32 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
|
||||
625A14CC19C7829400AD0C32 /* HTMLKitTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HTMLKitTests-Info.plist"; sourceTree = "<group>"; };
|
||||
@@ -225,10 +339,18 @@
|
||||
625A14EC19C7834100AD0C32 /* HTMLKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HTMLKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
6279F87319E1808D00F12EE5 /* HTMLElement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLElement.m; sourceTree = "<group>"; };
|
||||
628AF62E1BC99A6C00496128 /* CSSNthExpressionsParserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSNthExpressionsParserTests.m; sourceTree = "<group>"; };
|
||||
628AF6311BC9A63D00496128 /* CSSNthExpressionSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSNthExpressionSelector.h; sourceTree = "<group>"; };
|
||||
628AF6321BC9A63D00496128 /* CSSNthExpressionSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSNthExpressionSelector.m; sourceTree = "<group>"; };
|
||||
628AF63C1BC9D6FB00496128 /* CSSStructuralPseudoSelectors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSStructuralPseudoSelectors.h; sourceTree = "<group>"; };
|
||||
628AF63D1BC9D6FB00496128 /* CSSStructuralPseudoSelectors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSStructuralPseudoSelectors.m; sourceTree = "<group>"; };
|
||||
628B7CE61A080E1000602C87 /* HTMLNamespaces.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLNamespaces.h; sourceTree = "<group>"; };
|
||||
62ACB8DB1BC5C13E00E283C1 /* CSSPseudoFunctionSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSPseudoFunctionSelector.h; sourceTree = "<group>"; };
|
||||
62ACB8DC1BC5C13E00E283C1 /* CSSPseudoFunctionSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSPseudoFunctionSelector.m; sourceTree = "<group>"; };
|
||||
62AE593319F97D880043F069 /* HTMLParseErrorToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLParseErrorToken.h; sourceTree = "<group>"; };
|
||||
62AE593419F97D880043F069 /* HTMLParseErrorToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLParseErrorToken.m; sourceTree = "<group>"; };
|
||||
62AE593819F97E1C0043F069 /* HTMLDOCTYPEToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLDOCTYPEToken.h; sourceTree = "<group>"; };
|
||||
@@ -242,10 +364,20 @@
|
||||
62D8345719FB1AC4009205A9 /* HTML5LibTokenizerTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTML5LibTokenizerTest.h; sourceTree = "<group>"; };
|
||||
62D8345819FB1AC4009205A9 /* HTML5LibTokenizerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTML5LibTokenizerTest.m; sourceTree = "<group>"; };
|
||||
62E7CAAE19CDFFB500465A83 /* HTMLTokenizerCharacters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HTMLTokenizerCharacters.h; sourceTree = "<group>"; };
|
||||
62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLKitMutationAlgorithmsTests.m; sourceTree = "<group>"; };
|
||||
62F31FDB19E9DCCF007F0657 /* HTMLTokenizerEntities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLTokenizerEntities.h; sourceTree = "<group>"; };
|
||||
62F31FDC19E9DCCF007F0657 /* HTMLTokenizerEntities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLTokenizerEntities.m; sourceTree = "<group>"; };
|
||||
62F501631BC9576B0069F47B /* CSSNthExpressionParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSNthExpressionParser.h; sourceTree = "<group>"; };
|
||||
62F501641BC9576B0069F47B /* CSSNthExpressionParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSNthExpressionParser.m; sourceTree = "<group>"; };
|
||||
62F6586F1BD83C8E0045F137 /* CSSNThExpressionSelectorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSNThExpressionSelectorTests.m; sourceTree = "<group>"; };
|
||||
62F873E919E088C90062683C /* HTMLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLParser.h; sourceTree = "<group>"; };
|
||||
62F873EA19E088C90062683C /* HTMLParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTMLParser.m; sourceTree = "<group>"; };
|
||||
62FA04E11BCC360D009ABF98 /* CSSCombinatorSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSCombinatorSelector.h; sourceTree = "<group>"; };
|
||||
62FA04E21BCC360D009ABF98 /* CSSCombinatorSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSCombinatorSelector.m; sourceTree = "<group>"; };
|
||||
62FA98031BD57B6200A2AF86 /* CSSSelectors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectors.m; sourceTree = "<group>"; };
|
||||
62FA98061BD5A7E200A2AF86 /* CSSSelectorBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSSelectorBlock.h; sourceTree = "<group>"; };
|
||||
62FA98071BD5A7E200A2AF86 /* CSSSelectorBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelectorBlock.m; sourceTree = "<group>"; };
|
||||
62FC60451BD0519B0042BBE7 /* CSSSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSSelector.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -288,6 +420,42 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
62079BE61AF5656600D3B402 /* Selectors */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
624AB3151B04EA4200F3830D /* CSSSelectors.h */,
|
||||
62FA98031BD57B6200A2AF86 /* CSSSelectors.m */,
|
||||
624B37211B250BB50010BDDF /* CSSCodePoints.h */,
|
||||
624B371C1B24E9BA0010BDDF /* CSSInputStream.h */,
|
||||
624B371D1B24E9BA0010BDDF /* CSSInputStream.m */,
|
||||
622BF57F1BBF2FD700363583 /* CSSSelectorParser.h */,
|
||||
622BF5801BBF2FD700363583 /* CSSSelectorParser.m */,
|
||||
62F501631BC9576B0069F47B /* CSSNthExpressionParser.h */,
|
||||
62F501641BC9576B0069F47B /* CSSNthExpressionParser.m */,
|
||||
62079BE71AF56F1E00D3B402 /* CSSSelector.h */,
|
||||
62FC60451BD0519B0042BBE7 /* CSSSelector.m */,
|
||||
62FA98061BD5A7E200A2AF86 /* CSSSelectorBlock.h */,
|
||||
62FA98071BD5A7E200A2AF86 /* CSSSelectorBlock.m */,
|
||||
624B28B61B03DA820048D328 /* CSSTypeSelector.h */,
|
||||
624B28B71B03DA820048D328 /* CSSTypeSelector.m */,
|
||||
624B28BD1B0413200048D328 /* CSSAttributeSelector.h */,
|
||||
624B28BE1B0413200048D328 /* CSSAttributeSelector.m */,
|
||||
620EE9471BC46F2A0028ED34 /* CSSPseudoClassSelector.h */,
|
||||
620EE9481BC46F2A0028ED34 /* CSSPseudoClassSelector.m */,
|
||||
628AF63C1BC9D6FB00496128 /* CSSStructuralPseudoSelectors.h */,
|
||||
628AF63D1BC9D6FB00496128 /* CSSStructuralPseudoSelectors.m */,
|
||||
628AF6311BC9A63D00496128 /* CSSNthExpressionSelector.h */,
|
||||
628AF6321BC9A63D00496128 /* CSSNthExpressionSelector.m */,
|
||||
62ACB8DB1BC5C13E00E283C1 /* CSSPseudoFunctionSelector.h */,
|
||||
62ACB8DC1BC5C13E00E283C1 /* CSSPseudoFunctionSelector.m */,
|
||||
62FA04E11BCC360D009ABF98 /* CSSCombinatorSelector.h */,
|
||||
62FA04E21BCC360D009ABF98 /* CSSCombinatorSelector.m */,
|
||||
620C87791BD44CBE00FB3EEE /* CSSCompoundSelector.h */,
|
||||
620C877A1BD44CBE00FB3EEE /* CSSCompoundSelector.m */,
|
||||
);
|
||||
name = Selectors;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6236738C1AC0CD2400FF89B3 /* Tokenizer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -299,31 +467,40 @@
|
||||
name = Tokenizer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
623719441AA1472B002E03C8 /* Nodes */ = {
|
||||
623719441AA1472B002E03C8 /* DOM */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
623719431AA12EE8002E03C8 /* HTMLQuirksMode.h */,
|
||||
62362A3F1A9FDE8A00301989 /* HTMLNodes.h */,
|
||||
62362A3F1A9FDE8A00301989 /* HTMLDOM.h */,
|
||||
6234584C1A9D2FA4009BD491 /* HTMLNode.h */,
|
||||
6234584D1A9D2FA4009BD491 /* HTMLNode.m */,
|
||||
6279F87219E1808D00F12EE5 /* HTMLElement.h */,
|
||||
6279F87319E1808D00F12EE5 /* HTMLElement.m */,
|
||||
6238578F1A9E772B003A45D9 /* HTMLDocument.h */,
|
||||
623857901A9E772B003A45D9 /* HTMLDocument.m */,
|
||||
623857941A9E8606003A45D9 /* HTMLDocumentType.h */,
|
||||
623857951A9E8606003A45D9 /* HTMLDocumentType.m */,
|
||||
623406E41ADB05AD004677A3 /* HTMLDocumentFragment.h */,
|
||||
623406E51ADB05AD004677A3 /* HTMLDocumentFragment.m */,
|
||||
6279F87219E1808D00F12EE5 /* HTMLElement.h */,
|
||||
6279F87319E1808D00F12EE5 /* HTMLElement.m */,
|
||||
623857991A9E8934003A45D9 /* HTMLComment.h */,
|
||||
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 */,
|
||||
6247A9411B152F4F00CCF25C /* HTMLNodeIterator.h */,
|
||||
6247A9421B152F4F00CCF25C /* HTMLNodeIterator.m */,
|
||||
624717BA1B22009200B38302 /* HTMLTreeWalker.h */,
|
||||
624717BB1B22009200B38302 /* HTMLTreeWalker.m */,
|
||||
624717161B22333200C11912 /* HTMLNodeTraversal.h */,
|
||||
624717171B22333200C11912 /* HTMLNodeTraversal.m */,
|
||||
6247A9461B152F8C00CCF25C /* HTMLNodeFilter.h */,
|
||||
624717B71B21FE5400B38302 /* HTMLNodeFilter.m */,
|
||||
6238C9831AB8D6330006512E /* HTMLKitDOMExceptions.h */,
|
||||
6238C9841AB8D6330006512E /* HTMLKitDOMExceptions.m */,
|
||||
628B7CE61A080E1000602C87 /* HTMLNamespaces.h */,
|
||||
623719431AA12EE8002E03C8 /* HTMLQuirksMode.h */,
|
||||
);
|
||||
name = Nodes;
|
||||
name = DOM;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
623975581AC362A5007E26F1 /* Tree Construction */ = {
|
||||
@@ -337,13 +514,15 @@
|
||||
name = "Tree Construction";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
624B9FB71AE072CB00646C4C /* Nodes */ = {
|
||||
624B9FB71AE072CB00646C4C /* DOM */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
623916C61AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m */,
|
||||
624B9FB41AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m */,
|
||||
623916C61AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m */,
|
||||
6247171B1B2240B800C11912 /* HTMLTreeWalkerTests.m */,
|
||||
624FC3791AE591D80015DDF9 /* HTMLKitNodesTests.m */,
|
||||
62EC7AE51AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m */,
|
||||
);
|
||||
name = Nodes;
|
||||
name = DOM;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
624B9FB81AE072D500646C4C /* Categories */ = {
|
||||
@@ -354,6 +533,14 @@
|
||||
name = Categories;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
624E1A2D1B1D1C8A00E66AAC /* Structures */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
624B9FB41AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m */,
|
||||
);
|
||||
name = Structures;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
625A14A219C7829400AD0C32 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -400,14 +587,13 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
625A14BC19C7829400AD0C32 /* HTMLKit.h */,
|
||||
625A14BD19C7829400AD0C32 /* HTMLKit.m */,
|
||||
6238C9831AB8D6330006512E /* HTMLKitExceptions.h */,
|
||||
6238C9841AB8D6330006512E /* HTMLKitExceptions.m */,
|
||||
626652F81C03D30F00C3F121 /* HTMLKitErrorDomain.h */,
|
||||
62AE593219F97CCA0043F069 /* Tokenizing */,
|
||||
628E16EC1ADAE71700B15A06 /* Parsing */,
|
||||
623719441AA1472B002E03C8 /* Nodes */,
|
||||
623719441AA1472B002E03C8 /* DOM */,
|
||||
628E16ED1ADAE73700B15A06 /* Categories */,
|
||||
628E16EE1ADAE75300B15A06 /* Structures */,
|
||||
62079BE61AF5656600D3B402 /* Selectors */,
|
||||
625A14B619C7829400AD0C32 /* Supporting Files */,
|
||||
);
|
||||
name = "Source Code";
|
||||
@@ -429,8 +615,10 @@
|
||||
children = (
|
||||
6236738C1AC0CD2400FF89B3 /* Tokenizer */,
|
||||
623975581AC362A5007E26F1 /* Tree Construction */,
|
||||
624B9FB71AE072CB00646C4C /* Nodes */,
|
||||
624B9FB71AE072CB00646C4C /* DOM */,
|
||||
624B9FB81AE072D500646C4C /* Categories */,
|
||||
624E1A2D1B1D1C8A00E66AAC /* Structures */,
|
||||
62FF516C1C0A430A009BFDFE /* Selectors */,
|
||||
625A14CB19C7829400AD0C32 /* Supporting Files */,
|
||||
);
|
||||
name = Tests;
|
||||
@@ -440,6 +628,7 @@
|
||||
625A14CB19C7829400AD0C32 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
62132E5B1C021FF200084175 /* css-tests */,
|
||||
624AC90D19FC702E00BD3C4A /* HTML Standard.html */,
|
||||
624AC90419FBFE8A00BD3C4A /* html5lib-tests */,
|
||||
625A14CC19C7829400AD0C32 /* HTMLKitTests-Info.plist */,
|
||||
@@ -457,7 +646,6 @@
|
||||
6234BEED1AABBF1400DEB15F /* HTMLStackOfOpenElements.m */,
|
||||
62363C3B1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.h */,
|
||||
62363C3C1ABE428200DAB4C6 /* HTMLListOfActiveFormattingElements.m */,
|
||||
628B7CE61A080E1000602C87 /* HTMLNamespaces.h */,
|
||||
6223211D1A969B9300BACED5 /* HTMLElementTypes.h */,
|
||||
6234C3361AB3BF710046F527 /* HTMLElementAdjustment.h */,
|
||||
6279F87119E17DC700F12EE5 /* HTMLParserInsertionModes.h */,
|
||||
@@ -472,6 +660,8 @@
|
||||
children = (
|
||||
6235CE991AA509430026937B /* NSString+HTMLKit.h */,
|
||||
6235CE9A1AA509430026937B /* NSString+HTMLKit.m */,
|
||||
624B28C21B04190D0048D328 /* NSCharacterSet+HTMLKit.h */,
|
||||
624B28C31B04190D0048D328 /* NSCharacterSet+HTMLKit.m */,
|
||||
);
|
||||
name = Categories;
|
||||
sourceTree = "<group>";
|
||||
@@ -515,6 +705,21 @@
|
||||
name = Tokenizing;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
62FF516C1C0A430A009BFDFE /* Selectors */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
62132E571C01F83200084175 /* CSSSelectorTest.h */,
|
||||
62132E581C01F83200084175 /* CSSSelectorTest.m */,
|
||||
621FBE591BDAD68700BC9555 /* CSSSelectorParserTests.m */,
|
||||
628AF62E1BC99A6C00496128 /* CSSNthExpressionsParserTests.m */,
|
||||
624AB3161B0508AE00F3830D /* CSSTypeSelectorTests.m */,
|
||||
624AB3191B050A4D00F3830D /* CSSAttributeSelectorTests.m */,
|
||||
62F6586F1BD83C8E0045F137 /* CSSNThExpressionSelectorTests.m */,
|
||||
621FBE5C1BDAD90200BC9555 /* CSSCombinatorSelectorTests.m */,
|
||||
);
|
||||
name = Selectors;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@@ -522,34 +727,61 @@
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6235CE9B1AA509430026937B /* NSString+HTMLKit.h in Headers */,
|
||||
62F873EB19E088C90062683C /* HTMLParser.h in Headers */,
|
||||
624AC8FF19FBF59800BD3C4A /* HTMLTokens.h in Headers */,
|
||||
623916C31AC707250066B4FE /* HTMLNodeTreeEnumerator.h in Headers */,
|
||||
62AE594419F992F30043F069 /* HTMLCommentToken.h in Headers */,
|
||||
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 */,
|
||||
6279F87419E1808D00F12EE5 /* HTMLElement.h in Headers */,
|
||||
62AE593F19F9907C0043F069 /* HTMLTagToken.h in Headers */,
|
||||
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 */,
|
||||
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 */,
|
||||
629AA0EA1BDD9C2900D5CC98 /* HTMLKit.h in Headers */,
|
||||
626652F91C03D7AC00C3F121 /* HTMLKitErrorDomain.h in Headers */,
|
||||
629AA0EB1BDD9C2900D5CC98 /* HTMLParser.h in Headers */,
|
||||
629AA0EC1BDD9C2900D5CC98 /* HTMLDOM.h in Headers */,
|
||||
629AA0ED1BDD9C2900D5CC98 /* HTMLNode.h in Headers */,
|
||||
629AA0EE1BDD9C2900D5CC98 /* HTMLDocument.h in Headers */,
|
||||
629AA0EF1BDD9C2900D5CC98 /* HTMLDocumentType.h in Headers */,
|
||||
629AA0F01BDD9C2900D5CC98 /* HTMLDocumentFragment.h in Headers */,
|
||||
629AA0F11BDD9C2900D5CC98 /* HTMLElement.h in Headers */,
|
||||
629AA0F21BDD9C2900D5CC98 /* HTMLComment.h in Headers */,
|
||||
629AA0F31BDD9C2900D5CC98 /* HTMLText.h in Headers */,
|
||||
629AA0F41BDD9C2A00D5CC98 /* HTMLTemplate.h in Headers */,
|
||||
629AA0F51BDD9C2A00D5CC98 /* HTMLNodeIterator.h in Headers */,
|
||||
629AA0F61BDD9C2A00D5CC98 /* HTMLTreeWalker.h in Headers */,
|
||||
629AA0F71BDD9C2A00D5CC98 /* HTMLNodeTraversal.h in Headers */,
|
||||
629AA0F81BDD9C2A00D5CC98 /* HTMLNodeFilter.h in Headers */,
|
||||
629AA0F91BDD9C2A00D5CC98 /* HTMLKitDOMExceptions.h in Headers */,
|
||||
629AA0FA1BDD9C2A00D5CC98 /* HTMLNamespaces.h in Headers */,
|
||||
629AA0FB1BDD9C2A00D5CC98 /* HTMLQuirksMode.h in Headers */,
|
||||
629AA0FC1BDD9C2A00D5CC98 /* NSString+HTMLKit.h in Headers */,
|
||||
629AA0FD1BDD9C2A00D5CC98 /* NSCharacterSet+HTMLKit.h in Headers */,
|
||||
629AA0FE1BDD9C2A00D5CC98 /* HTMLOrderedDictionary.h in Headers */,
|
||||
629AA0FF1BDD9C2A00D5CC98 /* CSSSelectors.h in Headers */,
|
||||
629AA1001BDD9C2A00D5CC98 /* CSSSelectorParser.h in Headers */,
|
||||
629AA11F1BDD9C5E00D5CC98 /* CSSNthExpressionParser.h in Headers */,
|
||||
629AA1011BDD9C2A00D5CC98 /* CSSSelector.h in Headers */,
|
||||
629AA1021BDD9C2B00D5CC98 /* CSSSelectorBlock.h in Headers */,
|
||||
629AA1031BDD9C2B00D5CC98 /* CSSTypeSelector.h in Headers */,
|
||||
629AA1041BDD9C2B00D5CC98 /* CSSAttributeSelector.h in Headers */,
|
||||
629AA1051BDD9C2B00D5CC98 /* CSSPseudoClassSelector.h in Headers */,
|
||||
629AA1061BDD9C2B00D5CC98 /* CSSStructuralPseudoSelectors.h in Headers */,
|
||||
629AA1071BDD9C2B00D5CC98 /* CSSNthExpressionSelector.h in Headers */,
|
||||
629AA1081BDD9C2B00D5CC98 /* CSSPseudoFunctionSelector.h in Headers */,
|
||||
629AA1091BDD9C2B00D5CC98 /* CSSCombinatorSelector.h in Headers */,
|
||||
629AA10A1BDD9C2B00D5CC98 /* CSSCompoundSelector.h in Headers */,
|
||||
629AA10B1BDD9C5200D5CC98 /* HTMLTokenizer.h in Headers */,
|
||||
629AA10C1BDD9C5200D5CC98 /* HTMLTokenizerStates.h in Headers */,
|
||||
629AA10D1BDD9C5300D5CC98 /* HTMLTokenizerCharacters.h in Headers */,
|
||||
629AA10E1BDD9C5300D5CC98 /* HTMLTokenizerEntities.h in Headers */,
|
||||
629AA10F1BDD9C5300D5CC98 /* HTMLTokens.h in Headers */,
|
||||
629AA1101BDD9C5300D5CC98 /* HTMLToken.h in Headers */,
|
||||
629AA1111BDD9C5300D5CC98 /* HTMLCharacterToken.h in Headers */,
|
||||
629AA1121BDD9C5300D5CC98 /* HTMLCommentToken.h in Headers */,
|
||||
629AA1131BDD9C5300D5CC98 /* HTMLDOCTYPEToken.h in Headers */,
|
||||
629AA1141BDD9C5400D5CC98 /* HTMLParseErrorToken.h in Headers */,
|
||||
629AA1151BDD9C5400D5CC98 /* HTMLTagToken.h in Headers */,
|
||||
629AA1161BDD9C5400D5CC98 /* HTMLEOFToken.h in Headers */,
|
||||
629AA1171BDD9C5400D5CC98 /* HTMLStackOfOpenElements.h in Headers */,
|
||||
629AA1181BDD9C5400D5CC98 /* HTMLListOfActiveFormattingElements.h in Headers */,
|
||||
629AA1191BDD9C5400D5CC98 /* HTMLElementTypes.h in Headers */,
|
||||
629AA11A1BDD9C5400D5CC98 /* HTMLElementAdjustment.h in Headers */,
|
||||
629AA11B1BDD9C5500D5CC98 /* HTMLParserInsertionModes.h in Headers */,
|
||||
629AA11C1BDD9C5500D5CC98 /* HTMLMarker.h in Headers */,
|
||||
629AA11D1BDD9C5500D5CC98 /* CSSCodePoints.h in Headers */,
|
||||
629AA11E1BDD9C5500D5CC98 /* CSSInputStream.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -633,7 +865,7 @@
|
||||
625A14A319C7829400AD0C32 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0610;
|
||||
LastUpgradeCheck = 0700;
|
||||
ORGANIZATIONNAME = BrainCookie;
|
||||
TargetAttributes = {
|
||||
625A14C219C7829400AD0C32 = {
|
||||
@@ -679,6 +911,7 @@
|
||||
files = (
|
||||
624AC90F19FC702E00BD3C4A /* HTML Standard.html in Resources */,
|
||||
624AC90519FBFE9A00BD3C4A /* html5lib-tests in Resources */,
|
||||
62132E5D1C021FF200084175 /* css-tests in Resources */,
|
||||
625A14CF19C7829400AD0C32 /* InfoPlist.strings in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -687,6 +920,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
62132E5C1C021FF200084175 /* css-tests in Resources */,
|
||||
624AC90619FBFEA000BD3C4A /* html5lib-tests in Resources */,
|
||||
624AC90E19FC702E00BD3C4A /* HTML Standard.html in Resources */,
|
||||
);
|
||||
@@ -699,31 +933,48 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
62F501671BC9576B0069F47B /* CSSNthExpressionParser.m in Sources */,
|
||||
62362A3E1A9FA70400301989 /* HTMLText.m in Sources */,
|
||||
622BF5831BBF2FD700363583 /* CSSSelectorParser.m in Sources */,
|
||||
6235CE9D1AA509430026937B /* NSString+HTMLKit.m in Sources */,
|
||||
6247A9451B152F4F00CCF25C /* HTMLNodeIterator.m in Sources */,
|
||||
6238579D1A9E8934003A45D9 /* HTMLComment.m in Sources */,
|
||||
6234BEF01AABBF1400DEB15F /* HTMLStackOfOpenElements.m in Sources */,
|
||||
624493AE19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */,
|
||||
6235CEA21AA5170A0026937B /* HTMLMarker.m in Sources */,
|
||||
62FA98051BD57B6200A2AF86 /* CSSSelectors.m in Sources */,
|
||||
6234248A1AB467B200726190 /* HTMLOrderedDictionary.m in Sources */,
|
||||
624717BE1B22009200B38302 /* HTMLTreeWalker.m in Sources */,
|
||||
62AE594119F9907C0043F069 /* HTMLTagToken.m in Sources */,
|
||||
624B37201B24E9BA0010BDDF /* CSSInputStream.m in Sources */,
|
||||
62AE594619F992F30043F069 /* HTMLCommentToken.m in Sources */,
|
||||
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 */,
|
||||
62FA04E51BCC360D009ABF98 /* CSSCombinatorSelector.m in Sources */,
|
||||
6238C9871AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */,
|
||||
62FA980A1BD5A7E200A2AF86 /* CSSSelectorBlock.m in Sources */,
|
||||
628AF6401BC9D6FB00496128 /* CSSStructuralPseudoSelectors.m in Sources */,
|
||||
6247171A1B22333200C11912 /* HTMLNodeTraversal.m in Sources */,
|
||||
62F873ED19E088C90062683C /* HTMLParser.m in Sources */,
|
||||
623803A11AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */,
|
||||
624B28C61B04190D0048D328 /* NSCharacterSet+HTMLKit.m in Sources */,
|
||||
6279F87619E1808D00F12EE5 /* HTMLElement.m in Sources */,
|
||||
620C877D1BD44CBE00FB3EEE /* CSSCompoundSelector.m in Sources */,
|
||||
625A150A19C78ABA00AD0C32 /* HTMLInputStreamReader.m in Sources */,
|
||||
628AF6351BC9A63D00496128 /* CSSNthExpressionSelector.m in Sources */,
|
||||
623857931A9E772B003A45D9 /* HTMLDocument.m in Sources */,
|
||||
623406E81ADB05AD004677A3 /* HTMLDocumentFragment.m in Sources */,
|
||||
624717B91B21FE5400B38302 /* HTMLNodeFilter.m in Sources */,
|
||||
620EE94B1BC46F2A0028ED34 /* CSSPseudoClassSelector.m in Sources */,
|
||||
624493A819CCC54100BCDDF4 /* HTMLTokenizer.m in Sources */,
|
||||
625A14BE19C7829400AD0C32 /* HTMLKit.m in Sources */,
|
||||
624B28BA1B03DA820048D328 /* CSSTypeSelector.m in Sources */,
|
||||
62FC60471BD0519B0042BBE7 /* CSSSelector.m in Sources */,
|
||||
623857981A9E8606003A45D9 /* HTMLDocumentType.m in Sources */,
|
||||
620C877F1BD4519A00FB3EEE /* CSSPseudoFunctionSelector.m in Sources */,
|
||||
62AE594B19F9948A0043F069 /* HTMLCharacterToken.m in Sources */,
|
||||
623458501A9D2FA4009BD491 /* HTMLNode.m in Sources */,
|
||||
624B28C11B0413200048D328 /* CSSAttributeSelector.m in Sources */,
|
||||
62F31FDF19E9DCCF007F0657 /* HTMLTokenizerEntities.m in Sources */,
|
||||
62AE593719F97D880043F069 /* HTMLParseErrorToken.m in Sources */,
|
||||
);
|
||||
@@ -733,15 +984,25 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
62132E5A1C01F83200084175 /* CSSSelectorTest.m in Sources */,
|
||||
6239755B1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */,
|
||||
62F658711BD83C8E0045F137 /* CSSNThExpressionSelectorTests.m in Sources */,
|
||||
623CAF9E1AD88BEA00E34C32 /* HTMLKitParserPerformance.m in Sources */,
|
||||
6247171D1B2240B800C11912 /* HTMLTreeWalkerTests.m in Sources */,
|
||||
62EC7AE71AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */,
|
||||
624AB31B1B050A4D00F3830D /* CSSAttributeSelectorTests.m in Sources */,
|
||||
624B9FB61AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m in Sources */,
|
||||
624AB3181B0508AE00F3830D /* CSSTypeSelectorTests.m in Sources */,
|
||||
6236738F1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m in Sources */,
|
||||
624AC90219FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m in Sources */,
|
||||
624B9FB31AE0313300646C4C /* HTMLKitStringCategoryTests.m in Sources */,
|
||||
623916C81AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m in Sources */,
|
||||
623916C81AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m in Sources */,
|
||||
62D8345A19FB1AC4009205A9 /* HTML5LibTokenizerTest.m in Sources */,
|
||||
6239755F1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.m in Sources */,
|
||||
624FC37B1AE591D80015DDF9 /* HTMLKitNodesTests.m in Sources */,
|
||||
621FBE5B1BDAD68700BC9555 /* CSSSelectorParserTests.m in Sources */,
|
||||
621FBE5E1BDAD90200BC9555 /* CSSCombinatorSelectorTests.m in Sources */,
|
||||
628AF6301BC99A6C00496128 /* CSSNthExpressionsParserTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -750,30 +1011,47 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
62362A3D1A9FA70400301989 /* HTMLText.m in Sources */,
|
||||
622BF5821BBF2FD700363583 /* CSSSelectorParser.m in Sources */,
|
||||
6235CE9C1AA509430026937B /* NSString+HTMLKit.m in Sources */,
|
||||
6247A9441B152F4F00CCF25C /* HTMLNodeIterator.m in Sources */,
|
||||
6238579C1A9E8934003A45D9 /* HTMLComment.m in Sources */,
|
||||
6234BEEF1AABBF1400DEB15F /* HTMLStackOfOpenElements.m in Sources */,
|
||||
624493AD19CD0CBE00BCDDF4 /* HTMLToken.m in Sources */,
|
||||
6235CEA11AA5170A0026937B /* HTMLMarker.m in Sources */,
|
||||
623424891AB467B200726190 /* HTMLOrderedDictionary.m in Sources */,
|
||||
62FA98041BD57B6200A2AF86 /* CSSSelectors.m in Sources */,
|
||||
624717BD1B22009200B38302 /* HTMLTreeWalker.m in Sources */,
|
||||
62AE594019F9907C0043F069 /* HTMLTagToken.m in Sources */,
|
||||
62F501661BC9576B0069F47B /* CSSNthExpressionParser.m in Sources */,
|
||||
624B371F1B24E9BA0010BDDF /* CSSInputStream.m in Sources */,
|
||||
62AE594519F992F30043F069 /* HTMLCommentToken.m in Sources */,
|
||||
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 */,
|
||||
62FA04E41BCC360D009ABF98 /* CSSCombinatorSelector.m in Sources */,
|
||||
628AF63F1BC9D6FB00496128 /* CSSStructuralPseudoSelectors.m in Sources */,
|
||||
62FA98091BD5A7E200A2AF86 /* CSSSelectorBlock.m in Sources */,
|
||||
6238C9861AB8D6330006512E /* HTMLKitDOMExceptions.m in Sources */,
|
||||
624717191B22333200C11912 /* HTMLNodeTraversal.m in Sources */,
|
||||
62F873EC19E088C90062683C /* HTMLParser.m in Sources */,
|
||||
623803A01AB63A8C008A53D0 /* HTMLEOFToken.m in Sources */,
|
||||
624B28C51B04190D0048D328 /* NSCharacterSet+HTMLKit.m in Sources */,
|
||||
6279F87519E1808D00F12EE5 /* HTMLElement.m in Sources */,
|
||||
620C877C1BD44CBE00FB3EEE /* CSSCompoundSelector.m in Sources */,
|
||||
625A150919C78ABA00AD0C32 /* HTMLInputStreamReader.m in Sources */,
|
||||
623857921A9E772B003A45D9 /* HTMLDocument.m in Sources */,
|
||||
623406E71ADB05AD004677A3 /* HTMLDocumentFragment.m in Sources */,
|
||||
624717B81B21FE5400B38302 /* HTMLNodeFilter.m in Sources */,
|
||||
620EE94A1BC46F2A0028ED34 /* CSSPseudoClassSelector.m in Sources */,
|
||||
624493A719CCC54100BCDDF4 /* HTMLTokenizer.m in Sources */,
|
||||
625A150219C783DE00AD0C32 /* HTMLKit.m in Sources */,
|
||||
624B28B91B03DA820048D328 /* CSSTypeSelector.m in Sources */,
|
||||
623857971A9E8606003A45D9 /* HTMLDocumentType.m in Sources */,
|
||||
62FC60461BD0519B0042BBE7 /* CSSSelector.m in Sources */,
|
||||
62AE594A19F9948A0043F069 /* HTMLCharacterToken.m in Sources */,
|
||||
620C877E1BD4519A00FB3EEE /* CSSPseudoFunctionSelector.m in Sources */,
|
||||
6234584F1A9D2FA4009BD491 /* HTMLNode.m in Sources */,
|
||||
624B28C01B0413200048D328 /* CSSAttributeSelector.m in Sources */,
|
||||
628AF6341BC9A63D00496128 /* CSSNthExpressionSelector.m in Sources */,
|
||||
62F31FDE19E9DCCF007F0657 /* HTMLTokenizerEntities.m in Sources */,
|
||||
62AE593619F97D880043F069 /* HTMLParseErrorToken.m in Sources */,
|
||||
);
|
||||
@@ -783,15 +1061,25 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
62132E591C01F83200084175 /* CSSSelectorTest.m in Sources */,
|
||||
6239755A1AC362CA007E26F1 /* HTMLKitTreeConstructionTests.m in Sources */,
|
||||
62F658701BD83C8E0045F137 /* CSSNThExpressionSelectorTests.m in Sources */,
|
||||
623CAF9D1AD88BEA00E34C32 /* HTMLKitParserPerformance.m in Sources */,
|
||||
6247171C1B2240B800C11912 /* HTMLTreeWalkerTests.m in Sources */,
|
||||
62EC7AE61AEEAC6F0015D3BE /* HTMLKitMutationAlgorithmsTests.m in Sources */,
|
||||
624AB31A1B050A4D00F3830D /* CSSAttributeSelectorTests.m in Sources */,
|
||||
624B9FB51AE0391400646C4C /* HTMLKitOrderedDictionaryTests.m in Sources */,
|
||||
624AB3171B0508AE00F3830D /* CSSTypeSelectorTests.m in Sources */,
|
||||
6236738E1AC0CE2500FF89B3 /* HTMLKitTokenizerPerformance.m in Sources */,
|
||||
624AC90119FBF9ED00BD3C4A /* HTMLKitTokenizerTests.m in Sources */,
|
||||
624B9FB21AE0313300646C4C /* HTMLKitStringCategoryTests.m in Sources */,
|
||||
623916C71AC7209E0066B4FE /* HTMLKitNodeTreeEnumratorTests.m in Sources */,
|
||||
623916C71AC7209E0066B4FE /* HTMLKitNodeIteratorTests.m in Sources */,
|
||||
62D8345919FB1AC4009205A9 /* HTML5LibTokenizerTest.m in Sources */,
|
||||
6239755E1AC364BB007E26F1 /* HTML5LibTreeConstructionTest.m in Sources */,
|
||||
624FC37A1AE591D80015DDF9 /* HTMLKitNodesTests.m in Sources */,
|
||||
621FBE5A1BDAD68700BC9555 /* CSSSelectorParserTests.m in Sources */,
|
||||
621FBE5D1BDAD90200BC9555 /* CSSCombinatorSelectorTests.m in Sources */,
|
||||
628AF62F1BC99A6C00496128 /* CSSNthExpressionsParserTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -847,6 +1135,7 @@
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
@@ -904,12 +1193,14 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
FRAMEWORK_VERSION = A;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "HTMLKit/HTMLKit-Prefix.pch";
|
||||
INFOPLIST_FILE = "HTMLKit/HTMLKit-Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.braincookie.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = HTMLKit;
|
||||
WRAPPER_EXTENSION = framework;
|
||||
};
|
||||
@@ -919,12 +1210,14 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
FRAMEWORK_VERSION = A;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "HTMLKit/HTMLKit-Prefix.pch";
|
||||
INFOPLIST_FILE = "HTMLKit/HTMLKit-Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.braincookie.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = HTMLKit;
|
||||
WRAPPER_EXTENSION = framework;
|
||||
};
|
||||
@@ -946,6 +1239,7 @@
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = "HTMLKitTests/HTMLKitTests-Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.braincookie.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
@@ -964,6 +1258,7 @@
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "HTMLKit/HTMLKit-Prefix.pch";
|
||||
INFOPLIST_FILE = "HTMLKitTests/HTMLKitTests-Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.braincookie.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
@@ -973,6 +1268,7 @@
|
||||
625A14FD19C7834100AD0C32 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEFINES_MODULE = YES;
|
||||
DSTROOT = /tmp/HTMLKit.dst;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "HTMLKit/HTMLKit-Prefix.pch";
|
||||
@@ -991,6 +1287,7 @@
|
||||
625A14FE19C7834100AD0C32 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEFINES_MODULE = YES;
|
||||
DSTROOT = /tmp/HTMLKit.dst;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "HTMLKit/HTMLKit-Prefix.pch";
|
||||
@@ -1008,7 +1305,6 @@
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
"$(DEVELOPER_FRAMEWORKS_DIR)",
|
||||
);
|
||||
@@ -1020,6 +1316,8 @@
|
||||
);
|
||||
INFOPLIST_FILE = "HTMLKitTests/HTMLKitTests-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
|
||||
OTHER_LDFLAGS = " -ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.braincookie.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
||||
@@ -1032,7 +1330,6 @@
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
"$(DEVELOPER_FRAMEWORKS_DIR)",
|
||||
);
|
||||
@@ -1040,6 +1337,8 @@
|
||||
GCC_PREFIX_HEADER = "HTMLKit/HTMLKit-Prefix.pch";
|
||||
INFOPLIST_FILE = "HTMLKitTests/HTMLKitTests-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
|
||||
OTHER_LDFLAGS = " -ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.braincookie.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:HTMLKit.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// CSSAttributeSelector.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 14/05/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "CSSSelector.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface CSSAttributeSelector : CSSSelector
|
||||
|
||||
@property (nonatomic, assign) CSSAttributeSelectorType type;
|
||||
@property (nonatomic, strong, readonly) NSString *name;
|
||||
@property (nonatomic, strong, readonly) NSString *value;
|
||||
|
||||
+ (instancetype)classSelector:(NSString *)className;
|
||||
+ (instancetype)idSelector:(NSString *)elementId;
|
||||
+ (instancetype)hasAttributeSelector:(NSString *)attributeName;
|
||||
|
||||
- (instancetype)initWithType:(CSSAttributeSelectorType)type
|
||||
attributeName:(NSString *)name
|
||||
attrbiuteValue:(NSString *)value;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// CSSAttributeSelector.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 14/05/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSAttributeSelector.h"
|
||||
#import "HTMLElement.h"
|
||||
#import "NSCharacterSet+HTMLKit.h"
|
||||
|
||||
@interface CSSAttributeSelector ()
|
||||
{
|
||||
CSSAttributeSelectorType _type;
|
||||
NSString *_name;
|
||||
NSString *_value;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CSSAttributeSelector
|
||||
|
||||
+ (instancetype)classSelector:(NSString *)className
|
||||
{
|
||||
return [[self alloc] initWithType:CSSAttributeSelectorIncludes attributeName:@"class" attrbiuteValue:className];
|
||||
}
|
||||
|
||||
+ (instancetype)idSelector:(NSString *)elementId
|
||||
{
|
||||
return [[self alloc] initWithType:CSSAttributeSelectorExactMatch attributeName:@"id" attrbiuteValue:elementId];
|
||||
}
|
||||
|
||||
+ (instancetype)hasAttributeSelector:(NSString *)attributeName
|
||||
{
|
||||
return [[self alloc] initWithType:CSSAttributeSelectorExists attributeName:attributeName attrbiuteValue:@""];
|
||||
}
|
||||
|
||||
- (instancetype)initWithType:(CSSAttributeSelectorType)type
|
||||
attributeName:(NSString *)name
|
||||
attrbiuteValue:(NSString *)value
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.type = type;
|
||||
_name = [name copy];
|
||||
_value = value ? [value copy]: @"";
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
switch (_type) {
|
||||
case CSSAttributeSelectorExists:
|
||||
{
|
||||
return !!element[_name];
|
||||
}
|
||||
case CSSAttributeSelectorExactMatch:
|
||||
{
|
||||
return [element[_name] isEqualToString:_value];
|
||||
}
|
||||
case CSSAttributeSelectorIncludes:
|
||||
{
|
||||
NSArray *components = [element[_name] componentsSeparatedByCharactersInSet:[NSCharacterSet HTMLWhitespaceCharacterSet]];
|
||||
return [components containsObject:_value];
|
||||
}
|
||||
case CSSAttributeSelectorBegins:
|
||||
{
|
||||
return [element[_name] hasPrefix:_value];
|
||||
}
|
||||
case CSSAttributeSelectorEnds:
|
||||
{
|
||||
return [element[_name] hasSuffix:_value];
|
||||
}
|
||||
case CSSAttributeSelectorContains:
|
||||
{
|
||||
return [element[_name] containsString:_value];
|
||||
}
|
||||
case CSSAttributeSelectorHyphen:
|
||||
{
|
||||
return [element[_name] isEqualToString:_value] || [element[_name] hasPrefix:[_value stringByAppendingString:@"-"]];
|
||||
}
|
||||
case CSSAttributeSelectorNot:
|
||||
{
|
||||
return ![element[_name] isEqualToString:_value];
|
||||
}
|
||||
default:
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Description
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
if (self.type == CSSAttributeSelectorExists) {
|
||||
return [NSString stringWithFormat:@"[%@]", self.name];
|
||||
}
|
||||
|
||||
NSString *matcher = @{@(CSSAttributeSelectorExactMatch): @"=",
|
||||
@(CSSAttributeSelectorIncludes): @"~=",
|
||||
@(CSSAttributeSelectorBegins): @"^=",
|
||||
@(CSSAttributeSelectorEnds): @"$=",
|
||||
@(CSSAttributeSelectorContains): @"*=",
|
||||
@(CSSAttributeSelectorHyphen): @"|=",
|
||||
@(CSSAttributeSelectorNot): @"!="}[@(self.type)];
|
||||
|
||||
return [NSString stringWithFormat:@"[%@%@'%@']", self.name, matcher, self.value];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// CSSTokenizer CODEPOINTs.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 08/06/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#define CODEPOINTS \
|
||||
CODEPOINT( CONTROL, 0x0080 ) \
|
||||
CODEPOINT( CHARACTER_TABULATION, 0x0009 ) \
|
||||
CODEPOINT( LINE_FEED, 0x000A ) \
|
||||
CODEPOINT( SPACE, 0x0020 ) \
|
||||
CODEPOINT( QUOTATION_MARK, 0x0022 ) \
|
||||
CODEPOINT( NUMBER_SIGN, 0x0023 ) \
|
||||
CODEPOINT( DOLLAR_SIGN, 0x0024 ) \
|
||||
CODEPOINT( APOSTROPHE, 0x0027 ) \
|
||||
CODEPOINT( LEFT_PARENTHESIS, 0x0028 ) \
|
||||
CODEPOINT( RIGHT_PARENTHESIS, 0x0029 ) \
|
||||
CODEPOINT( ASTERIX, 0x002A ) \
|
||||
CODEPOINT( PLUS_SIGN, 0x002B ) \
|
||||
CODEPOINT( COMMA, 0x002C ) \
|
||||
CODEPOINT( HYPHEN_MINUS, 0x002D ) \
|
||||
CODEPOINT( FULL_STOP, 0x002E ) \
|
||||
CODEPOINT( DIGIT_ZERO, 0x0030 ) \
|
||||
CODEPOINT( DIGIT_NINE, 0x0039 ) \
|
||||
CODEPOINT( COLON, 0x003A ) \
|
||||
CODEPOINT( EQUALS_SIGN, 0x003D ) \
|
||||
CODEPOINT( GREATER_THAN_SIGN, 0x003E ) \
|
||||
CODEPOINT( LATIN_CAPITAL_LETTER_A, 0x0041 ) \
|
||||
CODEPOINT( LATIN_CAPITAL_LETTER_F, 0x0046 ) \
|
||||
CODEPOINT( LATIN_CAPITAL_LETTER_Z, 0x005A ) \
|
||||
CODEPOINT( LEFT_SQUARE_BRACKET, 0x005B ) \
|
||||
CODEPOINT( REVERSE_SOLIDUS, 0x005C ) \
|
||||
CODEPOINT( RIGHT_SQUARE_BRACKET, 0x005D ) \
|
||||
CODEPOINT( CIRCUMFLEX_ACCENT, 0x005E ) \
|
||||
CODEPOINT( LOW_LINE, 0x005F ) \
|
||||
CODEPOINT( LATIN_SMALL_LETTER_A, 0x0061 ) \
|
||||
CODEPOINT( LATIN_SMALL_LETTER_F, 0x0066 ) \
|
||||
CODEPOINT( LATIN_SMALL_LETTER_Z, 0x007A ) \
|
||||
CODEPOINT( VERTICAL_LINE, 0x007C ) \
|
||||
CODEPOINT( TILDE, 0x007E ) \
|
||||
CODEPOINT( REPLACEMENT_CHARACTER, 0xFFFD )
|
||||
|
||||
#define CODEPOINT( name, value ) static UniChar const name = value;
|
||||
CODEPOINTS
|
||||
#undef CODEPOINT
|
||||
|
||||
NS_INLINE BOOL isWhitespace(UTF32Char codePoint)
|
||||
{
|
||||
return (codePoint == CHARACTER_TABULATION ||
|
||||
codePoint == LINE_FEED ||
|
||||
codePoint == SPACE);
|
||||
}
|
||||
|
||||
NS_INLINE BOOL isCombinator(UTF32Char codePoint)
|
||||
{
|
||||
return (codePoint == SPACE ||
|
||||
codePoint == PLUS_SIGN ||
|
||||
codePoint == COMMA ||
|
||||
codePoint == GREATER_THAN_SIGN ||
|
||||
codePoint == TILDE);
|
||||
}
|
||||
|
||||
NS_INLINE BOOL isDigit(UTF32Char codePoint)
|
||||
{
|
||||
return codePoint >= DIGIT_ZERO && codePoint <= DIGIT_NINE;
|
||||
}
|
||||
|
||||
NS_INLINE BOOL isHexDigit(UTF32Char codePoint)
|
||||
{
|
||||
return ((codePoint >= DIGIT_ZERO && codePoint <= DIGIT_NINE) ||
|
||||
(codePoint >= LATIN_CAPITAL_LETTER_A && codePoint <= LATIN_CAPITAL_LETTER_F) ||
|
||||
(codePoint >= LATIN_SMALL_LETTER_A && codePoint <= LATIN_SMALL_LETTER_F));
|
||||
}
|
||||
|
||||
NS_INLINE BOOL isQuote(UTF32Char codePoint)
|
||||
{
|
||||
return codePoint == QUOTATION_MARK || codePoint == APOSTROPHE;
|
||||
}
|
||||
|
||||
NS_INLINE BOOL isNewLine(UTF32Char codePoint)
|
||||
{
|
||||
return codePoint == LINE_FEED;
|
||||
}
|
||||
|
||||
NS_INLINE BOOL isNameStart(UTF32Char codePoint)
|
||||
{
|
||||
return ((codePoint >= LATIN_CAPITAL_LETTER_A && codePoint <= LATIN_CAPITAL_LETTER_Z) ||
|
||||
(codePoint >= LATIN_SMALL_LETTER_A && codePoint <= LATIN_SMALL_LETTER_Z) ||
|
||||
codePoint >= CONTROL ||
|
||||
codePoint == LOW_LINE);
|
||||
}
|
||||
|
||||
NS_INLINE BOOL isName(UTF32Char codePoint)
|
||||
{
|
||||
return isNameStart(codePoint) || isDigit(codePoint) || codePoint == HYPHEN_MINUS;
|
||||
}
|
||||
|
||||
NS_INLINE BOOL isValidEscape(UTF32Char first, UTF32Char second)
|
||||
{
|
||||
if (first != REVERSE_SOLIDUS || isNewLine(second)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
NS_INLINE BOOL isValidEscapedCodePoint(UTF32Char codePoint)
|
||||
{
|
||||
return (codePoint != 0 &&
|
||||
!(codePoint >= 0xD800 && codePoint <= 0x0DFFF) &&
|
||||
codePoint <= 0x10FFFF);
|
||||
}
|
||||
|
||||
NS_INLINE BOOL isValidIdentifierStart(UTF32Char first, UTF32Char second, UTF32Char third)
|
||||
{
|
||||
if (first == HYPHEN_MINUS) {
|
||||
if (isNameStart(second) ||
|
||||
second == HYPHEN_MINUS ||
|
||||
isValidEscape(second, third)) {
|
||||
return YES;
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
} else if (isNameStart(first)) {
|
||||
return YES;
|
||||
} else if (first == REVERSE_SOLIDUS) {
|
||||
return isValidEscape(first, second);
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
NS_INLINE void AppendCodePoint(CFMutableStringRef string, UTF32Char codePoint)
|
||||
{
|
||||
UniChar pair[2];
|
||||
Boolean isPair = CFStringGetSurrogatePairForLongCharacter(codePoint, pair);
|
||||
CFStringAppendCharacters(string, pair, isPair ? 2 : 1);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// CSSCombinatorSelector.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 12/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSSelector.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface CSSCombinatorSelector : CSSSelector
|
||||
|
||||
+ (instancetype)childOfElementCombinator:(CSSSelector *)selector;
|
||||
+ (instancetype)descendantOfElementCombinator:(CSSSelector *)selector;
|
||||
+ (instancetype)adjacentSiblingCombinator:(CSSSelector *)selector;
|
||||
+ (instancetype)generalSiblingCombinator:(CSSSelector *)selector;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// CSSCombinatorSelector.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 12/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSCombinatorSelector.h"
|
||||
#import "HTMLElement.h"
|
||||
|
||||
#pragma mark - Declarations
|
||||
|
||||
@interface CSSChildOfElementCombinatorSelector : CSSCombinatorSelector
|
||||
@end
|
||||
|
||||
@interface CSSDecendantOfElementCombinatorSelector : CSSCombinatorSelector
|
||||
@end
|
||||
|
||||
@interface CSSAdjacentSiblingCombinatorSelector : CSSCombinatorSelector
|
||||
@end
|
||||
|
||||
@interface CSSGeneralSiblingCombinatorSelector : CSSCombinatorSelector
|
||||
@end
|
||||
|
||||
#pragma mark - Base Combinator
|
||||
|
||||
@interface CSSCombinatorSelector ()
|
||||
{
|
||||
CSSSelector *_selector;
|
||||
}
|
||||
@property (nonatomic, strong, readonly) CSSSelector *selector;
|
||||
@end
|
||||
|
||||
@implementation CSSCombinatorSelector
|
||||
@synthesize selector = _selector;
|
||||
|
||||
+ (instancetype)childOfElementCombinator:(CSSSelector *)selector
|
||||
{
|
||||
return [[CSSChildOfElementCombinatorSelector alloc] initWithSelector:selector];
|
||||
}
|
||||
|
||||
+ (instancetype)descendantOfElementCombinator:(CSSSelector *)selector
|
||||
{
|
||||
return [[CSSDecendantOfElementCombinatorSelector alloc] initWithSelector:selector];
|
||||
}
|
||||
|
||||
+ (instancetype)adjacentSiblingCombinator:(CSSSelector *)selector
|
||||
{
|
||||
return [[CSSAdjacentSiblingCombinatorSelector alloc] initWithSelector:selector];
|
||||
}
|
||||
|
||||
+ (instancetype)generalSiblingCombinator:(CSSSelector *)selector
|
||||
{
|
||||
return [[CSSGeneralSiblingCombinatorSelector alloc] initWithSelector:selector];
|
||||
}
|
||||
|
||||
- (instancetype)initWithSelector:(CSSSelector *)selector
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_selector = selector;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Child OfElement Combinator
|
||||
|
||||
@implementation CSSChildOfElementCombinatorSelector
|
||||
|
||||
- (BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
HTMLElement *parent = element.parentElement;
|
||||
return parent != nil && [self.selector acceptElement:parent];
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ > ", self.selector.debugDescription];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Decendant Of Element Combinator
|
||||
|
||||
@implementation CSSDecendantOfElementCombinatorSelector
|
||||
|
||||
- (BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
HTMLElement *parent = element.parentElement;
|
||||
|
||||
while (parent != nil) {
|
||||
if ([self.selector acceptElement:parent]) {
|
||||
return YES;
|
||||
}
|
||||
parent = parent.parentElement;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ ", self.selector.debugDescription];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Adjacent Sibling Combinator
|
||||
|
||||
@implementation CSSAdjacentSiblingCombinatorSelector
|
||||
|
||||
- (BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
HTMLNode *previous = element.previousSiblingElement;
|
||||
if (previous == nil || previous.nodeType != HTMLNodeElement) {
|
||||
return NO;
|
||||
}
|
||||
return [self.selector acceptElement:previous.asElement];
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ + ", self.selector.debugDescription];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - General Sibling Combinator
|
||||
|
||||
@implementation CSSGeneralSiblingCombinatorSelector
|
||||
|
||||
- (BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
HTMLNode *previous = element.previousSiblingElement;
|
||||
|
||||
while (previous != nil && previous.nodeType == HTMLNodeElement) {
|
||||
if ([self.selector acceptElement:previous.asElement]) {
|
||||
return YES;
|
||||
}
|
||||
previous = previous.previousSiblingElement;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ ~ ", self.selector.debugDescription];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// CSSCompoundSelector.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 18/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSSelector.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface CSSCompoundSelector : CSSSelector
|
||||
|
||||
+ (instancetype)andSelector:(NSArray<CSSSelector *> *)selectors;
|
||||
+ (instancetype)orSelector:(NSArray<CSSSelector *> *)selectors;
|
||||
|
||||
- (void)addSelector:(CSSSelector *)selector;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// CSSCompoundSelector.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 18/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSCompoundSelector.h"
|
||||
|
||||
#pragma mark - Declarations
|
||||
|
||||
@interface CSSAndCompoundSelector : CSSCompoundSelector
|
||||
@end
|
||||
|
||||
@interface CSSOrCompoundSelector : CSSCompoundSelector
|
||||
@end
|
||||
|
||||
#pragma mark - Base Combinator
|
||||
|
||||
@interface CSSCompoundSelector ()
|
||||
{
|
||||
NSMutableArray *_selectors;
|
||||
}
|
||||
@property (nonatomic, strong, readonly) NSArray *selectors;
|
||||
@end
|
||||
|
||||
@implementation CSSCompoundSelector
|
||||
@synthesize selectors = _selectors;
|
||||
|
||||
+ (instancetype)andSelector:(NSArray *)selectors
|
||||
{
|
||||
return [[CSSAndCompoundSelector alloc] initWithSelectors:selectors];
|
||||
}
|
||||
|
||||
+ (instancetype)orSelector:(NSArray *)selectors
|
||||
{
|
||||
return [[CSSOrCompoundSelector alloc] initWithSelectors:selectors];
|
||||
}
|
||||
|
||||
- (instancetype)initWithSelectors:(NSArray *)selectors
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_selectors = [[NSMutableArray alloc] initWithArray:selectors];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addSelector:(CSSSelector *)selector
|
||||
{
|
||||
[_selectors addObject:selector];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - And Compound Selector
|
||||
|
||||
@implementation CSSAndCompoundSelector
|
||||
|
||||
- (BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
for (CSSSelector *selector in self.selectors) {
|
||||
if (![selector acceptElement:element]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
NSArray *descriptions = [self.selectors valueForKey:@"debugDescription"];
|
||||
return [descriptions componentsJoinedByString:@""];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Or Compound Selector
|
||||
|
||||
@implementation CSSOrCompoundSelector
|
||||
|
||||
- (BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
for (CSSSelector *selector in self.selectors) {
|
||||
if ([selector acceptElement:element]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
NSArray *descriptions = [self.selectors valueForKey:@"debugDescription"];
|
||||
return [descriptions componentsJoinedByString:@","];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// CSSInputStream.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 07/06/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLInputStreamReader.h"
|
||||
|
||||
@interface CSSInputStream : HTMLInputStreamReader
|
||||
|
||||
- (void)consumeWhitespace;
|
||||
- (NSString *)consumeIdentifier;
|
||||
- (NSString *)consumeStringWithEndingCodePoint:(UTF32Char)endingCodePoint;
|
||||
- (UTF32Char)consumeEscapedCodePoint;
|
||||
- (NSString *)consumeCombinator;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,128 @@
|
||||
//
|
||||
// CSSInputStream.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 07/06/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSInputStream.h"
|
||||
#import "CSSCodePoints.h"
|
||||
|
||||
@interface HTMLInputStreamReader ()
|
||||
- (void)emitParseError:(NSString *)reason;
|
||||
@end
|
||||
|
||||
@implementation CSSInputStream
|
||||
|
||||
- (void)consumeWhitespace
|
||||
{
|
||||
while (isWhitespace(self.nextInputCharacter)) {
|
||||
[self consumeNextInputCharacter];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)consumeIdentifier
|
||||
{
|
||||
CFMutableStringRef value = CFStringCreateMutable(kCFAllocatorDefault, 0);
|
||||
|
||||
if (!isValidIdentifierStart([self inputCharacterPointAtOffset:0],
|
||||
[self inputCharacterPointAtOffset:1],
|
||||
[self inputCharacterPointAtOffset:2])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
while (YES) {
|
||||
UTF32Char codePoint = [self consumeNextInputCharacter];
|
||||
if (codePoint == EOF) {
|
||||
break;
|
||||
} else if (isName(codePoint)) {
|
||||
AppendCodePoint(value, codePoint);
|
||||
} else if (isValidEscape(codePoint, [self inputCharacterPointAtOffset:1])) {
|
||||
UTF32Char escapedCodePoint = [self consumeEscapedCodePoint];
|
||||
AppendCodePoint(value, escapedCodePoint);
|
||||
} else {
|
||||
[self reconsumeCurrentInputCharacter];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (__bridge NSString *)(CFStringGetLength(value) > 0 ? value : nil);
|
||||
}
|
||||
|
||||
- (NSString *)consumeStringWithEndingCodePoint:(UTF32Char)endingCodePoint
|
||||
{
|
||||
CFMutableStringRef value = CFStringCreateMutable(kCFAllocatorDefault, 0);
|
||||
|
||||
while (YES) {
|
||||
UTF32Char codePoint = [self consumeNextInputCharacter];
|
||||
if (codePoint == endingCodePoint) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (codePoint) {
|
||||
case EOF:
|
||||
break;
|
||||
case LINE_FEED:
|
||||
[self emitParseError:@"New-line character (0x000A) in CSS attribute value"];
|
||||
[self reconsumeCurrentInputCharacter];
|
||||
break;
|
||||
case REVERSE_SOLIDUS:
|
||||
{
|
||||
UTF32Char next = self.nextInputCharacter;
|
||||
if (next == EOF) {
|
||||
continue;
|
||||
} else if (next == LINE_FEED) {
|
||||
[self consumeNextInputCharacter];
|
||||
} else {
|
||||
UTF32Char escapedCodePoint = [self consumeNextInputCharacter];
|
||||
AppendCodePoint(value, escapedCodePoint);
|
||||
}
|
||||
}
|
||||
default:
|
||||
AppendCodePoint(value, codePoint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (__bridge NSString *)(CFStringGetLength(value) > 0 ? value : nil);
|
||||
}
|
||||
|
||||
- (UTF32Char)consumeEscapedCodePoint
|
||||
{
|
||||
UTF32Char codePoint = [self consumeNextInputCharacter];
|
||||
|
||||
if (isHexDigit(codePoint)) {
|
||||
CFMutableStringRef hexString = CFStringCreateMutable(kCFAllocatorDefault, 6);
|
||||
AppendCodePoint(hexString, codePoint);
|
||||
|
||||
while (isHexDigit(self.nextInputCharacter) && CFStringGetLength(hexString) <= 6) {
|
||||
UniChar codePoint = [self consumeNextInputCharacter];
|
||||
CFStringAppendCharacters(hexString, &codePoint, 1);
|
||||
}
|
||||
|
||||
if (isWhitespace(self.nextInputCharacter)) {
|
||||
[self consumeNextInputCharacter];
|
||||
}
|
||||
|
||||
NSScanner *scanner = [NSScanner scannerWithString:(__bridge NSString *)(hexString)];
|
||||
UTF32Char number;
|
||||
[scanner scanHexInt:&number];
|
||||
|
||||
return isValidEscapedCodePoint(number) ? number : REPLACEMENT_CHARACTER;
|
||||
} else if (codePoint == EOF) {
|
||||
return REPLACEMENT_CHARACTER;
|
||||
}
|
||||
|
||||
return codePoint;
|
||||
}
|
||||
|
||||
- (NSString *)consumeCombinator
|
||||
{
|
||||
NSString *combinator = [self consumeCharactersInString:@" >+~"];
|
||||
combinator = [combinator stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
|
||||
return combinator;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// CSSNthExpression.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 10/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "CSSSelectors.h"
|
||||
|
||||
@interface CSSNthExpressionParser : NSObject
|
||||
|
||||
+ (CSSNthExpression)parseExpression:(NSString *)expression;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// CSSNthExpression.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 10/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSNthExpressionParser.h"
|
||||
#import "CSSCodePoints.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
#import "NSCharacterSet+HTMLKit.h"
|
||||
|
||||
@implementation CSSNthExpressionParser
|
||||
|
||||
+ (CSSNthExpression)parseExpression:(NSString *)expression
|
||||
{
|
||||
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
||||
|
||||
NSString *string = [expression.lowercaseString copy];
|
||||
string = [[string stringByTrimmingCharactersInSet:whitespace] copy];
|
||||
|
||||
if ([string isEqualToStringIgnoringCase:@"odd"]) {
|
||||
return CSSNthExpressionOdd;
|
||||
} else if ([string isEqualToStringIgnoringCase:@"even"]) {
|
||||
return CSSNthExpressionEven;
|
||||
}
|
||||
|
||||
NSCharacterSet *set = [[NSCharacterSet CSSNthExpressionCharacterSet] invertedSet];
|
||||
if ([string rangeOfCharacterFromSet:set].location != NSNotFound) {
|
||||
return CSSNthExpressionMake(0, 0);
|
||||
}
|
||||
NSArray *parts = [string componentsSeparatedByString:@"n"];
|
||||
|
||||
if (parts.count == 1) {
|
||||
NSInteger b = [parts[0] integerValue];
|
||||
return CSSNthExpressionMake(0, b);
|
||||
} else if (parts.count == 2) {
|
||||
NSInteger a = [parts[0] integerValue];
|
||||
if (a == 0) {
|
||||
a = [parts[0] isEqualToString:@"-"] ? -1 : 1;
|
||||
}
|
||||
NSInteger b = [parts[1] integerValue];
|
||||
return CSSNthExpressionMake(a, b);
|
||||
} else {
|
||||
return CSSNthExpressionMake(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// CSSNthExpressionSelector.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 10/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSSelector.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface CSSNthExpressionSelector : CSSSelector
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *className;
|
||||
@property (nonatomic, assign, readonly) CSSNthExpression expression;
|
||||
|
||||
+ (instancetype)nthChildSelector:(CSSNthExpression)expression;
|
||||
+ (instancetype)nthLastChildSelector:(CSSNthExpression)expression;
|
||||
+ (instancetype)nthOfTypeSelector:(CSSNthExpression)expression;
|
||||
+ (instancetype)nthLastOfTypeSelector:(CSSNthExpression)expression;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,130 @@
|
||||
//
|
||||
// CSSNthExpressionSelector.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 10/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSNthExpressionSelector.h"
|
||||
#import "HTMLElement.h"
|
||||
|
||||
#pragma mark - Nth-Expression
|
||||
|
||||
const CSSNthExpression CSSNthExpressionOdd = (CSSNthExpression) {
|
||||
.an = 2, .b = 1
|
||||
};
|
||||
|
||||
const CSSNthExpression CSSNthExpressionEven = (CSSNthExpression) {
|
||||
.an = 2, .b = 0
|
||||
};
|
||||
|
||||
NSString * _Nonnull NSStringFromNthExpression(CSSNthExpression expression)
|
||||
{
|
||||
if (expression.an == 0 && expression.b == 0) {
|
||||
return @"invalid";
|
||||
}
|
||||
|
||||
if (expression.an == 0) {
|
||||
return [NSString stringWithFormat:@"%ld", expression.b];
|
||||
}
|
||||
if (expression.b == 0) {
|
||||
return [NSString stringWithFormat:@"%ldn", expression.an];
|
||||
}
|
||||
|
||||
return [NSString stringWithFormat:@"%ldn%+ld", expression.an, expression.b];
|
||||
}
|
||||
|
||||
#pragma mark - Implementation
|
||||
|
||||
NSInteger computeIndex(NSEnumerator *enumerator, HTMLElement *element)
|
||||
{
|
||||
NSInteger index = 0;
|
||||
for (HTMLNode *node in enumerator) {
|
||||
if (node.nodeType != HTMLNodeElement) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([node.asElement.tagName isEqualToString:element.tagName]) {
|
||||
index++;
|
||||
}
|
||||
|
||||
if (node == element) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
@interface CSSNthExpressionSelector ()
|
||||
{
|
||||
NSString *_className;
|
||||
CSSNthExpression _expression;
|
||||
NSInteger (^ _computeIndex)(HTMLElement *);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CSSNthExpressionSelector
|
||||
@synthesize expression = _expression;
|
||||
@synthesize className = _className;
|
||||
|
||||
+ (instancetype)nthChildSelector:(CSSNthExpression)expression
|
||||
{
|
||||
return [[self alloc] initWithClassName:@"nth-child" expression:expression block:^NSInteger(HTMLElement *element) {
|
||||
return [element.parentElement indexOfChildElement:element] + 1;
|
||||
}];
|
||||
}
|
||||
|
||||
+ (instancetype)nthLastChildSelector:(CSSNthExpression)expression
|
||||
{
|
||||
return [[self alloc] initWithClassName:@"nth-last-child" expression:expression block:^NSInteger(HTMLElement *element) {
|
||||
return element.parentElement.childElementsCount - [element.parentElement indexOfChildElement:element];
|
||||
}];
|
||||
}
|
||||
|
||||
+ (instancetype)nthOfTypeSelector:(CSSNthExpression)expression
|
||||
{
|
||||
return [[self alloc] initWithClassName:@"nth-of-type" expression:expression block:^NSInteger(HTMLElement *element) {
|
||||
return computeIndex(element.parentElement.childNodes.array.objectEnumerator, element);
|
||||
}];
|
||||
}
|
||||
|
||||
+ (instancetype)nthLastOfTypeSelector:(CSSNthExpression)expression
|
||||
{
|
||||
return [[self alloc] initWithClassName:@"nth-last-of-type" expression:expression block:^NSInteger(HTMLElement *element) {
|
||||
return computeIndex(element.parentElement.childNodes.array.reverseObjectEnumerator, element);
|
||||
}];
|
||||
}
|
||||
|
||||
- (instancetype)initWithClassName:(NSString *)className
|
||||
expression:(CSSNthExpression)expression
|
||||
block:(NSInteger (^)(HTMLElement *element))block
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_className = [className copy];
|
||||
_expression = expression;
|
||||
_computeIndex = [block copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
NSInteger index = _computeIndex(element);
|
||||
|
||||
if (_expression.an == 0) {
|
||||
return index == _expression.b;
|
||||
} else {
|
||||
NSInteger diff = (index - _expression.b);
|
||||
return (diff * _expression.an >= 0) && (diff % _expression.an == 0);
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return [NSString stringWithFormat:@":%@(%@)", self.className, NSStringFromNthExpression(self.expression)];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// CSSPseudoClassSelector.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 06/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSSelector.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface CSSPseudoClassSelector : CSSSelector
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *className;
|
||||
|
||||
- (instancetype)initWithClassName:(NSString *)className selector:(CSSSelector *)selector;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// CSSPseudoClassSelector.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 06/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSPseudoClassSelector.h"
|
||||
|
||||
@interface CSSPseudoClassSelector ()
|
||||
{
|
||||
NSString *_className;
|
||||
CSSSelector *_selector;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CSSPseudoClassSelector
|
||||
@synthesize className = _className;
|
||||
|
||||
- (instancetype)initWithClassName:(NSString *)className selector:(CSSSelector *)selector
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_className = [className copy];
|
||||
_selector = selector;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
return [_selector acceptElement:element];
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return [NSString stringWithFormat:@":%@", self.className];
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: %p '%@'>", self.class, self, self.debugDescription];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// CSSPseudoFunctionSelector.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 07/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSSelector.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface CSSPseudoFunctionSelector : CSSSelector
|
||||
|
||||
+ (instancetype)notSelector:(CSSSelector *)selector;
|
||||
+ (instancetype)hasSelector:(CSSSelector *)selector;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// CSSPseudoFunctionSelector.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 07/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSPseudoFunctionSelector.h"
|
||||
#import "HTMLElement.h"
|
||||
|
||||
#pragma mark - Declarations
|
||||
|
||||
@interface CSSNotSelector : CSSPseudoFunctionSelector
|
||||
@end
|
||||
|
||||
@interface CSSHasSelector : CSSPseudoFunctionSelector
|
||||
@end
|
||||
|
||||
#pragma mark - Base Function Selector
|
||||
|
||||
@interface CSSPseudoFunctionSelector ()
|
||||
{
|
||||
CSSSelector *_selector;
|
||||
}
|
||||
@property (nonatomic, strong, readonly) CSSSelector *selector;
|
||||
@end
|
||||
|
||||
@implementation CSSPseudoFunctionSelector
|
||||
@synthesize selector = _selector;
|
||||
|
||||
+ (instancetype)notSelector:(CSSSelector *)selector
|
||||
{
|
||||
return [[CSSNotSelector alloc] initWithSelector:selector];
|
||||
}
|
||||
|
||||
+ (instancetype)hasSelector:(CSSSelector *)selector
|
||||
{
|
||||
return [[CSSHasSelector alloc] initWithSelector:selector];
|
||||
}
|
||||
|
||||
- (instancetype)initWithSelector:(CSSSelector *)selector
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_selector = selector;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Not Selector
|
||||
|
||||
@implementation CSSNotSelector
|
||||
|
||||
- (BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
return ![self.selector acceptElement:element];
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return [NSString stringWithFormat:@":not(%@)", self.selector.debugDescription];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Has Selector
|
||||
|
||||
@implementation CSSHasSelector
|
||||
|
||||
- (BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
for (HTMLNode *child in element.childNodes) {
|
||||
if (child.nodeType == HTMLNodeElement && [self.selector acceptElement:child.asElement]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return [NSString stringWithFormat:@":has(%@)", self.selector.debugDescription];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// HTMLSelector.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 02/05/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#pragma mark - Attribute Selector Type
|
||||
|
||||
typedef NS_ENUM(NSUInteger, CSSAttributeSelectorType)
|
||||
{
|
||||
CSSAttributeSelectorExists,
|
||||
CSSAttributeSelectorExactMatch,
|
||||
CSSAttributeSelectorIncludes,
|
||||
CSSAttributeSelectorBegins,
|
||||
CSSAttributeSelectorEnds,
|
||||
CSSAttributeSelectorContains,
|
||||
CSSAttributeSelectorHyphen,
|
||||
CSSAttributeSelectorNot
|
||||
};
|
||||
|
||||
#pragma mark - CSS Nth-Expression
|
||||
|
||||
typedef struct CSSNthExpression
|
||||
{
|
||||
NSInteger an;
|
||||
NSInteger b;
|
||||
} CSSNthExpression;
|
||||
|
||||
NS_INLINE CSSNthExpression CSSNthExpressionMake(NSInteger an, NSInteger b) {
|
||||
return (CSSNthExpression){ .an = an, .b = b };
|
||||
}
|
||||
|
||||
extern const CSSNthExpression CSSNthExpressionOdd;
|
||||
extern const CSSNthExpression CSSNthExpressionEven;
|
||||
extern NSString * _Nonnull NSStringFromNthExpression(CSSNthExpression expression);
|
||||
|
||||
#pragma mark - Base Selector Class
|
||||
|
||||
@class HTMLElement;
|
||||
|
||||
@interface CSSSelector : NSObject
|
||||
|
||||
- (BOOL)acceptElement:(nonnull HTMLElement *)element;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// CSSSelector.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 15/10/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "CSSSelector.h"
|
||||
|
||||
@implementation CSSSelector
|
||||
|
||||
- (BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - Description
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: %p '%@'>", self.class, self, self.debugDescription];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// CSSSelectorBlock.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 20/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSSelector.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class HTMLElement;
|
||||
|
||||
@interface CSSSelectorBlock : CSSSelector
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name block:(BOOL (^)(HTMLElement *))block;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// CSSSelectorBlock.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 20/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSSelectorBlock.h"
|
||||
|
||||
@interface CSSSelectorBlock ()
|
||||
{
|
||||
NSString *_name;
|
||||
BOOL (^ _acceptBlock)(HTMLElement *);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CSSSelectorBlock
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name block:(BOOL (^)(HTMLElement *))block
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_name = [name copy];
|
||||
_acceptBlock = [block copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
return _acceptBlock ? _acceptBlock(element) : NO;
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// CSSSelectorParser.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 02/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class CSSSelector;
|
||||
|
||||
@interface CSSSelectorParser : NSObject
|
||||
|
||||
+ (CSSSelector *)parseSelector:(NSString *)string error:(NSError **)error;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,367 @@
|
||||
//
|
||||
// CSSSelectorParser.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 02/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSSelectorParser.h"
|
||||
#import "CSSInputStream.h"
|
||||
#import "CSSCodePoints.h"
|
||||
#import "CSSSelectors.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
#import "NSCharacterSet+HTMLKit.h"
|
||||
#import "CSSNthExpressionParser.h"
|
||||
#import "CSSCompoundSelector.h"
|
||||
#import "HTMLKitErrorDomain.h"
|
||||
|
||||
@interface CSSSelectorParser ()
|
||||
{
|
||||
NSString *_string;
|
||||
CSSInputStream *_inputStream;
|
||||
NSUInteger _location;
|
||||
|
||||
NSMutableArray *_selectors;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CSSSelectorParser
|
||||
|
||||
+ (CSSSelector *)parseSelector:(NSString *)string error:(NSError * __autoreleasing *)error
|
||||
{
|
||||
CSSSelectorParser *parser = [[CSSSelectorParser alloc] initWithString:string];
|
||||
CSSSelector *selector = [parser parse:error];
|
||||
|
||||
return selector;
|
||||
}
|
||||
|
||||
#pragma mark - Init
|
||||
|
||||
- (instancetype)initWithString:(NSString *)string
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_string = [self preprocessInput:string];
|
||||
_location = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)preprocessInput:(NSString *)string
|
||||
{
|
||||
string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"\r\n" withString:@"\n"];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"\r" withString:@"\n"];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"\f" withString:@"\n"];
|
||||
string = [string stringByReplacingOccurrencesOfString:@"\0" withString:@"\uFFFD"];
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
#pragma mark - Errors
|
||||
|
||||
- (void)emitError:(NSError * __autoreleasing *)error reason:(NSString *)reason location:(NSUInteger)location
|
||||
{
|
||||
NSDictionary *userInfo = @{
|
||||
NSLocalizedDescriptionKey: @"Error parsing selector",
|
||||
NSLocalizedFailureReasonErrorKey: reason,
|
||||
CSSSelectorStringKey: _string,
|
||||
CSSSelectorErrorLocationKey: @(location)
|
||||
};
|
||||
|
||||
if(error) {
|
||||
*error = [NSError errorWithDomain:HTMLKitSelectorErrorDomain code:HTMLKitSelectorParseError userInfo:userInfo];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Parsing
|
||||
|
||||
- (CSSSelector *)parse:(NSError * __autoreleasing *)error
|
||||
{
|
||||
if (_string.length == 0) {
|
||||
[self emitError:error reason:@"Empty selector" location:0];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray *allSubSelectors = [_string componentsSeparatedByString:@","];
|
||||
NSMutableArray *parsed = [NSMutableArray array];
|
||||
|
||||
for (NSString *subSelector in allSubSelectors) {
|
||||
if ([subSelector isEqualToString:@""]) {
|
||||
[self emitError:error reason:@"Empty selector" location:_location];
|
||||
break;
|
||||
}
|
||||
|
||||
CSSSelector *selector = [self parseSelector:subSelector error:error];
|
||||
if (selector == nil) {
|
||||
break;
|
||||
}
|
||||
[parsed addObject:selector];
|
||||
|
||||
_location += subSelector.length;
|
||||
}
|
||||
|
||||
if (*error != nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (parsed.count > 1) {
|
||||
return anyOf(parsed);
|
||||
}
|
||||
|
||||
return parsed.firstObject;
|
||||
}
|
||||
|
||||
- (CSSSelector *)parseSelector:(NSString *)selectorString error:(NSError * __autoreleasing *)error
|
||||
{
|
||||
_inputStream = [[CSSInputStream alloc] initWithString:selectorString];
|
||||
[_inputStream consumeWhitespace];
|
||||
|
||||
CSSSelector *result = nil;
|
||||
|
||||
while (YES) {
|
||||
CSSSelector *selector = [self parseSequenceOfSimpleSelectors:error];
|
||||
if (selector == nil) {
|
||||
break;
|
||||
}
|
||||
|
||||
result = result ? allOf(@[result, selector]) : selector;
|
||||
|
||||
UTF32Char next = _inputStream.nextInputCharacter;
|
||||
|
||||
if (isCombinator(next)) {
|
||||
NSString *combinator = [_inputStream consumeCombinator];
|
||||
|
||||
if ([combinator isEqualToString:@""]) {
|
||||
result = descendantOfElementSelector(result);
|
||||
} else if ([combinator isEqualToString:@">"]) {
|
||||
result = childOfElementSelector(result);
|
||||
} else if ([combinator isEqualToString:@"+"]) {
|
||||
result = adjacentSiblingSelector(result);
|
||||
} else if ([combinator isEqualToString:@"~"]) {
|
||||
result = generalSiblingSelector(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (CSSSelector *)parseSequenceOfSimpleSelectors:(NSError * __autoreleasing *)error
|
||||
{
|
||||
NSMutableArray *selectors = [NSMutableArray array];
|
||||
|
||||
CSSSelector *typeSelector = [self parseTypeSelector:error];
|
||||
if (typeSelector != nil) {
|
||||
[selectors addObject:typeSelector];
|
||||
}
|
||||
|
||||
while (YES) {
|
||||
UTF32Char next = _inputStream.nextInputCharacter;
|
||||
if (next == EOF || isCombinator(next)) {
|
||||
break;
|
||||
}
|
||||
|
||||
CSSSelector *simpleSelector = [self parseSimpleSelector:error];
|
||||
if (simpleSelector == nil) {
|
||||
return nil;
|
||||
}
|
||||
[selectors addObject:simpleSelector];
|
||||
}
|
||||
|
||||
if (selectors.count > 1) {
|
||||
return allOf(selectors);
|
||||
}
|
||||
|
||||
return selectors.firstObject;
|
||||
}
|
||||
|
||||
- (CSSSelector *)parseTypeSelector:(NSError * __autoreleasing *)error
|
||||
{
|
||||
NSString *identifier = [_inputStream consumeIdentifier];
|
||||
if (identifier != nil) {
|
||||
return typeSelector(identifier);
|
||||
}
|
||||
|
||||
if ([_inputStream consumeCharacter:ASTERIX]) {
|
||||
return universalSelector();
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CSSSelector *)parseSimpleSelector:(NSError * __autoreleasing *)error
|
||||
{
|
||||
CSSSelector *typeSelector = [self parseTypeSelector:error];
|
||||
if (typeSelector != nil) {
|
||||
return typeSelector;
|
||||
}
|
||||
|
||||
UTF32Char codePoint = [_inputStream consumeNextInputCharacter];
|
||||
switch (codePoint) {
|
||||
case NUMBER_SIGN:
|
||||
{
|
||||
NSString *elementId = [_inputStream consumeIdentifier];
|
||||
if (elementId == nil) {
|
||||
[self emitError:error reason:@"Invalid character" location:_location + _inputStream.currentLocation];
|
||||
return nil;
|
||||
}
|
||||
return idSelector(elementId);
|
||||
}
|
||||
case FULL_STOP:
|
||||
{
|
||||
NSString *className = [_inputStream consumeIdentifier];
|
||||
if (className == nil) {
|
||||
[self emitError:error reason:@"Invalid character" location:_location + _inputStream.currentLocation];
|
||||
return nil;
|
||||
}
|
||||
return classSelector(className);
|
||||
}
|
||||
case LEFT_SQUARE_BRACKET:
|
||||
{
|
||||
return [self parseAttributeSelector:error];
|
||||
}
|
||||
case COLON:
|
||||
{
|
||||
return [self parsePseudoSelector:error];
|
||||
}
|
||||
default:
|
||||
{
|
||||
[self emitError:error reason:@"Invalid character" location:_location + _inputStream.currentLocation];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (CSSSelector *)parseAttributeSelector:(NSError * __autoreleasing *)error
|
||||
{
|
||||
NSString *attribute = [_inputStream consumeIdentifier];
|
||||
if (attribute == nil) {
|
||||
[self emitError:error reason:@"Invalid character" location:_location + _inputStream.currentLocation + 1];
|
||||
return nil;
|
||||
}
|
||||
[_inputStream consumeWhitespace];
|
||||
|
||||
CSSAttributeSelectorType type = CSSAttributeSelectorExists;
|
||||
|
||||
NSString *operator = [_inputStream consumeCharactersInString:@"=~|^$*!"];
|
||||
|
||||
if ([operator isEqualToString:@"="]) {
|
||||
type = CSSAttributeSelectorExactMatch;
|
||||
} else if ([operator isEqualToString:@"~="]) {
|
||||
type = CSSAttributeSelectorIncludes;
|
||||
} else if ([operator isEqualToString:@"|="]) {
|
||||
type = CSSAttributeSelectorHyphen;
|
||||
} else if ([operator isEqualToString:@"^="]) {
|
||||
type = CSSAttributeSelectorBegins;
|
||||
} else if ([operator isEqualToString:@"$="]) {
|
||||
type = CSSAttributeSelectorEnds;
|
||||
} else if ([operator isEqualToString:@"*="]) {
|
||||
type = CSSAttributeSelectorContains;
|
||||
} else if ([operator isEqualToString:@"!="]) {
|
||||
type = CSSAttributeSelectorNot;
|
||||
}
|
||||
|
||||
NSString *value = nil;
|
||||
[_inputStream consumeWhitespace];
|
||||
|
||||
UTF32Char next = _inputStream.nextInputCharacter;
|
||||
if (isQuote(next)) {
|
||||
UTF32Char quote = [_inputStream consumeNextInputCharacter];
|
||||
value = [_inputStream consumeStringWithEndingCodePoint:quote];
|
||||
} else {
|
||||
value = [_inputStream consumeIdentifier];
|
||||
}
|
||||
|
||||
[_inputStream consumeWhitespace];
|
||||
|
||||
// Consume RIGHT_SQUARE_BRACKET
|
||||
if (![_inputStream consumeCharacter:RIGHT_SQUARE_BRACKET]) {
|
||||
[self emitError:error reason:@"Expected closing right square bracket ']'" location:_location + _inputStream.currentLocation];
|
||||
}
|
||||
|
||||
if (type == CSSAttributeSelectorExists) {
|
||||
return hasAttributeSelector(attribute);
|
||||
}
|
||||
|
||||
return attributeSelector(type, attribute, value);
|
||||
}
|
||||
|
||||
- (CSSSelector *)parsePseudoSelector:(NSError * __autoreleasing *)error
|
||||
{
|
||||
NSString *pseudoClass = [_inputStream consumeIdentifier];
|
||||
|
||||
if ([pseudoClass hasPrefix:@"nth"]) {
|
||||
[_inputStream consumeWhitespace];
|
||||
if (![_inputStream consumeCharacter:LEFT_PARENTHESIS]) {
|
||||
[self emitError:error reason:@"Expected opening left parenthesis '('" location:_location + _inputStream.currentLocation];
|
||||
}
|
||||
|
||||
NSString *functionExpression = [_inputStream consumeCharactersUpToString:@")"];
|
||||
CSSNthExpression expression = [CSSNthExpressionParser parseExpression:functionExpression];
|
||||
|
||||
[_inputStream consumeWhitespace];
|
||||
if (![_inputStream consumeCharacter:RIGHT_PARENTHESIS]) {
|
||||
[self emitError:error reason:@"Expected closing right parenthesis ')'" location:_location + _inputStream.currentLocation];
|
||||
}
|
||||
|
||||
if ([pseudoClass isEqualToString:@"nth-child"]) {
|
||||
return nthChildSelector(expression);
|
||||
} else if ([pseudoClass isEqualToString:@"nth-last-child"]) {
|
||||
return nthLastChildSelector(expression);
|
||||
} else if ([pseudoClass isEqualToString:@"nth-of-type"]) {
|
||||
return nthOfTypeSelector(expression);
|
||||
} else if ([pseudoClass isEqualToString:@"nth-last-of-type"]) {
|
||||
return nthLastOfTypeSelector(expression);
|
||||
}
|
||||
} else if ([pseudoClass isEqualToString:@"not"]) {
|
||||
[_inputStream consumeWhitespace];
|
||||
if (![_inputStream consumeCharacter:LEFT_PARENTHESIS]) {
|
||||
[self emitError:error reason:@"Expected opening left parenthesis '('" location:_location + _inputStream.currentLocation];
|
||||
}
|
||||
|
||||
CSSSelector *subSelector = [self parseSimpleSelector:error];
|
||||
[_inputStream consumeWhitespace];
|
||||
if (![_inputStream consumeCharacter:RIGHT_PARENTHESIS]) {
|
||||
[self emitError:error reason:@"Expected closing right parenthesis ')'" location:_location + _inputStream.currentLocation];
|
||||
}
|
||||
|
||||
return nay(subSelector);
|
||||
} else {
|
||||
if ([pseudoClass isEqualToString:@"even"]) {
|
||||
return evenSlector();
|
||||
} else if ([pseudoClass isEqualToString:@"odd"]) {
|
||||
return oddSelector();
|
||||
} else if ([pseudoClass isEqualToString:@"first-child"]) {
|
||||
return firstChildSelector();
|
||||
} else if ([pseudoClass isEqualToString:@"last-child"]) {
|
||||
return lastChildSelector();
|
||||
} else if ([pseudoClass isEqualToString:@"first-of-type"]) {
|
||||
return firstOfTypeSelector();
|
||||
} else if ([pseudoClass isEqualToString:@"last-of-type"]) {
|
||||
return lastOfTypeSelector();
|
||||
} else if ([pseudoClass isEqualToString:@"only-child"]) {
|
||||
return onlyChildSelector();
|
||||
} else if ([pseudoClass isEqualToString:@"only-of-type"]) {
|
||||
return onlyOfTypeSelector();
|
||||
} else if ([pseudoClass isEqualToString:@"root"]) {
|
||||
return rootSelector();
|
||||
} else if ([pseudoClass isEqualToString:@"empty"]) {
|
||||
return emptySelector();
|
||||
} else if ([pseudoClass isEqualToString:@"link"]) {
|
||||
return linkSelector();
|
||||
} else if ([pseudoClass isEqualToString:@"enabled"]) {
|
||||
return enabledSelector();
|
||||
} else if ([pseudoClass isEqualToString:@"disabled"]) {
|
||||
return disabledSelector();
|
||||
} else if ([pseudoClass isEqualToString:@"checked"]) {
|
||||
return checkedSelector();
|
||||
}
|
||||
}
|
||||
NSString *reason = [NSString stringWithFormat:@"Unknown pseudo class: %@", pseudoClass];
|
||||
[self emitError:error reason:reason location:_location + _inputStream.currentLocation];
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// CSSSelectors.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 14/05/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSSelector.h"
|
||||
#import "CSSStructuralPseudoSelectors.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#pragma mark - Type Selectors
|
||||
|
||||
extern CSSSelector * universalSelector();
|
||||
extern CSSSelector * typeSelector(NSString *type);
|
||||
|
||||
#pragma mark - Atribute Selectors
|
||||
|
||||
extern CSSSelector * idSelector(NSString *elementId);
|
||||
extern CSSSelector * classSelector(NSString *className);
|
||||
extern CSSSelector * hasAttributeSelector(NSString *attribute);
|
||||
extern CSSSelector * attributeSelector(CSSAttributeSelectorType type,
|
||||
NSString *attribute,
|
||||
NSString *value);
|
||||
|
||||
#pragma mark - Nth-Expression Selectors
|
||||
|
||||
extern CSSSelector * nthChildSelector(CSSNthExpression expression);
|
||||
extern CSSSelector * nthLastChildSelector(CSSNthExpression expression);
|
||||
extern CSSSelector * nthOfTypeSelector(CSSNthExpression expression);
|
||||
extern CSSSelector * nthLastOfTypeSelector(CSSNthExpression expression);
|
||||
|
||||
extern CSSSelector * oddSelector();
|
||||
extern CSSSelector * evenSlector();
|
||||
|
||||
extern CSSSelector * firstChildSelector();
|
||||
extern CSSSelector * lastChildSelector();
|
||||
extern CSSSelector * firstOfTypeSelector();
|
||||
extern CSSSelector * lastOfTypeSelector();
|
||||
|
||||
extern CSSSelector * onlyChildSelector();
|
||||
extern CSSSelector * onlyOfTypeSelector();
|
||||
|
||||
#pragma mark - Combinators
|
||||
|
||||
extern CSSSelector * childOfElementSelector(CSSSelector *selector);
|
||||
extern CSSSelector * descendantOfElementSelector(CSSSelector *selector);
|
||||
extern CSSSelector * adjacentSiblingSelector(CSSSelector *selector);
|
||||
extern CSSSelector * generalSiblingSelector(CSSSelector *selector);
|
||||
|
||||
#pragma mark - Pseudo Functions
|
||||
|
||||
extern CSSSelector * nay(CSSSelector *selector);
|
||||
extern CSSSelector * has(CSSSelector *selector);
|
||||
|
||||
#pragma mark - Compound Selectors
|
||||
|
||||
extern CSSSelector * allOf(NSArray<CSSSelector *> *selectors);
|
||||
extern CSSSelector * anyOf(NSArray<CSSSelector *> *selectors);
|
||||
|
||||
#pragma mark - Pseudo
|
||||
|
||||
extern CSSSelector * namedPseudoSelector(NSString *name, CSSSelector *selector);
|
||||
|
||||
#pragma mark - Block
|
||||
|
||||
extern CSSSelector * namedBlockSelector(NSString *name, BOOL (^ acceptBlock)(HTMLElement *element));
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,177 @@
|
||||
//
|
||||
// CSSSelectors.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 19/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSSelectors.h"
|
||||
#import "CSSTypeSelector.h"
|
||||
#import "CSSAttributeSelector.h"
|
||||
#import "CSSPseudoClassSelector.h"
|
||||
#import "CSSPseudoFunctionSelector.h"
|
||||
#import "CSSNthExpressionSelector.h"
|
||||
#import "CSSCombinatorSelector.h"
|
||||
#import "CSSCompoundSelector.h"
|
||||
#import "CSSSelectorBlock.h"
|
||||
|
||||
#pragma mark - Type Selectors
|
||||
|
||||
CSSSelector * universalSelector()
|
||||
{
|
||||
return [CSSTypeSelector universalSelector];
|
||||
}
|
||||
|
||||
CSSSelector * typeSelector(NSString *type)
|
||||
{
|
||||
return [[CSSTypeSelector alloc] initWithType:type];
|
||||
}
|
||||
|
||||
#pragma mark - Atribute Selectors
|
||||
|
||||
CSSSelector * idSelector(NSString *elementId)
|
||||
{
|
||||
return [CSSAttributeSelector idSelector:elementId];
|
||||
}
|
||||
|
||||
CSSSelector * classSelector(NSString *className)
|
||||
{
|
||||
return [CSSAttributeSelector classSelector:className];
|
||||
}
|
||||
|
||||
CSSSelector * hasAttributeSelector(NSString *attribute)
|
||||
{
|
||||
return [CSSAttributeSelector hasAttributeSelector:attribute];
|
||||
}
|
||||
|
||||
CSSSelector * attributeSelector(CSSAttributeSelectorType type,
|
||||
NSString *attribute,
|
||||
NSString *value)
|
||||
{
|
||||
return [[CSSAttributeSelector alloc] initWithType:type attributeName:attribute attrbiuteValue:value];
|
||||
}
|
||||
|
||||
#pragma mark - Nth-Expression Selectors
|
||||
|
||||
CSSSelector * nthChildSelector(CSSNthExpression expression)
|
||||
{
|
||||
return [CSSNthExpressionSelector nthChildSelector:expression];
|
||||
}
|
||||
|
||||
CSSSelector * nthLastChildSelector(CSSNthExpression expression)
|
||||
{
|
||||
return [CSSNthExpressionSelector nthLastChildSelector:expression];
|
||||
}
|
||||
|
||||
CSSSelector * nthOfTypeSelector(CSSNthExpression expression)
|
||||
{
|
||||
return [CSSNthExpressionSelector nthOfTypeSelector:expression];
|
||||
}
|
||||
|
||||
CSSSelector * nthLastOfTypeSelector(CSSNthExpression expression)
|
||||
{
|
||||
return [CSSNthExpressionSelector nthLastOfTypeSelector:expression];
|
||||
}
|
||||
|
||||
#pragma mark - Nth-Expression Shorthand
|
||||
|
||||
CSSSelector * oddSelector()
|
||||
{
|
||||
return namedPseudoSelector(@"odd", nthChildSelector(CSSNthExpressionOdd));
|
||||
}
|
||||
|
||||
CSSSelector * evenSlector()
|
||||
{
|
||||
return namedPseudoSelector(@"even", nthChildSelector(CSSNthExpressionEven));
|
||||
}
|
||||
|
||||
CSSSelector * firstChildSelector()
|
||||
{
|
||||
return namedPseudoSelector(@"first-child", nthChildSelector(CSSNthExpressionMake(0, 1)));
|
||||
}
|
||||
|
||||
CSSSelector * lastChildSelector()
|
||||
{
|
||||
return namedPseudoSelector(@"last-child", nthLastChildSelector(CSSNthExpressionMake(0, 1)));
|
||||
}
|
||||
|
||||
CSSSelector * firstOfTypeSelector()
|
||||
{
|
||||
return namedPseudoSelector(@"first-of-type", nthOfTypeSelector(CSSNthExpressionMake(0, 1)));
|
||||
}
|
||||
|
||||
CSSSelector * lastOfTypeSelector()
|
||||
{
|
||||
return namedPseudoSelector(@"last-of-type", nthLastOfTypeSelector(CSSNthExpressionMake(0, 1)));
|
||||
}
|
||||
|
||||
CSSSelector * onlyChildSelector()
|
||||
{
|
||||
return namedPseudoSelector(@"only-child", allOf(@[firstChildSelector(), lastChildSelector()]));
|
||||
}
|
||||
|
||||
CSSSelector * onlyOfTypeSelector()
|
||||
{
|
||||
return namedPseudoSelector(@"only-of-type", allOf(@[firstOfTypeSelector(), lastOfTypeSelector()]));
|
||||
}
|
||||
|
||||
#pragma mark - Combinators
|
||||
|
||||
CSSSelector * childOfElementSelector(CSSSelector *selector)
|
||||
{
|
||||
return [CSSCombinatorSelector childOfElementCombinator:selector];
|
||||
}
|
||||
|
||||
CSSSelector * descendantOfElementSelector(CSSSelector *selector)
|
||||
{
|
||||
return [CSSCombinatorSelector descendantOfElementCombinator:selector];
|
||||
}
|
||||
|
||||
CSSSelector * adjacentSiblingSelector(CSSSelector *selector)
|
||||
{
|
||||
return [CSSCombinatorSelector adjacentSiblingCombinator:selector];
|
||||
}
|
||||
|
||||
CSSSelector * generalSiblingSelector(CSSSelector *selector)
|
||||
{
|
||||
return [CSSCombinatorSelector generalSiblingCombinator:selector];
|
||||
}
|
||||
|
||||
#pragma mark - Pseudo Functions
|
||||
|
||||
CSSSelector * nay(CSSSelector *selector)
|
||||
{
|
||||
return [CSSPseudoFunctionSelector notSelector:selector];
|
||||
}
|
||||
|
||||
CSSSelector * has(CSSSelector *selector)
|
||||
{
|
||||
return [CSSPseudoFunctionSelector hasSelector:selector];
|
||||
}
|
||||
|
||||
#pragma mark - Compound Selectors
|
||||
|
||||
CSSSelector * allOf( NSArray<CSSSelector *> * selectors)
|
||||
{
|
||||
return [CSSCompoundSelector andSelector:selectors];
|
||||
}
|
||||
|
||||
CSSSelector * anyOf( NSArray<CSSSelector *> * selectors)
|
||||
{
|
||||
return [CSSCompoundSelector orSelector:selectors];
|
||||
}
|
||||
|
||||
#pragma mark - Pseudo
|
||||
|
||||
CSSSelector * namedPseudoSelector(NSString *name, CSSSelector *selector)
|
||||
{
|
||||
return [[CSSPseudoClassSelector alloc] initWithClassName:name selector:selector];
|
||||
}
|
||||
|
||||
#pragma mark - Block
|
||||
|
||||
CSSSelector * namedBlockSelector(NSString *name, BOOL (^ acceptBlock)(HTMLElement *element))
|
||||
{
|
||||
return [[CSSSelectorBlock alloc] initWithName:name block:acceptBlock];
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// CSSStructuralPseudoSelector.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 11/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
@class CSSSelector;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern CSSSelector * rootSelector();
|
||||
extern CSSSelector * emptySelector();
|
||||
extern CSSSelector * parentSelector();
|
||||
|
||||
extern CSSSelector * buttonSelector();
|
||||
extern CSSSelector * checkboxSelector();
|
||||
extern CSSSelector * fileSelector();
|
||||
extern CSSSelector * headerSelector();
|
||||
extern CSSSelector * imageSelector();
|
||||
extern CSSSelector * inputSelector();
|
||||
extern CSSSelector * linkSelector();
|
||||
extern CSSSelector * passwordSelector();
|
||||
extern CSSSelector * radioSelector();
|
||||
extern CSSSelector * resetSelector();
|
||||
extern CSSSelector * submitSelector();
|
||||
extern CSSSelector * textSelector();
|
||||
|
||||
extern CSSSelector * enabledSelector();
|
||||
extern CSSSelector * disabledSelector();
|
||||
extern CSSSelector * checkedSelector();
|
||||
extern CSSSelector * optionalSelector();
|
||||
extern CSSSelector * requiredSelector();
|
||||
|
||||
extern CSSSelector * ltSelector();
|
||||
extern CSSSelector * gtSelector();
|
||||
extern CSSSelector * eqSelector();
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,301 @@
|
||||
//
|
||||
// CSSStructuralPseudoSelector.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 11/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSStructuralPseudoSelectors.h"
|
||||
#import "CSSSelectors.h"
|
||||
#import "HTMLElement.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
|
||||
#pragma mark - Elements
|
||||
|
||||
CSSSelector * rootSelector()
|
||||
{
|
||||
return namedBlockSelector(@":root", ^BOOL(HTMLElement * element) {
|
||||
return element.parentElement == nil;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * emptySelector()
|
||||
{
|
||||
return namedBlockSelector(@":empty", ^BOOL(HTMLElement * element) {
|
||||
for (HTMLNode *child in element.childNodes) {
|
||||
if (child.nodeType == HTMLNodeElement) {
|
||||
return NO;
|
||||
} else if (child.nodeType == HTMLNodeText && child.textContent.length > 0) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * parentSelector()
|
||||
{
|
||||
return namedBlockSelector(@":parent", ^BOOL(HTMLElement * element) {
|
||||
return element.childNodesCount > 0;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * buttonSelector()
|
||||
{
|
||||
return namedBlockSelector(@":button", ^BOOL(HTMLElement * _Nonnull element) {
|
||||
if ([element.tagName isEqualToString:@"button"]) {
|
||||
return YES;
|
||||
}
|
||||
if ([element.tagName isEqualToString:@"input"] && [element[@"type"] isEqualToString:@"button"]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * checkboxSelector()
|
||||
{
|
||||
return namedBlockSelector(@":checkbox", ^BOOL(HTMLElement * _Nonnull element) {
|
||||
if ([element[@"type"] isEqualToString:@"checkbox"]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * fileSelector()
|
||||
{
|
||||
return namedBlockSelector(@":file", ^BOOL(HTMLElement * _Nonnull element) {
|
||||
if ([element[@"type"] isEqualToString:@"file"]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * headerSelector()
|
||||
{
|
||||
return namedBlockSelector(@":header", ^BOOL(HTMLElement * _Nonnull element) {
|
||||
if ([element.tagName isEqualToAny:@"h1", @"h2", @"h3", @"h4", @"h5", @"h6", nil]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * imageSelector()
|
||||
{
|
||||
return namedBlockSelector(@":image", ^BOOL(HTMLElement * _Nonnull element) {
|
||||
if ([element[@"type"] isEqualToString:@"image"]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * inputSelector()
|
||||
{
|
||||
return namedBlockSelector(@":input", ^BOOL(HTMLElement * _Nonnull element) {
|
||||
if ([element.tagName isEqualToAny:@"button", @"input", @"select", @"textarea", nil]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * linkSelector()
|
||||
{
|
||||
// https://html.spec.whatwg.org/multipage/scripting.html#selector-link
|
||||
return namedBlockSelector(@":link", ^BOOL(HTMLElement * element) {
|
||||
if ([element hasAttribute:@"href"]) {
|
||||
return [element.tagName isEqualToAny:@"a", @"area", @"link", nil];
|
||||
}
|
||||
return NO;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * passwordSelector()
|
||||
{
|
||||
return namedBlockSelector(@":password", ^BOOL(HTMLElement * _Nonnull element) {
|
||||
if ([element[@"type"] isEqualToString:@"password"]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * radioSelector()
|
||||
{
|
||||
return namedBlockSelector(@":radio", ^BOOL(HTMLElement * _Nonnull element) {
|
||||
if ([element[@"type"] isEqualToString:@"radio"]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * resetSelector()
|
||||
{
|
||||
return namedBlockSelector(@":reset", ^BOOL(HTMLElement * _Nonnull element) {
|
||||
if ([element[@"type"] isEqualToString:@"reset"]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * submitSelector()
|
||||
{
|
||||
return namedBlockSelector(@":submit", ^BOOL(HTMLElement * _Nonnull element) {
|
||||
if ([element.tagName isEqualToString:@"input"] && [element[@"type"] isEqualToString:@"submit"]) {
|
||||
return YES;
|
||||
}
|
||||
if ([element.tagName isEqualToString:@"button"] && [element[@"type"] isEqualToString:@"submit"]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * textSelector()
|
||||
{
|
||||
return namedBlockSelector(@":text", ^BOOL(HTMLElement * _Nonnull element) {
|
||||
if ([element[@"type"] isEqualToString:@"text"]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - State
|
||||
|
||||
CSSSelector * enabledSelector()
|
||||
{
|
||||
// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
|
||||
CSSSelector *candiate = anyOf(@[
|
||||
typeSelector(@"button"),
|
||||
typeSelector(@"input"),
|
||||
typeSelector(@"select"),
|
||||
typeSelector(@"textarea"),
|
||||
typeSelector(@"optgroup"),
|
||||
typeSelector(@"option"),
|
||||
typeSelector(@"menuitem"),
|
||||
typeSelector(@"fieldset"),
|
||||
]);
|
||||
return namedPseudoSelector(@"enabled", allOf(@[candiate, nay(disabledSelector())]));
|
||||
}
|
||||
|
||||
CSSSelector * disabledSelector()
|
||||
{
|
||||
// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
|
||||
CSSSelector *disabledAttribute = hasAttributeSelector(@"disabled");
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/forms.html#concept-fieldset-disabled
|
||||
CSSSelector *disabledFieldset = allOf(@[typeSelector(@"fieldset"), disabledAttribute]);
|
||||
CSSSelector *firstLegend = allOf(@[typeSelector(@"legend"), firstOfTypeSelector()]);
|
||||
CSSSelector *firstLegendDecendantDisabledFieldSet = allOf(@[firstLegend, descendantOfElementSelector(disabledFieldset)]);
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
|
||||
CSSSelector *disabledForm = anyOf(@[
|
||||
anyOf(@[
|
||||
allOf(@[typeSelector(@"button"), disabledAttribute]),
|
||||
allOf(@[typeSelector(@"input"), disabledAttribute]),
|
||||
allOf(@[typeSelector(@"select"), disabledAttribute]),
|
||||
allOf(@[typeSelector(@"textarea"), disabledAttribute])
|
||||
]),
|
||||
allOf(@[
|
||||
descendantOfElementSelector(disabledFieldset),
|
||||
nay(firstLegendDecendantDisabledFieldSet)
|
||||
])
|
||||
]);
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
|
||||
CSSSelector *disabledMenuItem = allOf(@[typeSelector(@"menuitem"), disabledAttribute]);
|
||||
CSSSelector *disabledOptgroup = allOf(@[typeSelector(@"optgroup"), disabledAttribute]);
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
|
||||
CSSSelector *disabledOption = allOf(@[
|
||||
typeSelector(@"option"),
|
||||
anyOf(@[
|
||||
disabledAttribute,
|
||||
descendantOfElementSelector(disabledOptgroup)])
|
||||
]);
|
||||
return namedPseudoSelector(@"disabled",
|
||||
anyOf(@[disabledOption, disabledOptgroup, disabledMenuItem, disabledForm, disabledFieldset]));
|
||||
}
|
||||
|
||||
CSSSelector * checkedSelector()
|
||||
{
|
||||
// https://html.spec.whatwg.org/multipage/scripting.html#selector-checked
|
||||
CSSSelector *candidate = anyOf(@[
|
||||
typeSelector(@"input"),
|
||||
typeSelector(@"option"),
|
||||
typeSelector(@"menutitem")
|
||||
]);
|
||||
CSSSelector *hasAttribute = anyOf(@[
|
||||
hasAttributeSelector(@"checked"),
|
||||
hasAttributeSelector(@"selected")
|
||||
]);
|
||||
|
||||
return namedPseudoSelector(@"checked", allOf(@[candidate, hasAttribute]));
|
||||
}
|
||||
|
||||
CSSSelector * optionalSelector()
|
||||
{
|
||||
// https://html.spec.whatwg.org/multipage/scripting.html#selector-optional
|
||||
CSSSelector *candidate = anyOf(@[
|
||||
typeSelector(@"input"),
|
||||
typeSelector(@"select"),
|
||||
typeSelector(@"textarea")
|
||||
]);
|
||||
CSSSelector *noAttribute = nay(hasAttributeSelector(@"required"));
|
||||
|
||||
return namedPseudoSelector(@"optional", allOf(@[candidate, noAttribute]));
|
||||
}
|
||||
|
||||
CSSSelector * requiredSelector()
|
||||
{
|
||||
// https://html.spec.whatwg.org/multipage/scripting.html#selector-required
|
||||
// https://html.spec.whatwg.org/multipage/forms.html#concept-input-required
|
||||
CSSSelector *candidate = anyOf(@[
|
||||
typeSelector(@"input"),
|
||||
typeSelector(@"select"),
|
||||
typeSelector(@"textarea")
|
||||
]);
|
||||
CSSSelector *hasAttribute = hasAttributeSelector(@"required");
|
||||
|
||||
return namedPseudoSelector(@"required", allOf(@[candidate, hasAttribute]));
|
||||
}
|
||||
|
||||
#pragma mark - Positional
|
||||
|
||||
CSSSelector * ltSelector(NSUInteger index)
|
||||
{
|
||||
NSString *name = [NSString stringWithFormat:@":lt(%lu)", (unsigned long)index];
|
||||
return namedBlockSelector(name, ^BOOL(HTMLElement * _Nonnull element) {
|
||||
return [element.parentElement indexOfChildNode:element] < index;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * gtSelector(NSUInteger index)
|
||||
{
|
||||
NSString *name = [NSString stringWithFormat:@":gt(%lu)", (unsigned long)index];
|
||||
return namedBlockSelector(name, ^BOOL(HTMLElement * _Nonnull element) {
|
||||
return [element.parentElement indexOfChildNode:element] > index;
|
||||
});
|
||||
}
|
||||
|
||||
CSSSelector * eqSelector(NSInteger index)
|
||||
{
|
||||
NSString *name = [NSString stringWithFormat:@":eq(%lu)", (unsigned long)index];
|
||||
return namedBlockSelector(name, ^BOOL(HTMLElement * _Nonnull element) {
|
||||
NSUInteger elementIndex = [element.parentElement indexOfChildNode:element];
|
||||
|
||||
if (index > 0) {
|
||||
return elementIndex == index;
|
||||
} else {
|
||||
return elementIndex == element.parentElement.childNodesCount - index - 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// CSSTypeSelector.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 13/05/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "CSSSelector.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface CSSTypeSelector : CSSSelector
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *type;
|
||||
|
||||
+ (instancetype)universalSelector;
|
||||
|
||||
- (instancetype)initWithType:(NSString *)type;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// CSSTypeSelector.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 13/05/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSTypeSelector.h"
|
||||
#import "HTMLElement.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
|
||||
@interface CSSTypeSelector ()
|
||||
{
|
||||
NSString *_type;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CSSTypeSelector
|
||||
|
||||
+ (instancetype)universalSelector
|
||||
{
|
||||
return [[self alloc] initWithType:@"*"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithType:(NSString *)type
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_type = [type copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)acceptElement:(HTMLElement *)element
|
||||
{
|
||||
if ([_type isEqualToString:@"*"] || [_type isEqualToStringIgnoringCase:element.tagName]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - Description
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return self.type;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -10,6 +10,11 @@
|
||||
|
||||
@implementation HTMLComment
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self initWithData:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSString *)data
|
||||
{
|
||||
self = [super initWithName:@"#comment" type:HTMLNodeComment];
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
#import "HTMLNode.h"
|
||||
#import "HTMLDocument.h"
|
||||
#import "HTMLDocumentType.h"
|
||||
#import "HTMLDocumentFragment.h"
|
||||
#import "HTMLElement.h"
|
||||
#import "HTMLComment.h"
|
||||
#import "HTMLText.h"
|
||||
#import "HTMLTemplate.h"
|
||||
#import "HTMLDocumentFragment.h"
|
||||
#import "HTMLNodeIterator.h"
|
||||
#import "HTMLTreeWalker.h"
|
||||
#import "HTMLNodeFilter.h"
|
||||
@@ -27,6 +27,16 @@ typedef NS_ENUM(short, HTMLDocumentReadyState)
|
||||
|
||||
@property (nonatomic, assign, readonly) HTMLDocumentReadyState readyState;
|
||||
|
||||
@property (nonatomic, strong) HTMLElement *rootElement;
|
||||
|
||||
@property (nonatomic, strong) HTMLElement *documentElement;
|
||||
|
||||
@property (nonatomic, strong) HTMLElement *head;
|
||||
|
||||
@property (nonatomic, strong) HTMLElement *body;
|
||||
|
||||
+ (instancetype)documentWithString:(NSString *)string;
|
||||
|
||||
- (HTMLNode *)adoptNode:(HTMLNode *)node;
|
||||
|
||||
- (HTMLDocument *)associatedInertTemplateDocument;
|
||||
|
||||
+103
-2
@@ -7,16 +7,25 @@
|
||||
//
|
||||
|
||||
#import "HTMLDocument.h"
|
||||
#import "HTMLKitExceptions.h"
|
||||
#import "HTMLParser.h"
|
||||
#import "HTMLNodeIterator.h"
|
||||
#import "HTMLKitDOMExceptions.h"
|
||||
|
||||
@interface HTMLNode (Private)
|
||||
@property (nonatomic, weak) HTMLDocument *ownerDocument;
|
||||
@property (nonatomic, weak) HTMLNode *parentNode;
|
||||
@end
|
||||
|
||||
@interface HTMLNodeIterator (Private)
|
||||
- (void)runRemovingStepsForNode:(HTMLNode *)oldNode
|
||||
withOldParent:(HTMLNode *)oldParent
|
||||
andOldPreviousSibling:(HTMLNode *)oldPreviousSibling;
|
||||
@end
|
||||
|
||||
@interface HTMLDocument ()
|
||||
{
|
||||
HTMLDocument *_inertTemplateDocument;
|
||||
NSMutableArray *_nodeIterators;
|
||||
}
|
||||
@property (nonatomic, assign) HTMLDocumentReadyState readyState;
|
||||
@end
|
||||
@@ -25,11 +34,18 @@
|
||||
|
||||
#pragma mark - Init
|
||||
|
||||
+ (instancetype)documentWithString:(NSString *)string
|
||||
{
|
||||
HTMLParser *parser = [[HTMLParser alloc] initWithString:string];
|
||||
return [parser parseDocument];
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super initWithName:@"#document" type:HTMLNodeDocument];
|
||||
if (self) {
|
||||
_readyState = HTMLDocumentLoading;
|
||||
_nodeIterators = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -57,6 +73,91 @@
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (HTMLElement *)rootElement
|
||||
{
|
||||
for (HTMLNode *node = self.firstChild; node; node = node.nextSibling) {
|
||||
if (node.nodeType == HTMLNodeElement) {
|
||||
return node.asElement;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setRootElement:(HTMLElement *)rootElement
|
||||
{
|
||||
[self replaceChildNode:self.rootElement withNode:rootElement];
|
||||
}
|
||||
|
||||
- (HTMLElement *)documentElement
|
||||
{
|
||||
for (HTMLNode *node in [self nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]) {
|
||||
if ([node.asElement.tagName isEqualToString:@"html"]) {
|
||||
return node.asElement;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setDocumentElement:(HTMLElement *)documentElement
|
||||
{
|
||||
[self replaceChildNode:self.documentElement withNode:documentElement];
|
||||
}
|
||||
|
||||
- (HTMLElement *)head
|
||||
{
|
||||
for (HTMLNode *node in [self nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]) {
|
||||
if ([node.asElement.tagName isEqualToString:@"head"]) {
|
||||
return node.asElement;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setHead:(HTMLElement *)head
|
||||
{
|
||||
[self replaceChildNode:self.head withNode:head];
|
||||
}
|
||||
|
||||
- (HTMLElement *)body
|
||||
{
|
||||
for (HTMLNode *node in [self nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]) {
|
||||
if ([node.asElement.tagName isEqualToString:@"body"]) {
|
||||
return node.asElement;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setBody:(HTMLElement *)body
|
||||
{
|
||||
[self replaceChildNode:self.body withNode:body];
|
||||
}
|
||||
|
||||
#pragma mark - Node Iterators
|
||||
|
||||
- (void)attachNodeIterator:(HTMLNodeIterator *)iterator
|
||||
{
|
||||
[_nodeIterators addObject:iterator];
|
||||
}
|
||||
|
||||
- (void)detachNodeIterator:(HTMLNodeIterator *)iterator
|
||||
{
|
||||
[_nodeIterators removeObject:iterator];
|
||||
}
|
||||
|
||||
- (void)runRemovingStepsForNode:(HTMLNode *)oldNode
|
||||
withOldParent:(HTMLNode *)oldParent
|
||||
andOldPreviousSibling:(HTMLNode *)oldPreviousSibling
|
||||
{
|
||||
for (HTMLNodeIterator *iterator in _nodeIterators) {
|
||||
[iterator runRemovingStepsForNode:oldNode
|
||||
withOldParent:oldParent
|
||||
andOldPreviousSibling:oldPreviousSibling];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Mutation Algorithms
|
||||
|
||||
- (HTMLNode *)adoptNode:(HTMLNode *)node
|
||||
@@ -65,7 +166,7 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (node.type == HTMLNodeDocument) {
|
||||
if (node.nodeType == HTMLNodeDocument) {
|
||||
[NSException raise:HTMLKitNotSupportedError
|
||||
format:@"%@: Not Fount Error, adopting a document node. The operation is not supported.", NSStringFromSelector(_cmd)];
|
||||
}
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
|
||||
@implementation HTMLDocumentFragment
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self initWithDocument:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDocument:(HTMLDocument *)document
|
||||
{
|
||||
self = [super initWithName:@"#document-fragment" type:HTMLNodeDocumentFragment];
|
||||
@@ -27,8 +32,8 @@
|
||||
- (NSString *)textContent
|
||||
{
|
||||
NSMutableString *content = [NSMutableString string];
|
||||
for (HTMLNode *node in self.treeEnumerator) {
|
||||
if (node.type == HTMLNodeText) {
|
||||
for (HTMLNode *node in self.nodeIterator) {
|
||||
if (node.nodeType == HTMLNodeText) {
|
||||
[content appendString:[(HTMLText *)node data]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ NS_INLINE BOOL nilOrEqual(id first, id second) {
|
||||
|
||||
@implementation HTMLDocumentType
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self initWithName:@"html" publicIdentifier:nil systemIdentifier:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name
|
||||
publicIdentifier:(NSString *)publicIdentifier
|
||||
systemIdentifier:(NSString *)systemIdentifier
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
- (instancetype)initWithTagName:(NSString *)tagName;
|
||||
- (instancetype)initWithTagName:(NSString *)tagName attributes:(NSDictionary *)attributes;
|
||||
- (instancetype)initWithTagName:(NSString *)tagName attributes:(NSDictionary *)attributes namespace:(HTMLNamespace)htmlNamespace;
|
||||
- (instancetype)initWithTagName:(NSString *)tagName namespace:(HTMLNamespace)htmlNamespace attributes:(NSDictionary *)attributes;
|
||||
|
||||
- (BOOL)hasAttribute:(NSString *)name;
|
||||
- (NSString *)objectForKeyedSubscript:(NSString *)name;
|
||||
|
||||
+20
-6
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import "HTMLElement.h"
|
||||
#import "HTMLParser.h"
|
||||
#import "HTMLDocument.h"
|
||||
#import "HTMLText.h"
|
||||
|
||||
@@ -35,10 +36,10 @@
|
||||
|
||||
- (instancetype)initWithTagName:(NSString *)tagName attributes:(NSDictionary *)attributes
|
||||
{
|
||||
return [self initWithTagName:tagName attributes:attributes namespace:HTMLNamespaceHTML];
|
||||
return [self initWithTagName:tagName namespace:HTMLNamespaceHTML attributes:attributes];
|
||||
}
|
||||
|
||||
- (instancetype)initWithTagName:(NSString *)tagName attributes:(NSDictionary *)attributes namespace:(HTMLNamespace)htmlNamespace
|
||||
- (instancetype)initWithTagName:(NSString *)tagName namespace:(HTMLNamespace)htmlNamespace attributes:(NSDictionary *)attributes
|
||||
{
|
||||
self = [super initWithName:tagName type:HTMLNodeElement];
|
||||
if (self) {
|
||||
@@ -87,8 +88,8 @@
|
||||
- (NSString *)textContent
|
||||
{
|
||||
NSMutableString *content = [NSMutableString string];
|
||||
for (HTMLNode *node in self.treeEnumerator) {
|
||||
if (node.type == HTMLNodeText) {
|
||||
for (HTMLNode *node in self.nodeIterator) {
|
||||
if (node.nodeType == HTMLNodeText) {
|
||||
[content appendString:[(HTMLText *)node data]];
|
||||
}
|
||||
}
|
||||
@@ -101,6 +102,14 @@
|
||||
[self replaceAllChildNodesWithNode:node];
|
||||
}
|
||||
|
||||
- (void)setInnerHTML:(NSString *)innerHTML
|
||||
{
|
||||
HTMLParser *parser = [[HTMLParser alloc] initWithString:innerHTML];
|
||||
NSArray *fragmentNodes = [parser parseFragmentWithContextElement:self];
|
||||
[self removeAllChildNodes];
|
||||
[self appendNodes:fragmentNodes];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
@@ -137,8 +146,8 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
if ([self.tagName isEqualToAny:@"pre", @"textarea", @"listing", nil] && self.firstChiledNode.type == HTMLNodeText) {
|
||||
HTMLText *textNode = (HTMLText *)self.firstChiledNode;
|
||||
if ([self.tagName isEqualToAny:@"pre", @"textarea", @"listing", nil] && self.firstChild.nodeType == HTMLNodeText) {
|
||||
HTMLText *textNode = (HTMLText *)self.firstChild;
|
||||
if ([textNode.data hasPrefix:@"\n"]) {
|
||||
[result appendString:@"\n"];
|
||||
}
|
||||
@@ -171,4 +180,9 @@
|
||||
return description;
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return self.description;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -24,6 +24,7 @@ typedef void (^ HTMLStreamReaderErrorCallback)(NSString *reason);
|
||||
|
||||
- (UTF32Char)currentInputCharacter;
|
||||
- (UTF32Char)nextInputCharacter;
|
||||
- (UTF32Char)inputCharacterPointAtOffset:(NSUInteger)offset;
|
||||
|
||||
- (UTF32Char)consumeNextInputCharacter;
|
||||
- (void)reconsumeCurrentInputCharacter;
|
||||
@@ -35,6 +36,7 @@ typedef void (^ HTMLStreamReaderErrorCallback)(NSString *reason);
|
||||
- (BOOL)consumeString:(NSString *)string caseSensitive:(BOOL)caseSensitive;
|
||||
- (NSString *)consumeCharactersUpToCharactersInString:(NSString *)characters;
|
||||
- (NSString *)consumeCharactersUpToString:(NSString *)string;
|
||||
- (NSString *)consumeCharactersInString:(NSString *)characters;
|
||||
- (NSString *)consumeAlphanumericCharacters;
|
||||
|
||||
- (void)markCurrentLocation;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import "HTMLInputStreamReader.h"
|
||||
#import "HTMLTokenizerCharacters.h"
|
||||
#import "NSCharacterSet+HTMLKit.h"
|
||||
|
||||
#pragma mark - HTMLInputStreamReader
|
||||
|
||||
@@ -39,6 +40,7 @@
|
||||
if (self) {
|
||||
_string = [string copy];
|
||||
_scanner = [[NSScanner alloc] initWithString:string];
|
||||
_scanner.charactersToBeSkipped = nil;
|
||||
CFStringInitInlineBuffer((CFStringRef)_string, &_buffer, CFRangeMake(0, _string.length));
|
||||
}
|
||||
return self;
|
||||
@@ -63,7 +65,6 @@
|
||||
- (UTF32Char)nextInputCharacter
|
||||
{
|
||||
if (_reconsume) {
|
||||
_reconsume = NO;
|
||||
return _currentInputCharacter;
|
||||
}
|
||||
|
||||
@@ -106,6 +107,11 @@
|
||||
return nextInputCharacter;
|
||||
}
|
||||
|
||||
- (UTF32Char)inputCharacterPointAtOffset:(NSUInteger)offset
|
||||
{
|
||||
return CFStringGetCharacterFromInlineBuffer(&_buffer, _location + offset);
|
||||
}
|
||||
|
||||
- (UTF32Char)consumeNextInputCharacter
|
||||
{
|
||||
if (_reconsume) {
|
||||
@@ -124,9 +130,12 @@
|
||||
{
|
||||
UTF32Char nextInputCharacter = [self nextInputCharacter];
|
||||
if (nextInputCharacter == character) {
|
||||
_location += _consume;
|
||||
_scanner.scanLocation = _location;
|
||||
_currentInputCharacter = nextInputCharacter;
|
||||
if (!_reconsume) {
|
||||
_location += _consume;
|
||||
_scanner.scanLocation = _location;
|
||||
_currentInputCharacter = nextInputCharacter;
|
||||
}
|
||||
_reconsume = NO;
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
@@ -145,7 +154,7 @@
|
||||
|
||||
- (BOOL)consumeHexNumber:(unsigned long long *)result
|
||||
{
|
||||
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"];
|
||||
NSCharacterSet *set = [NSCharacterSet HTMLHexNumberCharacterSet];
|
||||
|
||||
NSString *string = nil;
|
||||
BOOL success = [_scanner scanCharactersFromSet:set intoString:&string];
|
||||
@@ -193,6 +202,26 @@
|
||||
return consumed;
|
||||
}
|
||||
|
||||
- (NSString *)consumeCharactersInString:(NSString *)characters
|
||||
{
|
||||
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:characters];
|
||||
|
||||
if (_reconsume) {
|
||||
_scanner.scanLocation--;
|
||||
}
|
||||
|
||||
NSString *string = nil;
|
||||
BOOL success = [_scanner scanCharactersFromSet:set intoString:&string];
|
||||
if (success == NO) {
|
||||
_scanner.scanLocation++;
|
||||
return nil;
|
||||
}
|
||||
|
||||
_reconsume = NO;
|
||||
_location = _scanner.scanLocation;
|
||||
return string;
|
||||
}
|
||||
|
||||
- (NSString *)consumeAlphanumericCharacters
|
||||
{
|
||||
NSCharacterSet *set = [NSCharacterSet alphanumericCharacterSet];
|
||||
|
||||
+4
-5
@@ -6,8 +6,7 @@
|
||||
// Copyright (c) 2014 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface HTMLKit : NSObject
|
||||
|
||||
@end
|
||||
#import "HTMLParser.h"
|
||||
#import "HTMLDOM.h"
|
||||
#import "CSSSelectors.h"
|
||||
#import "HTMLKitErrorDomain.h"
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
//
|
||||
// HTMLKit.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 15/09/14.
|
||||
// Copyright (c) 2014 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLKit.h"
|
||||
|
||||
@implementation HTMLKit
|
||||
|
||||
@end
|
||||
@@ -6,7 +6,7 @@
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLKitExceptions.h"
|
||||
#import "HTMLKitDOMExceptions.h"
|
||||
|
||||
NSString * const HTMLKitHierarchyRequestError = @"HierarchyRequestError";
|
||||
NSString * const HTMLKitNotFoundError = @"NotFoundError";
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// HTMLKitErrorDomain.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 24/11/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef HTMLKitErrorDomain_h
|
||||
#define HTMLKitErrorDomain_h
|
||||
|
||||
static NSString *const HTMLKitErrorDomain = @"HTMLKit";
|
||||
static NSString *const HTMLKitSelectorErrorDomain = @"HTMLKitSelector";
|
||||
|
||||
static NSString *const CSSSelectorStringKey = @"CSSSelectorString";
|
||||
static NSString *const CSSSelectorErrorLocationKey = @"CSSSelectorErrorLocation";
|
||||
|
||||
NS_ENUM(NSInteger)
|
||||
{
|
||||
HTMLKitSelectorParseError = 4200
|
||||
};
|
||||
|
||||
#endif /* HTMLKitErrorDomain_h */
|
||||
@@ -52,7 +52,7 @@
|
||||
}
|
||||
if (node.htmlNamespace == element.htmlNamespace &&
|
||||
[node.tagName isEqualToString:element.tagName] &&
|
||||
[node.attributes isEqualTo:element.attributes]) {
|
||||
[node.attributes isEqual:element.attributes]) {
|
||||
existing++;
|
||||
}
|
||||
if (existing == 3) {
|
||||
|
||||
+53
-11
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLNodeIterator.h"
|
||||
|
||||
typedef NS_ENUM(short, HTMLNodeType)
|
||||
{
|
||||
@@ -24,37 +25,59 @@ typedef NS_ENUM(short, HTMLNodeType)
|
||||
HTMLNodeNotation = 12 // historical
|
||||
};
|
||||
|
||||
typedef NS_ENUM(unsigned short, HTMLDocumentPosition)
|
||||
{
|
||||
HTMLDocumentPositionEquivalent = 0x0,
|
||||
HTMLDocumentPositionDisconnected = 0x01,
|
||||
HTMLDocumentPositionPreceding = 0x02,
|
||||
HTMLDocumentPositionFollowing = 0x04,
|
||||
HTMLDocumentPositionContains = 0x08,
|
||||
HTMLDocumentPositionContainedBy = 0x10,
|
||||
HTMLDocumentPositionImplementationSpecific = 0x20
|
||||
};
|
||||
|
||||
@class HTMLDocument;
|
||||
@class HTMLElement;
|
||||
@class CSSSelector;
|
||||
|
||||
@interface HTMLNode : NSObject <NSCopying>
|
||||
|
||||
@property (nonatomic, assign, readonly) HTMLNodeType type;
|
||||
@property (nonatomic, assign, readonly) HTMLNodeType nodeType;
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *name;
|
||||
|
||||
@property (nonatomic, weak, readonly) HTMLDocument *ownerDocument;
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *baseURI;
|
||||
|
||||
@property (nonatomic, weak, readonly) HTMLNode *parentNode;
|
||||
|
||||
@property (nonatomic, weak, readonly) HTMLElement *parentElement;
|
||||
|
||||
@property (nonatomic, strong, readonly) NSOrderedSet *childNodes;
|
||||
|
||||
@property (nonatomic, strong, readonly) HTMLNode *firstChiledNode;
|
||||
@property (nonatomic, strong, readonly) HTMLNode *firstChild;
|
||||
|
||||
@property (nonatomic, strong, readonly) HTMLNode *lastChildNode;
|
||||
@property (nonatomic, strong, readonly) HTMLNode *lastChild;
|
||||
|
||||
@property (nonatomic, strong, readonly) HTMLNode *previousSibling;
|
||||
|
||||
@property (nonatomic, strong, readonly) HTMLNode *nextSibling;
|
||||
|
||||
@property (nonatomic, strong, readonly) HTMLElement *previousSiblingElement;
|
||||
|
||||
@property (nonatomic, strong, readonly) HTMLElement *nextSiblingElement;
|
||||
|
||||
@property (nonatomic, copy) NSString *textContent;
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *outerHTML;
|
||||
|
||||
@property (nonatomic, copy) NSString *innerHTML;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name type:(HTMLNodeType)type;
|
||||
|
||||
- (HTMLElement *)asElement;
|
||||
|
||||
- (BOOL)hasChildNodes;
|
||||
|
||||
- (BOOL)hasChildNodeOfType:(HTMLNodeType)type;
|
||||
@@ -65,16 +88,28 @@ typedef NS_ENUM(short, HTMLNodeType)
|
||||
|
||||
- (NSUInteger)indexOfChildNode:(HTMLNode *)node;
|
||||
|
||||
- (HTMLNode *)insertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child;
|
||||
- (NSUInteger)childElementsCount;
|
||||
|
||||
- (HTMLElement *)childElementAtIndex:(NSUInteger)index;
|
||||
|
||||
- (NSUInteger)indexOfChildElement:(HTMLElement *)element;
|
||||
|
||||
- (HTMLNode *)prependNode:(HTMLNode *)node;
|
||||
|
||||
- (void)prependNodes:(NSArray *)nodes;
|
||||
|
||||
- (HTMLNode *)appendNode:(HTMLNode *)node;
|
||||
|
||||
- (void)appendNodes:(NSArray *)nodes;
|
||||
|
||||
- (HTMLNode *)insertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child;
|
||||
|
||||
- (HTMLNode *)replaceChildNode:(HTMLNode *)node withNode:(HTMLNode *)replacement;
|
||||
|
||||
- (void)replaceAllChildNodesWithNode:(HTMLNode *)node;
|
||||
|
||||
- (void)removeFromParentNode;
|
||||
|
||||
- (HTMLNode *)removeChildNode:(HTMLNode *)node;
|
||||
|
||||
- (HTMLNode *)removeChildNodeAtIndex:(NSUInteger)index;
|
||||
@@ -83,15 +118,22 @@ typedef NS_ENUM(short, HTMLNodeType)
|
||||
|
||||
- (void)removeAllChildNodes;
|
||||
|
||||
- (HTMLDocumentPosition)compareDocumentPositionWithNode:(HTMLNode *)node;
|
||||
- (BOOL)isDescendantOfNode:(HTMLNode *)node;
|
||||
- (BOOL)containsNode:(HTMLNode *)node;
|
||||
|
||||
- (void)enumerateChildNodesUsingBlock:(void (^)(HTMLNode *node, NSUInteger idx, BOOL *stop))block;
|
||||
|
||||
- (NSEnumerator *)treeEnumerator;
|
||||
- (void)enumerateChildElementsUsingBlock:(void (^)(HTMLElement *element, NSUInteger idx, BOOL *stop))block;
|
||||
|
||||
- (NSEnumerator *)reverseTreeEnumerator;
|
||||
- (HTMLNodeIterator *)nodeIterator;
|
||||
- (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions
|
||||
filter:(id<HTMLNodeFilter>)filter;
|
||||
- (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions
|
||||
filterBlock:(HTMLNodeFilterValue (^)(HTMLNode *node))filter;
|
||||
|
||||
- (NSString *)outerHTML;
|
||||
|
||||
- (NSString *)innerHTML;
|
||||
- (HTMLElement *)firstElementMatchingSelector:(CSSSelector *)selector;
|
||||
- (NSArray<HTMLElement *> *)elementsMatchingSelector:(CSSSelector *)selector;
|
||||
|
||||
- (NSString *)treeDescription;
|
||||
|
||||
|
||||
+316
-100
@@ -12,8 +12,14 @@
|
||||
#import "HTMLElement.h"
|
||||
#import "HTMLText.h"
|
||||
#import "HTMLComment.h"
|
||||
#import "HTMLKitExceptions.h"
|
||||
#import "HTMLNodeTreeEnumerator.h"
|
||||
#import "HTMLKitDOMExceptions.h"
|
||||
#import "CSSSelector.h"
|
||||
|
||||
@interface HTMLDocument (Private)
|
||||
- (void)runRemovingStepsForNode:(HTMLNode *)oldNode
|
||||
withOldParent:(HTMLNode *)oldParent
|
||||
andOldPreviousSibling:(HTMLNode *)oldPreviousSibling;
|
||||
@end
|
||||
|
||||
@interface HTMLNode ()
|
||||
{
|
||||
@@ -32,7 +38,7 @@
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_name = name;
|
||||
_type = type;
|
||||
_nodeType = type;
|
||||
_childNodes = [NSMutableOrderedSet new];
|
||||
}
|
||||
return self;
|
||||
@@ -42,7 +48,7 @@
|
||||
|
||||
- (HTMLDocument *)ownerDocument
|
||||
{
|
||||
if (_type == HTMLNodeDocument) {
|
||||
if (_nodeType == HTMLNodeDocument) {
|
||||
return (HTMLDocument *)self;
|
||||
} else {
|
||||
return _ownerDocument;
|
||||
@@ -55,12 +61,6 @@
|
||||
[self.childNodes.array makeObjectsPerformSelector:@selector(setOwnerDocument:) withObject:ownerDocument];
|
||||
}
|
||||
|
||||
- (void)setBaseURI:(NSString *)baseURI
|
||||
{
|
||||
_baseURI = [baseURI copy];
|
||||
[self.childNodes.array makeObjectsPerformSelector:@selector(setBaseURI:) withObject:baseURI];
|
||||
}
|
||||
|
||||
- (void)setParentNode:(HTMLNode *)parentNode
|
||||
{
|
||||
_parentNode = parentNode;
|
||||
@@ -68,15 +68,15 @@
|
||||
|
||||
- (HTMLElement *)parentElement
|
||||
{
|
||||
return _parentNode.type == HTMLNodeElement ? (HTMLElement *)_parentNode : nil;
|
||||
return _parentNode.nodeType == HTMLNodeElement ? (HTMLElement *)_parentNode : nil;
|
||||
}
|
||||
|
||||
- (HTMLNode *)firstChiledNode
|
||||
- (HTMLNode *)firstChild
|
||||
{
|
||||
return self.childNodes.firstObject;
|
||||
}
|
||||
|
||||
- (HTMLNode *)lastChildNode
|
||||
- (HTMLNode *)lastChild
|
||||
{
|
||||
return self.childNodes.lastObject;
|
||||
}
|
||||
@@ -99,11 +99,36 @@
|
||||
return [_parentNode childNodeAtIndex:index + 1];
|
||||
}
|
||||
|
||||
- (HTMLElement *)previousSiblingElement
|
||||
{
|
||||
HTMLNode *node = self.previousSibling;
|
||||
while (node && node.nodeType != HTMLNodeElement) {
|
||||
node = node.previousSibling;
|
||||
}
|
||||
return node.asElement;
|
||||
}
|
||||
|
||||
- (HTMLElement *)nextSiblingElement
|
||||
{
|
||||
HTMLNode *node = self.previousSibling;
|
||||
while (node && node.nodeType != HTMLNodeElement) {
|
||||
node = node.nextSibling;
|
||||
}
|
||||
return node.asElement;
|
||||
}
|
||||
|
||||
- (NSString *)textContent
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - Cast
|
||||
|
||||
- (HTMLElement *)asElement
|
||||
{
|
||||
return (HTMLElement *)self;
|
||||
}
|
||||
|
||||
#pragma mark - Child Nodes
|
||||
|
||||
- (BOOL)hasChildNodes
|
||||
@@ -114,7 +139,7 @@
|
||||
- (BOOL)hasChildNodeOfType:(HTMLNodeType)type
|
||||
{
|
||||
NSUInteger index = [self.childNodes indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
|
||||
if ([(HTMLNode *)obj type] == type) {
|
||||
if ([(HTMLNode *)obj nodeType] == type) {
|
||||
*stop = YES;
|
||||
return YES;
|
||||
}
|
||||
@@ -134,40 +159,105 @@
|
||||
return [self.childNodes objectAtIndex:index];
|
||||
}
|
||||
|
||||
- (NSUInteger)childElementsCount
|
||||
{
|
||||
return [self.childNodes indexesOfObjectsPassingTest:^BOOL(HTMLNode * _Nonnull node, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
return node.nodeType == HTMLNodeElement;
|
||||
}].count;
|
||||
}
|
||||
|
||||
- (NSUInteger)indexOfChildNode:(HTMLNode *)node
|
||||
{
|
||||
return [self.childNodes indexOfObject:node];
|
||||
}
|
||||
|
||||
- (HTMLNode *)insertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child
|
||||
- (HTMLElement *)childElementAtIndex:(NSUInteger)index
|
||||
{
|
||||
node = [self preInsertNode:node beforeChildNode:child];
|
||||
node.parentNode = self;
|
||||
return node;
|
||||
NSUInteger counter = 0;
|
||||
for (HTMLNode *node in self.childNodes) {
|
||||
if (node.nodeType == HTMLNodeElement) {
|
||||
if (counter == index) {
|
||||
return node.asElement;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSUInteger)indexOfChildElement:(HTMLElement *)element
|
||||
{
|
||||
NSUInteger counter = 0;
|
||||
for (HTMLNode *node in self.childNodes) {
|
||||
if (node.nodeType == HTMLNodeElement) {
|
||||
if (node == element) {
|
||||
return counter;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
return NSNotFound;
|
||||
}
|
||||
|
||||
- (HTMLNode *)prependNode:(HTMLNode *)node
|
||||
{
|
||||
return [self insertNode:node beforeChildNode:self.firstChild];
|
||||
}
|
||||
|
||||
- (void)prependNodes:(NSArray *)nodes
|
||||
{
|
||||
for (id node in nodes.reverseObjectEnumerator) {
|
||||
[self insertNode:node beforeChildNode:self.firstChild];
|
||||
}
|
||||
}
|
||||
|
||||
- (HTMLNode *)appendNode:(HTMLNode *)node
|
||||
{
|
||||
node = [self preInsertNode:node beforeChildNode:nil];
|
||||
node.parentNode = self;
|
||||
return node;
|
||||
return [self insertNode:node beforeChildNode:nil];
|
||||
}
|
||||
|
||||
- (void)appendNodes:(NSArray *)nodes
|
||||
{
|
||||
for (id node in nodes) {
|
||||
[self appendNode:node];
|
||||
[self insertNode:node beforeChildNode:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (HTMLNode *)insertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child
|
||||
{
|
||||
#ifndef HTMLKIT_NO_DOM_CHECKS
|
||||
[self ensurePreInsertionValidityOfNode:node beforeChildNode:child];
|
||||
#endif
|
||||
|
||||
[self.ownerDocument adoptNode:node];
|
||||
|
||||
NSArray *nodes = node.nodeType == HTMLNodeDocumentFragment ? [NSArray arrayWithArray:node.childNodes.array] : @[node];
|
||||
|
||||
NSUInteger index = [self indexOfChildNode:child];
|
||||
if (index != NSNotFound) {
|
||||
NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, nodes.count)];
|
||||
[(NSMutableOrderedSet *)self.childNodes insertObjects:nodes atIndexes:indexes];
|
||||
} else {
|
||||
[(NSMutableOrderedSet *)self.childNodes addObjectsFromArray:nodes];
|
||||
}
|
||||
|
||||
if (node.nodeType == HTMLNodeDocumentFragment) {
|
||||
[node removeAllChildNodes];
|
||||
}
|
||||
|
||||
[nodes makeObjectsPerformSelector:@selector(setParentNode:) withObject:self];
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
- (HTMLNode *)replaceChildNode:(HTMLNode *)child withNode:(HTMLNode *)node
|
||||
{
|
||||
#ifndef HTMLKIT_NO_DOM_CHECKS
|
||||
[self ensureReplacementValidityOfChildNode:child withNode:node];
|
||||
#endif
|
||||
|
||||
[self.ownerDocument adoptNode:node];
|
||||
NSUInteger index = [self indexOfChildNode:child];
|
||||
node.parentNode = self;
|
||||
[(NSMutableOrderedSet *)self.childNodes replaceObjectAtIndex:index withObject:node];
|
||||
[self insertNode:node beforeChildNode:child];
|
||||
[child removeFromParentNode];
|
||||
return child;
|
||||
}
|
||||
|
||||
@@ -181,6 +271,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeFromParentNode
|
||||
{
|
||||
[self.parentNode removeChildNode:self];
|
||||
}
|
||||
|
||||
- (HTMLNode *)removeChildNode:(HTMLNode *)child
|
||||
{
|
||||
if (child.parentNode != self) {
|
||||
@@ -189,8 +284,16 @@
|
||||
NSStringFromSelector(_cmd), child];
|
||||
}
|
||||
|
||||
HTMLNode *oldNode = child;
|
||||
HTMLNode *oldParent = child.parentNode;
|
||||
HTMLNode *oldPreviousSibling = child.previousSibling;
|
||||
|
||||
[(NSMutableOrderedSet *)self.childNodes removeObject:child];
|
||||
child.parentNode = nil;
|
||||
|
||||
[self.ownerDocument runRemovingStepsForNode:oldNode
|
||||
withOldParent:oldParent
|
||||
andOldPreviousSibling:oldPreviousSibling];
|
||||
return child;
|
||||
}
|
||||
|
||||
@@ -205,14 +308,95 @@
|
||||
for (HTMLNode *child in self.childNodes.array) {
|
||||
[node appendNode:child];
|
||||
}
|
||||
[self removeAllChildNodes];
|
||||
[(NSMutableOrderedSet *)self.childNodes removeAllObjects];
|
||||
}
|
||||
|
||||
- (void)removeAllChildNodes
|
||||
{
|
||||
[self.childNodes.array makeObjectsPerformSelector:@selector(setParentNode:) withObject:nil];
|
||||
[(NSMutableOrderedSet *)self.childNodes removeAllObjects];
|
||||
}
|
||||
|
||||
- (HTMLDocumentPosition)compareDocumentPositionWithNode:(HTMLNode *)otherNode
|
||||
{
|
||||
if (otherNode == nil) {
|
||||
return HTMLDocumentPositionDisconnected;
|
||||
}
|
||||
|
||||
if (self == otherNode) {
|
||||
return HTMLDocumentPositionEquivalent;
|
||||
}
|
||||
|
||||
NSArray * (^ ancestorNodes) (HTMLNode *) = ^ NSArray * (HTMLNode *node) {
|
||||
NSMutableArray *ancestors = [NSMutableArray array];
|
||||
for (HTMLNode *node = self; node; node = node.parentNode) {
|
||||
[ancestors addObject:node];
|
||||
}
|
||||
return ancestors;
|
||||
};
|
||||
|
||||
NSArray *ancestors1 = ancestorNodes(self);
|
||||
NSArray *ancestors2 = ancestorNodes(otherNode);
|
||||
|
||||
if (ancestors1.lastObject != ancestors2.lastObject) {
|
||||
return HTMLDocumentPositionDisconnected |
|
||||
HTMLDocumentPositionImplementationSpecific |
|
||||
HTMLDocumentPositionFollowing;
|
||||
}
|
||||
|
||||
for (NSUInteger i = MIN(ancestors1.count - 1, ancestors2.count - 1); i; --i) {
|
||||
HTMLNode *child1 = ancestors1[i];
|
||||
HTMLNode *child2 = ancestors2[i];
|
||||
|
||||
if (child1 != child2) {
|
||||
for (HTMLNode *sibling = child1.nextSibling; sibling; sibling = sibling.nextSibling) {
|
||||
if (sibling == child2) {
|
||||
return HTMLDocumentPositionFollowing;
|
||||
}
|
||||
}
|
||||
return HTMLDocumentPositionPreceding;
|
||||
}
|
||||
}
|
||||
|
||||
if (ancestors1.count < ancestors2.count) {
|
||||
return HTMLDocumentPositionContainedBy | HTMLDocumentPositionFollowing;
|
||||
} else {
|
||||
return HTMLDocumentPositionContains | HTMLDocumentPositionPreceding;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isDescendantOfNode:(HTMLNode *)otherNode
|
||||
{
|
||||
if (otherNode == nil) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (self.ownerDocument != otherNode.ownerDocument) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (!otherNode.hasChildNodes) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (otherNode.nodeType == HTMLNodeDocument) {
|
||||
return self.nodeType != HTMLNodeDocument && self.ownerDocument == otherNode;
|
||||
}
|
||||
|
||||
for (HTMLNode *parentNode = self.parentNode; parentNode; parentNode = parentNode.parentNode) {
|
||||
if (parentNode == otherNode) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)containsNode:(HTMLNode *)otherNode
|
||||
{
|
||||
return self == otherNode || [otherNode isDescendantOfNode:self];
|
||||
}
|
||||
|
||||
#pragma mark - Enumeration
|
||||
|
||||
- (void)enumerateChildNodesUsingBlock:(void (^)(HTMLNode *node, NSUInteger idx, BOOL *stop))block
|
||||
@@ -226,40 +410,71 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSEnumerator *)treeEnumerator
|
||||
- (void)enumerateChildElementsUsingBlock:(void (^)(HTMLElement *element, NSUInteger idx, BOOL *stop))block
|
||||
{
|
||||
return [[HTMLNodeTreeEnumerator alloc] initWithNode:self reverse:NO];
|
||||
}
|
||||
|
||||
- (NSEnumerator *)reverseTreeEnumerator
|
||||
{
|
||||
return [[HTMLNodeTreeEnumerator alloc] initWithNode:self reverse:YES];
|
||||
}
|
||||
|
||||
#pragma mark - Mutation Algorithms
|
||||
|
||||
- (HTMLNode *)preInsertNode:(HTMLNode *)node beforeChildNode:(HTMLNode *)child
|
||||
{
|
||||
[self ensurePreInsertionValidityOfNode:node beforeChildNode:child];
|
||||
[self.ownerDocument adoptNode:node];
|
||||
NSUInteger index = [self indexOfChildNode:child];
|
||||
if (index != NSNotFound) {
|
||||
[(NSMutableOrderedSet *)self.childNodes insertObject:node atIndex:index];
|
||||
} else {
|
||||
[(NSMutableOrderedSet *)self.childNodes addObject:node];
|
||||
if (block == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
return node;
|
||||
[self.childNodes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
|
||||
if ([obj isKindOfClass:[HTMLElement class]]) {
|
||||
block([obj asElement], idx, stop);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
NS_INLINE void CheckParentValid(HTMLNode *node, NSString *cmd)
|
||||
- (HTMLNodeIterator *)nodeIterator
|
||||
{
|
||||
if (node.type != HTMLNodeDocument &&
|
||||
node.type != HTMLNodeDocumentFragment &&
|
||||
node.type != HTMLNodeElement) {
|
||||
return [self nodeIteratorWithShowOptions:HTMLNodeFilterShowAll filter:nil];
|
||||
}
|
||||
|
||||
- (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions
|
||||
filter:(id<HTMLNodeFilter>)filter
|
||||
{
|
||||
return [[HTMLNodeIterator alloc] initWithNode:self showOptions:showOptions filter:filter];
|
||||
}
|
||||
|
||||
- (HTMLNodeIterator *)nodeIteratorWithShowOptions:(HTMLNodeFilterShowOptions)showOptions
|
||||
filterBlock:(HTMLNodeFilterValue (^)(HTMLNode *node))filter
|
||||
{
|
||||
return [HTMLNodeIterator iteratorWithNode:self showOptions:showOptions filter:filter];
|
||||
}
|
||||
|
||||
#pragma mark - Selectors
|
||||
|
||||
- (HTMLElement *)firstElementMatchingSelector:(CSSSelector *)selector
|
||||
{
|
||||
for (HTMLElement *element in [self nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]) {
|
||||
if ([selector acceptElement:element]) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSArray<HTMLElement *> *)elementsMatchingSelector:(CSSSelector *)selector
|
||||
{
|
||||
NSMutableArray *result = [NSMutableArray array];
|
||||
for (HTMLElement *element in [self nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]) {
|
||||
if ([selector acceptElement:element]) {
|
||||
[result addObject:element];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef HTMLKIT_NO_DOM_CHECKS
|
||||
|
||||
#pragma mark - Validity Checks
|
||||
|
||||
NS_INLINE void CheckParentValid(HTMLNode *parent, NSString *cmd)
|
||||
{
|
||||
if (parent.nodeType != HTMLNodeDocument &&
|
||||
parent.nodeType != HTMLNodeDocumentFragment &&
|
||||
parent.nodeType != HTMLNodeElement) {
|
||||
[NSException raise:HTMLKitHierarchyRequestError
|
||||
format:@"%@: Hierarchy Request Error, inserting into %@ is not allowed. The operation would yield an incorrect node tree.",
|
||||
cmd, node.name];
|
||||
cmd, parent.name];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,11 +490,11 @@ NS_INLINE void CheckChildsParent(HTMLNode *parent, HTMLNode *child, NSString *cm
|
||||
|
||||
NS_INLINE void CheckInsertedNodeValid(HTMLNode *node, NSString *cmd)
|
||||
{
|
||||
if (node.type != HTMLNodeDocumentFragment &&
|
||||
node.type != HTMLNodeDocumentType &&
|
||||
node.type != HTMLNodeElement &&
|
||||
node.type != HTMLNodeText &&
|
||||
node.type != HTMLNodeComment) {
|
||||
if (node.nodeType != HTMLNodeDocumentFragment &&
|
||||
node.nodeType != HTMLNodeDocumentType &&
|
||||
node.nodeType != HTMLNodeElement &&
|
||||
node.nodeType != HTMLNodeText &&
|
||||
node.nodeType != HTMLNodeComment) {
|
||||
[NSException raise:HTMLKitHierarchyRequestError
|
||||
format:@"%@: Hierarchy Request Error, inserting a %@ is not allowed. The operation would yield an incorrect node tree.",
|
||||
cmd, node.name];
|
||||
@@ -288,13 +503,13 @@ NS_INLINE void CheckInsertedNodeValid(HTMLNode *node, NSString *cmd)
|
||||
|
||||
NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSString *cmd)
|
||||
{
|
||||
if (node.type == HTMLNodeText && parent.type == HTMLNodeDocument) {
|
||||
if (node.nodeType == HTMLNodeText && parent.nodeType == HTMLNodeDocument) {
|
||||
[NSException raise:HTMLKitHierarchyRequestError
|
||||
format:@"%@: Hierarchy Request Error, inserting a text node %@ into docuement is not allowed. The operation would yield an incorrect node tree.",
|
||||
cmd, parent.name];
|
||||
}
|
||||
|
||||
if (node.type == HTMLNodeDocumentType && parent.type != HTMLNodeDocument) {
|
||||
if (node.nodeType == HTMLNodeDocumentType && parent.nodeType != HTMLNodeDocument) {
|
||||
[NSException raise:HTMLKitHierarchyRequestError
|
||||
format:@"%@: Hierarchy Request Error, inserting a doctype %@ into a non-document node is not allowed. The operation would yield an incorrect node tree.",
|
||||
cmd, parent.name];
|
||||
@@ -313,28 +528,28 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin
|
||||
|
||||
void (^ hierarchyError)() = ^{
|
||||
[NSException raise:HTMLKitHierarchyRequestError
|
||||
format:@"%@: Hierarchy Request Error. The operation would yield an incorrect node tree.",
|
||||
NSStringFromSelector(_cmd)];
|
||||
format:@"%@: Hierarchy Request Error, inserting (%@) into (%@). The operation would yield an incorrect node tree.",
|
||||
NSStringFromSelector(_cmd), self, node];
|
||||
};
|
||||
|
||||
if (self.type == HTMLNodeDocument) {
|
||||
switch (node.type) {
|
||||
if (self.nodeType == HTMLNodeDocument) {
|
||||
switch (node.nodeType) {
|
||||
case HTMLNodeDocumentFragment:
|
||||
if (self.childNodesCount > 1 ||
|
||||
[self hasChildNodeOfType:HTMLNodeText]) {
|
||||
if (node.childNodesCount > 1 ||
|
||||
[node hasChildNodeOfType:HTMLNodeText]) {
|
||||
hierarchyError();
|
||||
} else if (self.childNodesCount == 1) {
|
||||
if (self.hasChildNodes ||
|
||||
child.type == HTMLNodeDocumentType ||
|
||||
child.nextSibling.type == HTMLNodeDocumentType) {
|
||||
} else if (node.childNodesCount == 1) {
|
||||
if ([self hasChildNodeOfType:HTMLNodeElement] ||
|
||||
child.nodeType == HTMLNodeDocumentType ||
|
||||
child.nextSibling.nodeType == HTMLNodeDocumentType) {
|
||||
hierarchyError();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HTMLNodeElement:
|
||||
if ([self hasChildNodeOfType:HTMLNodeElement] ||
|
||||
child.type == HTMLNodeDocumentType ||
|
||||
(child != nil && child.nextSibling.type == HTMLNodeDocumentType)) {
|
||||
child.nodeType == HTMLNodeDocumentType ||
|
||||
(child != nil && child.nextSibling.nodeType == HTMLNodeDocumentType)) {
|
||||
hierarchyError();
|
||||
}
|
||||
break;
|
||||
@@ -367,43 +582,42 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin
|
||||
NSStringFromSelector(_cmd)];
|
||||
};
|
||||
|
||||
if (self.type == HTMLNodeDocument) {
|
||||
switch (node.type) {
|
||||
void (^ checkParentHasAnotherChildOfType)(HTMLNodeType) = ^ void (HTMLNodeType type) {
|
||||
[self enumerateChildNodesUsingBlock:^(HTMLNode *node, NSUInteger idx, BOOL *stop) {
|
||||
if (node.nodeType == type && node != child) {
|
||||
*stop = YES;
|
||||
hierarchyError();
|
||||
}
|
||||
}];
|
||||
};
|
||||
|
||||
if (self.nodeType == HTMLNodeDocument) {
|
||||
switch (node.nodeType) {
|
||||
case HTMLNodeDocumentFragment:
|
||||
if (self.childNodesCount > 1 ||
|
||||
[self hasChildNodeOfType:HTMLNodeText]) {
|
||||
if (node.childNodesCount > 1 ||
|
||||
[node hasChildNodeOfType:HTMLNodeText]) {
|
||||
hierarchyError();
|
||||
} else if (self.childNodesCount == 1) {
|
||||
if (self.firstChiledNode != node ||
|
||||
child.nextSibling.type == HTMLNodeDocumentType) {
|
||||
} else if (node.childNodesCount == 1) {
|
||||
if (child.nextSibling.nodeType == HTMLNodeDocumentType) {
|
||||
hierarchyError();
|
||||
}
|
||||
checkParentHasAnotherChildOfType(HTMLNodeElement);
|
||||
}
|
||||
break;
|
||||
case HTMLNodeElement:
|
||||
{
|
||||
if (child.nextSibling.type == HTMLNodeDocumentType) {
|
||||
if (child.nextSibling.nodeType == HTMLNodeDocumentType) {
|
||||
hierarchyError();
|
||||
}
|
||||
[self enumerateChildNodesUsingBlock:^(HTMLNode *node, NSUInteger idx, BOOL *stop) {
|
||||
if (node.type == HTMLNodeElement && node != child) {
|
||||
*stop = YES;
|
||||
hierarchyError();
|
||||
}
|
||||
}];
|
||||
checkParentHasAnotherChildOfType(HTMLNodeElement);
|
||||
break;
|
||||
}
|
||||
case HTMLNodeDocumentType:
|
||||
{
|
||||
if (child.previousSibling.type == HTMLNodeElement) {
|
||||
if (child.previousSibling.nodeType == HTMLNodeElement) {
|
||||
hierarchyError();
|
||||
}
|
||||
[self enumerateChildNodesUsingBlock:^(HTMLNode *node, NSUInteger idx, BOOL *stop) {
|
||||
if (node.type == HTMLNodeDocument && node != child) {
|
||||
*stop = YES;
|
||||
hierarchyError();
|
||||
}
|
||||
}];
|
||||
checkParentHasAnotherChildOfType(HTMLNodeDocumentType);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -412,11 +626,13 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
HTMLNode *copy = [[self.class alloc] initWithName:self.name type:self.type];
|
||||
HTMLNode *copy = [[self.class alloc] initWithName:self.name type:self.nodeType];
|
||||
return copy;
|
||||
}
|
||||
|
||||
@@ -433,6 +649,11 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin
|
||||
return [[self.childNodes.array valueForKey:@"outerHTML"] componentsJoinedByString:@""];
|
||||
}
|
||||
|
||||
- (void)setInnerHTML:(NSString *)outerHTML
|
||||
{
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
}
|
||||
|
||||
#pragma mark - Description
|
||||
|
||||
- (NSString *)treeDescription
|
||||
@@ -466,12 +687,7 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: %p %@>", self.class, self, self.name];
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription
|
||||
{
|
||||
return self.treeDescription;
|
||||
return [NSString stringWithFormat:@"<%@: %p '%@'>", self.class, self, self.name];
|
||||
}
|
||||
|
||||
- (id)debugQuickLookObject
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// HTMLNodeFilter.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 27/05/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(unsigned short, HTMLNodeFilterValue)
|
||||
{
|
||||
HTMLNodeFilterAccept = 1,
|
||||
HTMLNodeFilterReject = 2,
|
||||
HTMLNodeFilterSkip = 3
|
||||
};
|
||||
|
||||
typedef NS_OPTIONS(unsigned long, HTMLNodeFilterShowOptions)
|
||||
{
|
||||
HTMLNodeFilterShowAll = 0xFFFFFFFF,
|
||||
HTMLNodeFilterShowElement = 0x1,
|
||||
HTMLNodeFilterShowText = 0x4,
|
||||
HTMLNodeFilterShowComment = 0x80,
|
||||
HTMLNodeFilterShowDocument = 0x100,
|
||||
HTMLNodeFilterShowDocumentType = 0x200,
|
||||
HTMLNodeFilterShowDocumentFragment = 0x400
|
||||
};
|
||||
|
||||
|
||||
#pragma mark - Node Filter
|
||||
|
||||
@class HTMLNode;
|
||||
|
||||
@protocol HTMLNodeFilter <NSObject>
|
||||
|
||||
- (HTMLNodeFilterValue)acceptNode:(HTMLNode *)node;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Block Filter
|
||||
|
||||
@interface HTMLNodeFilterBlock : NSObject <HTMLNodeFilter>
|
||||
|
||||
+ (instancetype)filterWithBlock:(HTMLNodeFilterValue (^)(HTMLNode *node))block;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - CSS Selector Filter
|
||||
|
||||
@class CSSSelector;
|
||||
|
||||
@interface HTMLSelectorNodeFilter : NSObject <HTMLNodeFilter>
|
||||
|
||||
+ (instancetype)filterWithSelector:(CSSSelector *)selector;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// HTMLNodeFilter.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 05/06/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLNodeFilter.h"
|
||||
#import "HTMLNode.h"
|
||||
#import "CSSSelector.h"
|
||||
|
||||
#pragma mark - Block Filter
|
||||
|
||||
@interface HTMLNodeFilterBlock ()
|
||||
{
|
||||
BOOL (^ _block)(HTMLNode *);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLNodeFilterBlock
|
||||
|
||||
+ (instancetype)filterWithBlock:(HTMLNodeFilterValue (^)(HTMLNode *))block
|
||||
{
|
||||
return [[self alloc] initWithBlock:block];
|
||||
}
|
||||
|
||||
- (instancetype)initWithBlock:(HTMLNodeFilterValue (^)(HTMLNode *))block
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_block = [block copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (HTMLNodeFilterValue)acceptNode:(HTMLNode *)node
|
||||
{
|
||||
if (!_block) {
|
||||
return HTMLNodeFilterSkip;
|
||||
}
|
||||
|
||||
return _block(node);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - CSS Selector Filter
|
||||
|
||||
@interface HTMLSelectorNodeFilter ()
|
||||
{
|
||||
CSSSelector *_selector;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLSelectorNodeFilter
|
||||
|
||||
+ (instancetype)filterWithSelector:(CSSSelector *)selector
|
||||
{
|
||||
return [[self alloc] initWithSelector:selector];
|
||||
}
|
||||
|
||||
- (instancetype)initWithSelector:(CSSSelector *)selector
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_selector = selector;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (HTMLNodeFilterValue)acceptNode:(HTMLNode *)node
|
||||
{
|
||||
if (node.nodeType != HTMLNodeElement) {
|
||||
return HTMLNodeFilterSkip;
|
||||
}
|
||||
|
||||
if ([_selector acceptElement:node.asElement]) {
|
||||
return HTMLNodeFilterAccept;
|
||||
}
|
||||
|
||||
return HTMLNodeFilterSkip;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// HTMLNodeIterator.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 27/05/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLNodeFilter.h"
|
||||
|
||||
@class HTMLNode;
|
||||
|
||||
@interface HTMLNodeIterator : NSEnumerator
|
||||
|
||||
@property (nonatomic, strong, readonly) HTMLNode *root;
|
||||
@property (nonatomic, strong, readonly) HTMLNode *referenceNode;
|
||||
@property (nonatomic, assign, readonly) BOOL pointerBeforeReferenceNode;
|
||||
@property (nonatomic, assign, readonly) HTMLNodeFilterShowOptions whatToShow;
|
||||
@property (nonatomic, strong, readonly) id<HTMLNodeFilter> filter;
|
||||
|
||||
+ (instancetype)iteratorWithNode:(HTMLNode *)node
|
||||
showOptions:(HTMLNodeFilterShowOptions)showOptions
|
||||
filter:(HTMLNodeFilterValue (^)(HTMLNode *node))filter;
|
||||
|
||||
- (instancetype)initWithNode:(HTMLNode *)node;
|
||||
- (instancetype)initWithNode:(HTMLNode *)node
|
||||
filter:(id<HTMLNodeFilter>)filter;
|
||||
- (instancetype)initWithNode:(HTMLNode *)node
|
||||
showOptions:(HTMLNodeFilterShowOptions)showOptions
|
||||
filter:(id<HTMLNodeFilter>)filter;
|
||||
|
||||
- (HTMLNode *)nextNode;
|
||||
- (HTMLNode *)previousNode;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,166 @@
|
||||
//
|
||||
// HTMLNodeIterator.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 27/05/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLNodeIterator.h"
|
||||
#import "HTMLDocument.h"
|
||||
#import "HTMLNode.h"
|
||||
#import "HTMLNodeFilter.h"
|
||||
#import "HTMLNodeTraversal.h"
|
||||
|
||||
typedef NS_ENUM(short, TraverseDirection)
|
||||
{
|
||||
TraverseDirectionNext,
|
||||
TraverseDirectionPrevious
|
||||
};
|
||||
|
||||
@interface HTMLDocument (Private)
|
||||
- (void)attachNodeIterator:(HTMLNodeIterator *)iterator;
|
||||
- (void)detachNodeIterator:(HTMLNodeIterator *)iterator;
|
||||
@end
|
||||
|
||||
@interface HTMLNodeIterator ()
|
||||
{
|
||||
HTMLNode *_root;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLNodeIterator
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
+ (instancetype)iteratorWithNode:(HTMLNode *)node
|
||||
showOptions:(HTMLNodeFilterShowOptions)showOptions
|
||||
filter:(HTMLNodeFilterValue (^)(HTMLNode *))filter
|
||||
{
|
||||
return [[self alloc] initWithNode:node
|
||||
showOptions:showOptions
|
||||
filter:[HTMLNodeFilterBlock filterWithBlock:filter]];
|
||||
}
|
||||
|
||||
- (instancetype)initWithNode:(HTMLNode *)node
|
||||
{
|
||||
return [self initWithNode:node filter:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithNode:(HTMLNode *)node
|
||||
filter:(id<HTMLNodeFilter>)filter
|
||||
{
|
||||
return [self initWithNode:node showOptions:HTMLNodeFilterShowAll filter:filter];
|
||||
}
|
||||
|
||||
- (instancetype)initWithNode:(HTMLNode *)node
|
||||
showOptions:(HTMLNodeFilterShowOptions)showOptions
|
||||
filter:(id<HTMLNodeFilter>)filter
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_root = node;
|
||||
_filter = filter;
|
||||
_whatToShow = showOptions;
|
||||
_referenceNode = _root;
|
||||
_pointerBeforeReferenceNode = YES;
|
||||
[_root.ownerDocument attachNodeIterator:self];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_root.ownerDocument detachNodeIterator:self];
|
||||
}
|
||||
|
||||
#pragma mark - Removing Steps
|
||||
|
||||
- (void)runRemovingStepsForNode:(HTMLNode *)oldNode
|
||||
withOldParent:(HTMLNode *)oldParent
|
||||
andOldPreviousSibling:(HTMLNode *)oldPreviousSibling
|
||||
{
|
||||
if ([oldNode containsNode:_root]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (![oldNode containsNode:_referenceNode]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_pointerBeforeReferenceNode) {
|
||||
HTMLNode *nextSibling = oldPreviousSibling != nil ? oldPreviousSibling.nextSibling : oldParent.firstChild;
|
||||
if (nextSibling != nil) {
|
||||
_referenceNode = nextSibling;
|
||||
return;
|
||||
}
|
||||
|
||||
HTMLNode *next = FollowingNode(oldParent, _root);
|
||||
if ([_root containsNode:next]) {
|
||||
_referenceNode = next;
|
||||
return;
|
||||
}
|
||||
|
||||
_pointerBeforeReferenceNode = NO;
|
||||
}
|
||||
|
||||
HTMLNode * (^ lastInclusiveDescendant) (HTMLNode *) = ^ HTMLNode * (HTMLNode *node) {
|
||||
while (node.lastChild) {
|
||||
node = node.lastChild;
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
_referenceNode = oldPreviousSibling != nil ? lastInclusiveDescendant(oldPreviousSibling) : oldParent;
|
||||
}
|
||||
|
||||
#pragma mark - Traversal
|
||||
|
||||
- (HTMLNode *)traverseInDirection:(TraverseDirection)direction
|
||||
{
|
||||
HTMLNode *node = self.referenceNode;
|
||||
BOOL beforeNode = self.pointerBeforeReferenceNode;
|
||||
|
||||
do {
|
||||
if (direction == TraverseDirectionNext) {
|
||||
if (!beforeNode) {
|
||||
node = FollowingNode(node, self.root);
|
||||
if (node == nil) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
beforeNode = NO;
|
||||
} else {
|
||||
if (beforeNode) {
|
||||
node = PrecedingNode(node, self.root);
|
||||
if (node == nil) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
beforeNode = YES;
|
||||
}
|
||||
} while (FilterNode(self.filter, self.whatToShow, node) != HTMLNodeFilterAccept);
|
||||
|
||||
_referenceNode = node;
|
||||
_pointerBeforeReferenceNode = beforeNode;
|
||||
return node;
|
||||
}
|
||||
|
||||
- (HTMLNode *)nextNode
|
||||
{
|
||||
return [self traverseInDirection:TraverseDirectionNext];
|
||||
}
|
||||
|
||||
- (HTMLNode *)previousNode
|
||||
{
|
||||
return [self traverseInDirection:TraverseDirectionPrevious];
|
||||
}
|
||||
|
||||
#pragma mark - NSEnumerator
|
||||
|
||||
- (id)nextObject
|
||||
{
|
||||
return self.nextNode;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// HTMLNodeTraversal.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 05/06/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLNodeFilter.h"
|
||||
|
||||
@class HTMLNode;
|
||||
|
||||
extern HTMLNode * PrecedingNode(HTMLNode *node, HTMLNode *root);
|
||||
extern HTMLNode * FollowingNode(HTMLNode *node, HTMLNode *root);
|
||||
extern HTMLNode * FollowingNodeSkippingChildren(HTMLNode *node, HTMLNode *root);
|
||||
extern HTMLNodeFilterValue FilterNode(id<HTMLNodeFilter> filter, HTMLNodeFilterShowOptions whatToShow, HTMLNode *node);
|
||||
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// HTMLNodeTraversal.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 05/06/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLNodeTraversal.h"
|
||||
#import "HTMLNode.h"
|
||||
#import "HTMLNodeFilter.h"
|
||||
|
||||
HTMLNode * PrecedingNode(HTMLNode *node, HTMLNode *root)
|
||||
{
|
||||
HTMLNode *previous = node.previousSibling;
|
||||
if (previous != nil) {
|
||||
while (previous.lastChild != nil) {
|
||||
previous = previous.lastChild;
|
||||
}
|
||||
return previous;
|
||||
}
|
||||
|
||||
if (node == root) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return node.parentNode;
|
||||
}
|
||||
|
||||
HTMLNode * FollowingNode(HTMLNode *node, HTMLNode *root)
|
||||
{
|
||||
if (node.firstChild != nil) {
|
||||
return node.firstChild;
|
||||
}
|
||||
|
||||
do {
|
||||
if (node == root) {
|
||||
return nil;
|
||||
}
|
||||
if (node.nextSibling != nil) {
|
||||
return node.nextSibling;
|
||||
}
|
||||
node = node.parentNode;
|
||||
} while (node != nil);
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
HTMLNode * FollowingNodeSkippingChildren(HTMLNode *node, HTMLNode *root)
|
||||
{
|
||||
do {
|
||||
if (node == root) {
|
||||
return nil;
|
||||
}
|
||||
if (node.nextSibling != nil) {
|
||||
return node.nextSibling;
|
||||
}
|
||||
node = node.parentNode;
|
||||
} while (node != nil);
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
HTMLNodeFilterValue FilterNode(id<HTMLNodeFilter> filter, HTMLNodeFilterShowOptions whatToShow, HTMLNode *node)
|
||||
{
|
||||
unsigned long nthBit = (1 << (node.nodeType - 1)) & whatToShow;
|
||||
if (!nthBit) {
|
||||
return HTMLNodeFilterSkip;
|
||||
}
|
||||
|
||||
if (filter == nil) {
|
||||
return HTMLNodeFilterAccept;
|
||||
}
|
||||
|
||||
return [filter acceptNode:node];
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
//
|
||||
// HTMLNodeTreeEnumerator.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 28/03/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class HTMLNode;
|
||||
|
||||
@interface HTMLNodeTreeEnumerator : NSEnumerator
|
||||
|
||||
- (instancetype)initWithNode:(HTMLNode *)node reverse:(BOOL)reverse;
|
||||
|
||||
@end
|
||||
@@ -1,54 +0,0 @@
|
||||
//
|
||||
// HTMLNodeTreeEnumerator.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 28/03/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLNodeTreeEnumerator.h"
|
||||
#import "HTMLNode.h"
|
||||
|
||||
@interface HTMLNodeTreeEnumerator ()
|
||||
{
|
||||
BOOL _reverse;
|
||||
NSMutableArray *_stack;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLNodeTreeEnumerator
|
||||
|
||||
- (instancetype)initWithNode:(HTMLNode *)node reverse:(BOOL)reverse
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_reverse = reverse;
|
||||
_stack = [[NSMutableArray alloc] initWithObjects:node, nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)nextObject
|
||||
{
|
||||
if (_stack.count == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
HTMLNode *node = _stack.lastObject;
|
||||
[_stack removeLastObject];
|
||||
|
||||
NSArray *childNodes = node.childNodes.array;
|
||||
if (childNodes != nil && childNodes.count > 0) {
|
||||
if (childNodes.count > 1) {
|
||||
NSRange range = NSMakeRange(_reverse ? 0 : 1, childNodes.count - 1);
|
||||
NSArray *rest = [childNodes subarrayWithRange:range];
|
||||
|
||||
[_stack addObjectsFromArray:_reverse ? rest : rest.reverseObjectEnumerator.allObjects];
|
||||
}
|
||||
[_stack addObject:_reverse ? childNodes.lastObject : childNodes.firstObject];
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -8,18 +8,22 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface HTMLOrderedDictionary : NSMutableDictionary
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (id)objectAtIndex:(NSUInteger)index;
|
||||
- (void)setObject:(id)anObject forKey:(id<NSCopying>)aKey atIndex:(NSUInteger)index;
|
||||
@interface HTMLOrderedDictionary<KeyType, ObjectType> : NSMutableDictionary<KeyType, ObjectType>
|
||||
|
||||
- (ObjectType)objectAtIndex:(NSUInteger)index;
|
||||
- (void)setObject:(ObjectType)anObject forKey:(KeyType<NSCopying>)aKey atIndex:(NSUInteger)index;
|
||||
- (void)removeObjectAtIndex:(NSUInteger)index;
|
||||
- (void)replaceKeyValueAtIndex:(NSUInteger)index withObject:(id)anObject andKey:(id<NSCopying>)aKey;
|
||||
- (void)replaceKey:(id<NSCopying>)aKey withKey:(id<NSCopying>)newKey;
|
||||
- (NSUInteger)indexOfKey:(id<NSCopying>)aKey;
|
||||
- (void)replaceKeyValueAtIndex:(NSUInteger)index withObject:(ObjectType)anObject andKey:(KeyType<NSCopying>)aKey;
|
||||
- (void)replaceKey:(KeyType<NSCopying>)aKey withKey:(KeyType<NSCopying>)newKey;
|
||||
- (NSUInteger)indexOfKey:(KeyType<NSCopying>)aKey;
|
||||
|
||||
- (id)objectAtIndexedSubscript:(NSUInteger)index;
|
||||
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)index;
|
||||
- (ObjectType)objectAtIndexedSubscript:(NSUInteger)index;
|
||||
- (void)setObject:(ObjectType)obj atIndexedSubscript:(NSUInteger)index;
|
||||
|
||||
- (NSEnumerator *)reverseKeyEnumerator;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#import "HTMLStackOfOpenElements.h"
|
||||
#import "HTMLListOfActiveFormattingElements.h"
|
||||
#import "HTMLParserInsertionModes.h"
|
||||
#import "HTMLNodes.h"
|
||||
#import "HTMLDOM.h"
|
||||
#import "HTMLElementTypes.h"
|
||||
#import "HTMLElementAdjustment.h"
|
||||
#import "HTMLMarker.h"
|
||||
@@ -127,7 +127,7 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ([_contextElement isEqualTo:contextElement]) {
|
||||
if ([_contextElement isEqual:contextElement]) {
|
||||
return [_document childNodeAtIndex:0].childNodes.array;
|
||||
}
|
||||
|
||||
@@ -421,8 +421,8 @@
|
||||
- (HTMLElement *)createElementForToken:(HTMLTagToken *)token inNamespace:(HTMLNamespace)htmlNamespace
|
||||
{
|
||||
HTMLElement *element = [[HTMLElement alloc] initWithTagName:token.tagName
|
||||
attributes:token.attributes
|
||||
namespace:htmlNamespace];
|
||||
namespace:htmlNamespace
|
||||
attributes:token.attributes];
|
||||
return element;
|
||||
}
|
||||
|
||||
@@ -452,11 +452,11 @@
|
||||
HTMLElement *child = nil;
|
||||
HTMLNode *adjustedInsertionLocation = [self appropriatePlaceForInsertingANodeWithOverrideTarget:nil
|
||||
beforeChildNode:&child];
|
||||
if (adjustedInsertionLocation.type != HTMLNodeDocument) {
|
||||
if (child != nil && child.previousSibling.type == HTMLNodeText) {
|
||||
if (adjustedInsertionLocation.nodeType != HTMLNodeDocument) {
|
||||
if (child != nil && child.previousSibling.nodeType == HTMLNodeText) {
|
||||
[(HTMLText *)child.previousSibling appendString:data];
|
||||
} else if (adjustedInsertionLocation.lastChildNode.type == HTMLNodeText) {
|
||||
[(HTMLText *)adjustedInsertionLocation.lastChildNode appendString:data];
|
||||
} else if (adjustedInsertionLocation.lastChild.nodeType == HTMLNodeText) {
|
||||
[(HTMLText *)adjustedInsertionLocation.lastChild appendString:data];
|
||||
} else {
|
||||
HTMLText *text = [[HTMLText alloc] initWithData:data];
|
||||
[adjustedInsertionLocation insertNode:text beforeChildNode:child];
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// HTMLTreeWalker.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 05/06/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLNodeFilter.h"
|
||||
|
||||
@class HTMLNode;
|
||||
|
||||
@interface HTMLTreeWalker : NSObject
|
||||
|
||||
@property (nonatomic, strong, readonly) HTMLNode *root;
|
||||
@property (nonatomic, assign, readonly) HTMLNodeFilterShowOptions whatToShow;
|
||||
@property (nonatomic, strong, readonly) id<HTMLNodeFilter> filter;
|
||||
@property (nonatomic, strong) HTMLNode *currentNode;
|
||||
|
||||
- (instancetype)initWithNode:(HTMLNode *)node;
|
||||
- (instancetype)initWithNode:(HTMLNode *)node
|
||||
filter:(id<HTMLNodeFilter>)filter;
|
||||
- (instancetype)initWithNode:(HTMLNode *)node
|
||||
showOptions:(HTMLNodeFilterShowOptions)showOptions
|
||||
filter:(id<HTMLNodeFilter>)filter;
|
||||
|
||||
- (HTMLNode *)parentNode;
|
||||
- (HTMLNode *)firstChild;
|
||||
- (HTMLNode *)lastChild;
|
||||
- (HTMLNode *)previousSibling;
|
||||
- (HTMLNode *)nextSibling;
|
||||
- (HTMLNode *)previousNode;
|
||||
- (HTMLNode *)nextNode;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,236 @@
|
||||
//
|
||||
// HTMLTreeWalker.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 05/06/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLTreeWalker.h"
|
||||
#import "HTMLNode.h"
|
||||
#import "HTMLNodeFilter.h"
|
||||
#import "HTMLNodeTraversal.h"
|
||||
|
||||
typedef NS_ENUM(short, HTMLTreeWalkerChildrenType)
|
||||
{
|
||||
HTMLTreeWalkerChildrenTypeFirst,
|
||||
HTMLTreeWalkerChildrenTypeLast
|
||||
};
|
||||
|
||||
typedef NS_ENUM(short, HTMLTreeWalkerSiblingsType)
|
||||
{
|
||||
HTMLTreeWalkerSiblingsTypeNext,
|
||||
HTMLTreeWalkerSiblingsTypePrevious
|
||||
};
|
||||
|
||||
@implementation HTMLTreeWalker
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)initWithNode:(HTMLNode *)node
|
||||
{
|
||||
return [self initWithNode:node filter:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithNode:(HTMLNode *)node
|
||||
filter:(id<HTMLNodeFilter>)filter
|
||||
{
|
||||
return [self initWithNode:node showOptions:HTMLNodeFilterShowAll filter:filter];
|
||||
}
|
||||
|
||||
- (instancetype)initWithNode:(HTMLNode *)node
|
||||
showOptions:(HTMLNodeFilterShowOptions)showOptions
|
||||
filter:(id<HTMLNodeFilter>)filter
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_root = node;
|
||||
_filter = filter;
|
||||
_whatToShow = showOptions;
|
||||
_currentNode = _root;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Traversal
|
||||
|
||||
- (HTMLNode *)parentNode
|
||||
{
|
||||
HTMLNode *node = _currentNode;
|
||||
|
||||
while (node != nil && node != _root) {
|
||||
node = node.parentNode;
|
||||
if (node != nil && FilterNode(self.filter, self.whatToShow, node) == HTMLNodeFilterAccept) {
|
||||
_currentNode = node;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (HTMLNode *)traverseChildrenOfType:(HTMLTreeWalkerChildrenType)type
|
||||
{
|
||||
HTMLNode *node = _currentNode;
|
||||
|
||||
node = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.firstChild : node.lastChild;
|
||||
|
||||
while (node != nil) {
|
||||
HTMLNodeFilterValue result = FilterNode(self.filter, self.whatToShow, node);
|
||||
if (result == HTMLNodeFilterAccept) {
|
||||
_currentNode = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
if (result == HTMLNodeFilterSkip) {
|
||||
HTMLNode *child = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.firstChild : node.lastChild;
|
||||
if (child != nil) {
|
||||
node = child;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
while (node != nil) {
|
||||
HTMLNode *sibling = (type == HTMLTreeWalkerChildrenTypeFirst) ? node.nextSibling : node.previousSibling;
|
||||
if (sibling != nil) {
|
||||
node = sibling;
|
||||
break;
|
||||
}
|
||||
|
||||
HTMLNode *parent = node.parentNode;
|
||||
if (parent == nil || parent == _root || parent == _currentNode) {
|
||||
return nil;
|
||||
}
|
||||
node = parent;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (HTMLNode *)firstChild
|
||||
{
|
||||
return [self traverseChildrenOfType:HTMLTreeWalkerChildrenTypeFirst];
|
||||
}
|
||||
|
||||
- (HTMLNode *)lastChild
|
||||
{
|
||||
return [self traverseChildrenOfType:HTMLTreeWalkerChildrenTypeLast];
|
||||
}
|
||||
|
||||
- (HTMLNode *)traverseSiblingsOfType:(HTMLTreeWalkerSiblingsType)type
|
||||
{
|
||||
HTMLNode *node = _currentNode;
|
||||
|
||||
if (node == _root) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
while (YES) {
|
||||
HTMLNode *sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.nextSibling : node.previousSibling;
|
||||
while (sibling != nil) {
|
||||
node = sibling;
|
||||
HTMLNodeFilterValue result = FilterNode(self.filter, self.whatToShow, node);
|
||||
if (result == HTMLNodeFilterAccept) {
|
||||
_currentNode = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.firstChild : node.lastChild;
|
||||
if (result == HTMLNodeFilterReject || sibling == nil) {
|
||||
sibling = (type == HTMLTreeWalkerSiblingsTypeNext) ? node.nextSibling : node.previousSibling;
|
||||
}
|
||||
}
|
||||
|
||||
node = node.parentNode;
|
||||
if (node == nil || node == _root) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (FilterNode(self.filter, self.whatToShow, node) == HTMLNodeFilterAccept) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (HTMLNode *)previousSibling
|
||||
{
|
||||
return [self traverseSiblingsOfType:HTMLTreeWalkerSiblingsTypePrevious];
|
||||
}
|
||||
|
||||
- (HTMLNode *)nextSibling
|
||||
{
|
||||
return [self traverseSiblingsOfType:HTMLTreeWalkerSiblingsTypeNext];
|
||||
}
|
||||
|
||||
- (HTMLNode *)previousNode
|
||||
{
|
||||
HTMLNode *node = _currentNode;
|
||||
|
||||
while (node != _root) {
|
||||
HTMLNode *sibling = node.previousSibling;
|
||||
|
||||
while (sibling != nil) {
|
||||
node = sibling;
|
||||
|
||||
HTMLNodeFilterValue result = FilterNode(self.filter, self.whatToShow, node);
|
||||
while (result != HTMLNodeFilterReject && node.hasChildNodes) {
|
||||
node = node.lastChild;
|
||||
result = FilterNode(self.filter, self.whatToShow, node);
|
||||
}
|
||||
|
||||
if (result == HTMLNodeFilterAccept) {
|
||||
_currentNode = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
sibling = node.previousSibling;
|
||||
}
|
||||
|
||||
if (node == _root || node.parentNode == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
node = node.parentNode;
|
||||
if (FilterNode(self.filter, self.whatToShow, node) == HTMLNodeFilterAccept) {
|
||||
_currentNode = node;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (HTMLNode *)nextNode
|
||||
{
|
||||
HTMLNode *node = _currentNode;
|
||||
|
||||
HTMLNodeFilterValue result = YES;
|
||||
|
||||
while (YES) {
|
||||
while (result != HTMLNodeFilterReject && node.hasChildNodes) {
|
||||
node = node.firstChild;
|
||||
result = FilterNode(self.filter, self.whatToShow, node);
|
||||
if (result == HTMLNodeFilterAccept) {
|
||||
_currentNode = node;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
HTMLNode *nextSibling;
|
||||
while ((nextSibling = FollowingNodeSkippingChildren(node, _root)) != nil) {
|
||||
node = nextSibling;
|
||||
result = FilterNode(self.filter, self.whatToShow, node);
|
||||
if (result == HTMLNodeFilterAccept) {
|
||||
_currentNode = node;
|
||||
return node;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// NSCharacterSet+HTMLKit.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 14/05/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSCharacterSet (HTMLKit)
|
||||
|
||||
+ (instancetype)HTMLWhitespaceCharacterSet;
|
||||
+ (instancetype)HTMLHexNumberCharacterSet;
|
||||
+ (instancetype)CSSNthExpressionCharacterSet;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// NSCharacterSet+HTMLKit.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 14/05/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSCharacterSet+HTMLKit.h"
|
||||
|
||||
@implementation NSCharacterSet (HTMLKit)
|
||||
|
||||
+ (instancetype)HTMLWhitespaceCharacterSet
|
||||
{
|
||||
static NSCharacterSet *set = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
set = [NSCharacterSet characterSetWithCharactersInString:@" \t\n\r\f"];
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
+ (instancetype)HTMLHexNumberCharacterSet
|
||||
{
|
||||
static NSCharacterSet *set = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
set = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"];
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
+ (instancetype)CSSNthExpressionCharacterSet
|
||||
{
|
||||
static NSCharacterSet *set = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
set = [NSCharacterSet characterSetWithCharactersInString:@" 0123456789nN-+"];
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,238 @@
|
||||
//
|
||||
// CSSAttributeSelectorTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 14/05/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "CSSSelectors.h"
|
||||
#import "HTMLDOM.h"
|
||||
|
||||
@interface CSSAttributeSelectorTests : XCTestCase
|
||||
{
|
||||
HTMLElement *_element;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CSSAttributeSelectorTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
_element = [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
}
|
||||
|
||||
- (void)testAttributeExists
|
||||
{
|
||||
CSSSelector *selector = hasAttributeSelector(@"attr");
|
||||
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"class"] = @"class";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"value";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"value 2";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"value 3";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
[_element.attributes removeObjectForKey:@"attr"];
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
}
|
||||
|
||||
- (void)testAttributeExactMatch
|
||||
{
|
||||
CSSSelector *selector = attributeSelector(CSSAttributeSelectorExactMatch, @"attr", @"value");
|
||||
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"class"] = @"class";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"value 1";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"value 2";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"value 3";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"value";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
[_element.attributes removeObjectForKey:@"attr"];
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
}
|
||||
|
||||
- (void)testAttributeIncludes
|
||||
{
|
||||
CSSSelector *selector = attributeSelector(CSSAttributeSelectorIncludes, @"attr", @"value");
|
||||
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"class"] = @"class";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"value";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"a b value";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"a value b";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
[_element.attributes removeObjectForKey:@"attr"];
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
}
|
||||
|
||||
- (void)testAttributeBegins
|
||||
{
|
||||
CSSSelector *selector = attributeSelector(CSSAttributeSelectorBegins, @"attr", @"value");
|
||||
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"class"] = @"class";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"val";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"a value";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"value";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"values";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
[_element.attributes removeObjectForKey:@"attr"];
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
}
|
||||
|
||||
- (void)testAttributeEnds
|
||||
{
|
||||
CSSSelector *selector = attributeSelector(CSSAttributeSelectorEnds, @"attr", @"value");
|
||||
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"class"] = @"class";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"val";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"value";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"a value";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"some-value";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
[_element.attributes removeObjectForKey:@"attr"];
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
}
|
||||
|
||||
- (void)testAttributeContains
|
||||
{
|
||||
CSSSelector *selector = attributeSelector(CSSAttributeSelectorContains, @"attr", @"value");
|
||||
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"class"] = @"class";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"val";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"value";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"a value b";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"some-values";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
[_element.attributes removeObjectForKey:@"attr"];
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
}
|
||||
|
||||
- (void)testAttributeHyphen
|
||||
{
|
||||
CSSSelector *selector = attributeSelector(CSSAttributeSelectorHyphen, @"attr", @"top");
|
||||
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"class"] = @"class";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"top_text";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"toptext";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
|
||||
_element[@"attr"] = @"top";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"top-text";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
[_element.attributes removeObjectForKey:@"attr"];
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
}
|
||||
|
||||
- (void)testAttributeNot
|
||||
{
|
||||
CSSSelector *selector = attributeSelector(CSSAttributeSelectorNot, @"attr", @"value");
|
||||
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"class"] = @"class";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"top_text";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"toptext";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"top";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"top-text";
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
[_element.attributes removeObjectForKey:@"attr"];
|
||||
XCTAssertEqual([selector acceptElement:_element], YES);
|
||||
|
||||
_element[@"attr"] = @"value";
|
||||
XCTAssertEqual([selector acceptElement:_element], NO);
|
||||
}
|
||||
|
||||
- (void)testIdSelector
|
||||
{
|
||||
_element[@"id"] = @"id";
|
||||
XCTAssertEqual([idSelector(@"id") acceptElement:_element], YES);
|
||||
XCTAssertEqual([idSelector(@"other id") acceptElement:_element], NO);
|
||||
}
|
||||
|
||||
- (void)testClassSelector
|
||||
{
|
||||
_element[@"class"] = @"class";
|
||||
XCTAssertEqual([classSelector(@"class") acceptElement:_element], YES);
|
||||
XCTAssertEqual([classSelector(@"other class") acceptElement:_element], NO);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,116 @@
|
||||
//
|
||||
// CSSCombinatorSelectorTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 23/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "CSSSelectors.h"
|
||||
#import "HTMLParser.h"
|
||||
#import "HTMLDOM.h"
|
||||
|
||||
@interface CSSCombinatorSelectorTests : XCTestCase
|
||||
{
|
||||
HTMLDocument *_document;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CSSCombinatorSelectorTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
|
||||
/*
|
||||
| <body>
|
||||
| <p id='p1'>
|
||||
| A paragraph<span id='span1'>A span</span>
|
||||
| <table id='table'>
|
||||
| <tbody id='tbody'>
|
||||
| <tr id='tr1'>
|
||||
| <td id='td'>
|
||||
| <span id='span2'>Span in table</span>
|
||||
| </td>
|
||||
| </tr>
|
||||
| <tr id='tr2'></tr>
|
||||
| <tr id='tr3'></tr>
|
||||
| </tbody>
|
||||
| </table>
|
||||
| </p>
|
||||
| <div id='inner-div1'>
|
||||
| <p id='p2'></p>
|
||||
| </div>
|
||||
| <div id='inner-div2'>
|
||||
| <p id='p3'></p>
|
||||
| </div>
|
||||
| </body>
|
||||
*/
|
||||
_document = [[[HTMLParser alloc] initWithString:@"<body>"
|
||||
"<p id='p1'>"
|
||||
"A paragraph<span id='span1'>A span</span>"
|
||||
"<table id='table'>"
|
||||
"<tbody id='tbody'>"
|
||||
"<tr id='tr1'><td id='td'>"
|
||||
"<span id='span2'>Span in table</span>"
|
||||
"</td></tr>"
|
||||
"<tr id='tr2'></tr>"
|
||||
"<tr id='tr3'></tr>"
|
||||
"</tbody>"
|
||||
"</table>"
|
||||
"</p>"
|
||||
"<div id='inner-div1'>"
|
||||
"<p id='p2'></p>"
|
||||
"</div>"
|
||||
"<div id='inner-div2'>"
|
||||
"<p id='p3'></p>"
|
||||
"</div>"
|
||||
"</body>"] document];
|
||||
}
|
||||
|
||||
-(void)testChildOfElementCombinator
|
||||
{
|
||||
NSArray *elements = [_document elementsMatchingSelector:childOfElementSelector(typeSelector(@"body"))];
|
||||
NSArray *expected = @[@"p1", @"inner-div1", @"inner-div2"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_document elementsMatchingSelector:childOfElementSelector(typeSelector(@"p"))];
|
||||
expected = @[@"span1", @"table"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
-(void)testDescendantOfElementCombinator
|
||||
{
|
||||
NSArray *elements = [_document elementsMatchingSelector:descendantOfElementSelector(typeSelector(@"p"))];
|
||||
NSArray *expected = @[@"span1", @"table", @"tbody", @"tr1", @"td", @"span2", @"tr2", @"tr3"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_document elementsMatchingSelector:descendantOfElementSelector(typeSelector(@"table"))];
|
||||
expected = @[@"tbody", @"tr1", @"td", @"span2", @"tr2", @"tr3"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
-(void)testAdjacentSiblingCombinator
|
||||
{
|
||||
NSArray *elements = [_document elementsMatchingSelector:adjacentSiblingSelector(typeSelector(@"tr"))];
|
||||
NSArray *expected = @[@"tr2", @"tr3"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_document elementsMatchingSelector:adjacentSiblingSelector(typeSelector(@"p"))];
|
||||
expected = @[@"inner-div1"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
-(void)testGeneralSiblingCombinator
|
||||
{
|
||||
NSArray *elements = [_document elementsMatchingSelector:generalSiblingSelector(typeSelector(@"tr"))];
|
||||
NSArray *expected = @[@"tr2", @"tr3"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_document elementsMatchingSelector:generalSiblingSelector(typeSelector(@"p"))];
|
||||
expected = @[@"inner-div1", @"inner-div2"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,352 @@
|
||||
//
|
||||
// CSSNThExpressionSelectorTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 21/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "CSSSelectors.h"
|
||||
#import "HTMLParser.h"
|
||||
#import "HTMLDOM.h"
|
||||
|
||||
@interface CSSNThExpressionSelectorTests : XCTestCase
|
||||
{
|
||||
HTMLDocument *_childTree;
|
||||
HTMLDocument *_typeTree;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation CSSNThExpressionSelectorTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
|
||||
/*
|
||||
| <div>
|
||||
| <table>
|
||||
| <tr id='11'><td>11</td></tr>
|
||||
| <tr id='12'><td>12</td></tr>
|
||||
| <tr id='13'><td>13</td></tr>
|
||||
| <tr id='14'><td>14</td></tr>
|
||||
| </table>
|
||||
| </div>
|
||||
| <div>
|
||||
| <table>
|
||||
| <tr id='21'><td>21</td></tr>
|
||||
| </table>
|
||||
| </div>
|
||||
| <div>
|
||||
| <table>
|
||||
| <tr id='31'><td>31</td></tr>
|
||||
| <tr id='32'><td>32</td></tr>
|
||||
| <tr id='33'><td>33</td></tr>
|
||||
| <tr id='34'><td>34</td></tr>
|
||||
| <tr id='35'><td>35</td></tr>
|
||||
| <tr id='36'><td>36</td></tr>
|
||||
| </table>
|
||||
| </div>
|
||||
*/
|
||||
_childTree = [[[HTMLParser alloc] initWithString:@"<div><table>"
|
||||
"<tr id='11'><td>11</td></tr>"
|
||||
"<tr id='12'><td>12</td></tr>"
|
||||
"<tr id='13'><td>13</td></tr>"
|
||||
"<tr id='14'><td>14</td></tr>"
|
||||
"</table></div>"
|
||||
"<div><table>"
|
||||
"<tr id='21'><td>21</td></tr>"
|
||||
"</table></div>"
|
||||
"<div><table>"
|
||||
"<tr id='31'><td>31</td></tr>"
|
||||
"<tr id='32'><td>32</td></tr>"
|
||||
"<tr id='33'><td>33</td></tr>"
|
||||
"<tr id='34'><td>34</td></tr>"
|
||||
"<tr id='35'><td>35</td></tr>"
|
||||
"<tr id='36'><td>36</td></tr>"
|
||||
"</table></div>"] document];
|
||||
|
||||
/*
|
||||
| <div>
|
||||
| <span id='s11'>s11</span>
|
||||
| <span id='s12'>s12</span>
|
||||
| <span id='s13'>s13</span>
|
||||
| <b id='b1'>b1</b>
|
||||
| </div>
|
||||
| <div>
|
||||
| <b id='b2'>b2</b>
|
||||
| <span id='s21'>s21</span>
|
||||
| <span id='s22'>s22</span>
|
||||
| <span id='s23'>s23</span>
|
||||
| </div>
|
||||
| <div>
|
||||
| <span id='s31'>s31</span>
|
||||
| <b id='b3'>b3</b>
|
||||
| <span id='s32'>s32</span>
|
||||
| <b id='b4'>b4</b>
|
||||
| <span id='s33'>s33</span>
|
||||
| <b id='b5'>b5</b>
|
||||
| <span id='s34'>s34</span>
|
||||
| </div>
|
||||
*/
|
||||
_typeTree = [[[HTMLParser alloc] initWithString:@"<div>"
|
||||
"<span id='s11'>s11</span>"
|
||||
"<span id='s12'>s12</span>"
|
||||
"<span id='s13'>s13</span>"
|
||||
"<b id='b1'>b1</b>"
|
||||
"</div>"
|
||||
"<div>"
|
||||
"<b id='b2'>b2</b>"
|
||||
"<span id='s21'>s21</span>"
|
||||
"<span id='s22'>s22</span>"
|
||||
"<span id='s23'>s23</span>"
|
||||
"</div>"
|
||||
"<div>"
|
||||
"<span id='s31'>s31</span>"
|
||||
"<b id='b3'>b3</b>"
|
||||
"<span id='s32'>s32</span>"
|
||||
"<b id='b4'>b4</b>"
|
||||
"<span id='s33'>s33</span>"
|
||||
"<b id='b5'>b5</b>"
|
||||
"<span id='s34'>s34</span>"
|
||||
"</div>"] document];
|
||||
}
|
||||
|
||||
- (void)testOddSelector
|
||||
{
|
||||
NSArray *elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), oddSelector()])];
|
||||
NSArray *expected = @[@"11", @"13", @"21", @"31", @"33", @"35"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)testEvenSelector
|
||||
{
|
||||
NSArray *elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), evenSlector()])];
|
||||
NSArray *expected = @[@"12", @"14", @"32", @"34", @"36"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)testFirstChildSelector
|
||||
{
|
||||
NSArray *elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), firstChildSelector()])];
|
||||
NSArray *expected = @[@"11", @"21", @"31"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)testLastChildSelector
|
||||
{
|
||||
NSArray *elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), lastChildSelector()])];
|
||||
NSArray *expected = @[@"14", @"21", @"36"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)testFirstOfTypeSelector
|
||||
{
|
||||
NSArray *elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), firstOfTypeSelector()])];
|
||||
NSArray *expected = @[@"s11", @"s21", @"s31"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)testLastOfTypeSelector
|
||||
{
|
||||
NSArray *elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), lastOfTypeSelector()])];
|
||||
NSArray *expected = @[@"s13", @"s23", @"s34"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)testOnlyChildSelector
|
||||
{
|
||||
NSArray *elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), onlyChildSelector()])];
|
||||
NSArray *expected = @[@"21"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)testOnlyOfTypeSelector
|
||||
{
|
||||
NSArray *elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), onlyOfTypeSelector()])];
|
||||
NSArray *expected = @[];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), onlyOfTypeSelector()])];
|
||||
expected = @[];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"b"), onlyOfTypeSelector()])];
|
||||
expected = @[@"b1", @"b2"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
#pragma mark - Nth-Child Selector
|
||||
|
||||
- (void)test_NthChild_B_Selector
|
||||
{
|
||||
NSArray *elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthChildSelector(CSSNthExpressionMake(0, 1))])];
|
||||
NSArray *expected = @[@"11", @"21", @"31"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthChildSelector(CSSNthExpressionMake(0, 2))])];
|
||||
expected = @[@"12", @"32"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthChildSelector(CSSNthExpressionMake(0, 3))])];
|
||||
expected = @[@"13", @"33"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)test_NthChild_An_Selector
|
||||
{
|
||||
NSArray *elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthChildSelector(CSSNthExpressionMake(2, 0))])];
|
||||
NSArray *expected = @[@"12", @"14", @"32", @"34", @"36"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthChildSelector(CSSNthExpressionMake(3, 0))])];
|
||||
expected = @[@"13", @"33", @"36"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthChildSelector(CSSNthExpressionMake(4, 0))])];
|
||||
expected = @[@"14", @"34"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)test_NthChild_An_B_Selector
|
||||
{
|
||||
NSArray *elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthChildSelector(CSSNthExpressionMake(3, 1))])];
|
||||
NSArray *expected = @[@"11", @"14", @"21", @"31", @"34"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthChildSelector(CSSNthExpressionMake(3, 2))])];
|
||||
expected = @[@"12", @"32", @"35"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
#pragma mark - Nth-Last-Child Selector
|
||||
|
||||
- (void)test_NthLastChild_B_Selector
|
||||
{
|
||||
NSArray *elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthLastChildSelector(CSSNthExpressionMake(0, 1))])];
|
||||
NSArray *expected = @[@"14", @"21", @"36"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthLastChildSelector(CSSNthExpressionMake(0, 2))])];
|
||||
expected = @[@"13", @"35"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthLastChildSelector(CSSNthExpressionMake(0, 3))])];
|
||||
expected = @[@"12", @"34"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)test_NthLastChild_An_Selector
|
||||
{
|
||||
NSArray *elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthLastChildSelector(CSSNthExpressionMake(2, 0))])];
|
||||
NSArray *expected = @[@"11", @"13", @"31", @"33", @"35"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthLastChildSelector(CSSNthExpressionMake(3, 0))])];
|
||||
expected = @[@"12", @"31", @"34"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthLastChildSelector(CSSNthExpressionMake(4, 0))])];
|
||||
expected = @[@"11", @"33"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)test_NthLastChild_An_B_Selector
|
||||
{
|
||||
NSArray *elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthLastChildSelector(CSSNthExpressionMake(3, 1))])];
|
||||
NSArray *expected = @[@"11", @"14", @"21", @"33", @"36"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_childTree elementsMatchingSelector:allOf(@[typeSelector(@"tr"), nthLastChildSelector(CSSNthExpressionMake(3, 2))])];
|
||||
expected = @[@"13", @"32", @"35"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
#pragma mark - Nth-Of-Type Selector
|
||||
|
||||
- (void)test_NthOfType_B_Selector
|
||||
{
|
||||
NSArray *elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthOfTypeSelector(CSSNthExpressionMake(0, 1))])];
|
||||
NSArray *expected = @[@"s11", @"s21", @"s31"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthOfTypeSelector(CSSNthExpressionMake(0, 2))])];
|
||||
expected = @[@"s12", @"s22", @"s32"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthOfTypeSelector(CSSNthExpressionMake(0, 3))])];
|
||||
expected = @[@"s13", @"s23", @"s33"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)test_NthOfType_An_Selector
|
||||
{
|
||||
NSArray *elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthOfTypeSelector(CSSNthExpressionMake(2, 0))])];
|
||||
NSArray *expected = @[@"s12", @"s22", @"s32", @"s34"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthOfTypeSelector(CSSNthExpressionMake(3, 0))])];
|
||||
expected = @[@"s13", @"s23", @"s33"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthOfTypeSelector(CSSNthExpressionMake(4, 0))])];
|
||||
expected = @[@"s34"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)test_NthOfType_An_B_Selector
|
||||
{
|
||||
NSArray *elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthOfTypeSelector(CSSNthExpressionMake(2, 1))])];
|
||||
NSArray *expected = @[@"s11", @"s13", @"s21", @"s23", @"s31", @"s33"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthOfTypeSelector(CSSNthExpressionMake(2, 2))])];
|
||||
expected = @[@"s12", @"s22", @"s32", @"s34"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
#pragma mark - Nth-Last-Of-Type Selector
|
||||
|
||||
- (void)test_NthLastOfType_B_Selector
|
||||
{
|
||||
NSArray *elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthLastOfTypeSelector(CSSNthExpressionMake(0, 1))])];
|
||||
NSArray *expected = @[@"s13", @"s23", @"s34"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthLastOfTypeSelector(CSSNthExpressionMake(0, 2))])];
|
||||
expected = @[@"s12", @"s22", @"s33"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthLastOfTypeSelector(CSSNthExpressionMake(0, 3))])];
|
||||
expected = @[@"s11", @"s21", @"s32"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)test_NthLastOfType_An_Selector
|
||||
{
|
||||
NSArray *elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthLastOfTypeSelector(CSSNthExpressionMake(2, 0))])];
|
||||
NSArray *expected = @[@"s12", @"s22", @"s31", @"s33"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthLastOfTypeSelector(CSSNthExpressionMake(3, 0))])];
|
||||
expected = @[@"s11", @"s21", @"s32"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthLastOfTypeSelector(CSSNthExpressionMake(4, 0))])];
|
||||
expected = @[@"s31"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
- (void)test_NthLastOfType_An_B_Selector
|
||||
{
|
||||
NSArray *elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthLastOfTypeSelector(CSSNthExpressionMake(2, 1))])];
|
||||
NSArray *expected = @[@"s11", @"s13", @"s21", @"s23", @"s32", @"s34"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
|
||||
elements = [_typeTree elementsMatchingSelector:allOf(@[typeSelector(@"span"), nthLastOfTypeSelector(CSSNthExpressionMake(2, 2))])];
|
||||
expected = @[@"s12", @"s22", @"s31", @"s33"];
|
||||
XCTAssertEqualObjects([elements valueForKeyPath:@"attributes.id"], expected);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,158 @@
|
||||
//
|
||||
// CSSNthExpressionsParserTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 10/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "CSSNthExpressionParser.h"
|
||||
|
||||
@interface CSSNthExpressionsParserTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation CSSNthExpressionsParserTests
|
||||
|
||||
- (void)testOddEvenExpression
|
||||
{
|
||||
CSSNthExpression odd = [CSSNthExpressionParser parseExpression:@"odd"];
|
||||
XCTAssertEqual(odd.an, 2);
|
||||
XCTAssertEqual(odd.b, 1);
|
||||
|
||||
odd = [CSSNthExpressionParser parseExpression:@" odd"];
|
||||
XCTAssertEqual(odd.an, 2);
|
||||
XCTAssertEqual(odd.b, 1);
|
||||
|
||||
odd = [CSSNthExpressionParser parseExpression:@"odd "];
|
||||
XCTAssertEqual(odd.an, 2);
|
||||
XCTAssertEqual(odd.b, 1);
|
||||
|
||||
odd = [CSSNthExpressionParser parseExpression:@" odd "];
|
||||
XCTAssertEqual(odd.an, 2);
|
||||
XCTAssertEqual(odd.b, 1);
|
||||
|
||||
CSSNthExpression even = [CSSNthExpressionParser parseExpression:@"even"];
|
||||
XCTAssertEqual(even.an, 2);
|
||||
XCTAssertEqual(even.b, 0);
|
||||
|
||||
even = [CSSNthExpressionParser parseExpression:@" even"];
|
||||
XCTAssertEqual(even.an, 2);
|
||||
XCTAssertEqual(even.b, 0);
|
||||
|
||||
even = [CSSNthExpressionParser parseExpression:@"even "];
|
||||
XCTAssertEqual(even.an, 2);
|
||||
XCTAssertEqual(even.b, 0);
|
||||
|
||||
even = [CSSNthExpressionParser parseExpression:@" even "];
|
||||
XCTAssertEqual(even.an, 2);
|
||||
XCTAssertEqual(even.b, 0);
|
||||
}
|
||||
|
||||
- (void)test_B_Expression
|
||||
{
|
||||
CSSNthExpression expression = [CSSNthExpressionParser parseExpression:@"1"];
|
||||
XCTAssertEqual(expression.an, 0);
|
||||
XCTAssertEqual(expression.b, 1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"+1"];
|
||||
XCTAssertEqual(expression.an, 0);
|
||||
XCTAssertEqual(expression.b, 1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"-1"];
|
||||
XCTAssertEqual(expression.an, 0);
|
||||
XCTAssertEqual(expression.b, -1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@" -1"];
|
||||
XCTAssertEqual(expression.an, 0);
|
||||
XCTAssertEqual(expression.b, -1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"+1 "];
|
||||
XCTAssertEqual(expression.an, 0);
|
||||
XCTAssertEqual(expression.b, 1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@" +1 "];
|
||||
XCTAssertEqual(expression.an, 0);
|
||||
XCTAssertEqual(expression.b, 1);
|
||||
}
|
||||
|
||||
- (void)test_AN_Expression
|
||||
{
|
||||
CSSNthExpression expression = [CSSNthExpressionParser parseExpression:@"n"];
|
||||
XCTAssertEqual(expression.an, 1);
|
||||
XCTAssertEqual(expression.b, 0);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"+n"];
|
||||
XCTAssertEqual(expression.an, 1);
|
||||
XCTAssertEqual(expression.b, 0);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"2n"];
|
||||
XCTAssertEqual(expression.an, 2);
|
||||
XCTAssertEqual(expression.b, 0);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"+2n"];
|
||||
XCTAssertEqual(expression.an, 2);
|
||||
XCTAssertEqual(expression.b, 0);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"-n"];
|
||||
XCTAssertEqual(expression.an, -1);
|
||||
XCTAssertEqual(expression.b, 0);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"-2n"];
|
||||
XCTAssertEqual(expression.an, -2);
|
||||
XCTAssertEqual(expression.b, 0);
|
||||
}
|
||||
|
||||
- (void)test_AN_B_Expression
|
||||
{
|
||||
CSSNthExpression expression = [CSSNthExpressionParser parseExpression:@"2n+1"];
|
||||
XCTAssertEqual(expression.an, 2);
|
||||
XCTAssertEqual(expression.b, 1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"+2n+1"];
|
||||
XCTAssertEqual(expression.an, 2);
|
||||
XCTAssertEqual(expression.b, 1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"-2n+1"];
|
||||
XCTAssertEqual(expression.an, -2);
|
||||
XCTAssertEqual(expression.b, 1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"2n-1"];
|
||||
XCTAssertEqual(expression.an, 2);
|
||||
XCTAssertEqual(expression.b, -1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"-2n-1"];
|
||||
XCTAssertEqual(expression.an, -2);
|
||||
XCTAssertEqual(expression.b, -1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"n-1"];
|
||||
XCTAssertEqual(expression.an, 1);
|
||||
XCTAssertEqual(expression.b, -1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"-n-1"];
|
||||
XCTAssertEqual(expression.an, -1);
|
||||
XCTAssertEqual(expression.b, -1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"+n-1"];
|
||||
XCTAssertEqual(expression.an, 1);
|
||||
XCTAssertEqual(expression.b, -1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"+2n + 1"];
|
||||
XCTAssertEqual(expression.an, 2);
|
||||
XCTAssertEqual(expression.b, 1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@"-2n + 1"];
|
||||
XCTAssertEqual(expression.an, -2);
|
||||
XCTAssertEqual(expression.b, 1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@" 2n - 1"];
|
||||
XCTAssertEqual(expression.an, 2);
|
||||
XCTAssertEqual(expression.b, -1);
|
||||
|
||||
expression = [CSSNthExpressionParser parseExpression:@" -2n -1 "];
|
||||
XCTAssertEqual(expression.an, -2);
|
||||
XCTAssertEqual(expression.b, -1);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,104 @@
|
||||
//
|
||||
// CSSSelectorParserTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 23/10/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <HTMLKit/HTMLKit.h>
|
||||
#import "CSSSelectorTest.h"
|
||||
#import "CSSSelectorParser.h"
|
||||
|
||||
@interface CSSSelectorParserTests : XCTestCase
|
||||
@property (nonatomic, strong) CSSSelectorTest *testCase;
|
||||
@end
|
||||
|
||||
@implementation CSSSelectorParserTests
|
||||
|
||||
+ (XCTestSuite *)defaultTestSuite
|
||||
{
|
||||
XCTestSuite *suite = [[XCTestSuite alloc] initWithName:NSStringFromClass(self)];
|
||||
|
||||
NSArray *tests = [CSSSelectorTest loadCSSSelectorTests];
|
||||
for (CSSSelectorTest *test in tests) {
|
||||
[self addSelectorTest:test toTestSuite:suite];
|
||||
}
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
+ (void)addSelectorTest:(CSSSelectorTest *)selectorTest toTestSuite:(XCTestSuite *)suite
|
||||
{
|
||||
NSArray *allInvocations = [self testInvocations];
|
||||
for (NSInvocation *invocation in allInvocations) {
|
||||
XCTestCase *testCase = [[self alloc] initWithInvocation:invocation
|
||||
testCase:selectorTest];
|
||||
[suite addTest:testCase];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Instance
|
||||
|
||||
- (instancetype)initWithInvocation:(NSInvocation *)invocation
|
||||
testCase:(CSSSelectorTest *)testCase
|
||||
{
|
||||
self = [super initWithInvocation:invocation];
|
||||
if (self) {
|
||||
_testCase = testCase;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)name
|
||||
{
|
||||
NSInvocation *invocation = [self invocation];
|
||||
NSString *title = self.testCase.testName.stringByDeletingPathExtension;
|
||||
return [NSString stringWithFormat:@"-[%@ %@_%@]", self.class, NSStringFromSelector(invocation.selector), title];
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return self.name;
|
||||
}
|
||||
|
||||
#pragma mark - Tests
|
||||
|
||||
- (void)testParser
|
||||
{
|
||||
for (NSDictionary *testDescription in self.testCase.selectors) {
|
||||
NSString *selectorString = testDescription[@"selector"];
|
||||
NSArray *expectedMatches = testDescription[@"match"];
|
||||
NSNumber *expectedError = testDescription[@"error"];
|
||||
HTMLElement *testDOM = self.testCase.testDOM;
|
||||
|
||||
NSError *error = nil;
|
||||
CSSSelector *parsedSelector = [CSSSelectorParser parseSelector:selectorString error:&error];
|
||||
|
||||
if (expectedError) {
|
||||
XCTAssertNotNil(error);
|
||||
XCTAssertNil(parsedSelector);
|
||||
|
||||
NSUInteger errorLocation = [error.userInfo[CSSSelectorErrorLocationKey] unsignedIntegerValue];
|
||||
XCTAssertEqual(errorLocation, expectedError.unsignedIntegerValue);
|
||||
} else {
|
||||
XCTAssertNil(error);
|
||||
XCTAssertNotNil(parsedSelector);
|
||||
|
||||
NSArray *matchedElements = [testDOM elementsMatchingSelector:parsedSelector];
|
||||
NSArray *matchedIds = [matchedElements valueForKeyPath:@"attributes.id"];
|
||||
|
||||
NSString *message = [NSString stringWithFormat:@"CSS test: \'%@\'\nInput:\n%@\nDOM:\n%@\nExpected:\n%@\nActual:\n%@\n",
|
||||
self.name,
|
||||
selectorString,
|
||||
testDOM.outerHTML,
|
||||
expectedMatches,
|
||||
matchedIds];
|
||||
|
||||
XCTAssertEqualObjects(matchedIds, expectedMatches, @"IDs mismatch:\n%@", message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// CSSSelectorTest.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 22/11/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class HTMLElement;
|
||||
|
||||
@interface CSSSelectorTest : NSObject
|
||||
|
||||
@property (nonatomic, copy) NSString *testName;
|
||||
@property (nonatomic, strong) NSArray *selectors;
|
||||
@property (nonatomic, strong) HTMLElement *testDOM;
|
||||
|
||||
+ (NSArray *)loadCSSSelectorTests;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// CSSSelectorTest.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 22/11/15.
|
||||
// Copyright © 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CSSSelectorTest.h"
|
||||
#import "HTMLParser.h"
|
||||
#import "HTMLDocument.h"
|
||||
#import "HTMLElement.h"
|
||||
#import "CSSSelectors.h"
|
||||
|
||||
static NSString * const CSSTests = @"css-tests";
|
||||
|
||||
@implementation CSSSelectorTest
|
||||
|
||||
+ (NSArray *)loadCSSSelectorTests
|
||||
{
|
||||
NSString *path = [[NSBundle bundleForClass:self.class] resourcePath];
|
||||
path = [path stringByAppendingPathComponent:CSSTests];
|
||||
|
||||
NSMutableArray *tests = [NSMutableArray array];
|
||||
NSArray *testFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
|
||||
|
||||
for (NSString *testFile in testFiles) {
|
||||
if (![testFile.pathExtension isEqualToString:@"html"]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSString *testFilePath = [path stringByAppendingPathComponent:testFile];
|
||||
CSSSelectorTest *test = [CSSSelectorTest testWithFileAtPath:testFilePath];
|
||||
[tests addObject:test];
|
||||
}
|
||||
|
||||
return tests;
|
||||
}
|
||||
|
||||
+ (instancetype)testWithFileAtPath:(NSString *)filePath
|
||||
{
|
||||
NSString *testName = filePath.lastPathComponent.stringByDeletingPathExtension;
|
||||
|
||||
NSString *html = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
|
||||
|
||||
HTMLDocument *document = [HTMLDocument documentWithString:html];
|
||||
|
||||
HTMLElement *domElement = [document firstElementMatchingSelector:idSelector(@"testDOM")];
|
||||
HTMLElement *scriptElement = [document firstElementMatchingSelector:idSelector(@"selectors")];
|
||||
NSData *data = [scriptElement.textContent dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSArray *selectors = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
|
||||
|
||||
CSSSelectorTest *instance = [CSSSelectorTest new];
|
||||
instance.testName = testName;
|
||||
instance.selectors = selectors;
|
||||
instance.testDOM = domElement;
|
||||
return instance;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// CSSTypeSelectorTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 14/05/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "CSSSelectors.h"
|
||||
#import "HTMLDOM.h"
|
||||
#import "CSSSelectorParser.h"
|
||||
|
||||
@interface CSSTypeSelectorTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation CSSTypeSelectorTests
|
||||
|
||||
- (void)testUniversalSelector
|
||||
{
|
||||
CSSSelector *selector = universalSelector();
|
||||
|
||||
XCTAssertEqual([selector acceptElement:[[HTMLElement alloc] initWithTagName:nil]], YES);
|
||||
XCTAssertEqual([selector acceptElement:[[HTMLElement alloc] initWithTagName:@""]], YES);
|
||||
XCTAssertEqual([selector acceptElement:[[HTMLElement alloc] initWithTagName:@"div"]], YES);
|
||||
XCTAssertEqual([selector acceptElement:[[HTMLElement alloc] initWithTagName:@"p"]], YES);
|
||||
XCTAssertEqual([selector acceptElement:[[HTMLElement alloc] initWithTagName:@"any other name"]], YES);
|
||||
}
|
||||
|
||||
- (void)testTypeSelector
|
||||
{
|
||||
CSSSelector *selector = typeSelector(@"div");
|
||||
|
||||
XCTAssertEqual([selector acceptElement:[[HTMLElement alloc] initWithTagName:nil]], NO);
|
||||
XCTAssertEqual([selector acceptElement:[[HTMLElement alloc] initWithTagName:@""]], NO);
|
||||
XCTAssertEqual([selector acceptElement:[[HTMLElement alloc] initWithTagName:@"p"]], NO);
|
||||
XCTAssertEqual([selector acceptElement:[[HTMLElement alloc] initWithTagName:@"any other name"]], NO);
|
||||
|
||||
XCTAssertEqual([selector acceptElement:[[HTMLElement alloc] initWithTagName:@"div"]], YES);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -13,7 +13,6 @@
|
||||
#import "HTMLElement.h"
|
||||
#import "HTMLText.h"
|
||||
#import "HTMLComment.h"
|
||||
#import "HTMLNodeTreeEnumerator.h"
|
||||
|
||||
static NSString * const HTML5LibTests = @"html5lib-tests";
|
||||
static NSString * const TreeConstruction = @"tree-construction";
|
||||
@@ -111,7 +110,7 @@ static NSString * const TreeConstruction = @"tree-construction";
|
||||
fragment = [fragment substringFromIndex:@"svg ".length];
|
||||
namespace = HTMLNamespaceSVG;
|
||||
}
|
||||
test.documentFragment = [[HTMLElement alloc] initWithTagName:fragment attributes:nil namespace:namespace];
|
||||
test.documentFragment = [[HTMLElement alloc] initWithTagName:fragment namespace:namespace attributes:nil];
|
||||
} else if ([match hasPrefix:@"#document\n"]) {
|
||||
NSArray *parts = [[match substringFromIndex:@"#document\n".length] componentsSeparatedByString:@"| "];
|
||||
NSArray *nodes = [HTML5LibTreeConstructionTest parseDocument:parts];
|
||||
@@ -245,7 +244,7 @@ NS_INLINE HTMLElement * parseTag(NSString *str)
|
||||
NSString *tagName = parts.count == 2 ? parts[1] : parts[0];
|
||||
HTMLNamespace namespace = parts.count == 1 ? HTMLNamespaceHTML : ([parts[0] isEqualToString:@"math"] ? HTMLNamespaceMathML : HTMLNamespaceSVG);
|
||||
|
||||
HTMLElement *element = [[HTMLElement alloc] initWithTagName:tagName attributes:nil namespace:namespace];
|
||||
HTMLElement *element = [[HTMLElement alloc] initWithTagName:tagName namespace:namespace attributes:nil];
|
||||
return element;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
//
|
||||
// HTMLKitMutationAlgorithmsTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 27/04/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "HTMLDOM.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
|
||||
extern uint64_t dispatch_benchmark(size_t count, void (^block)(void));
|
||||
|
||||
@interface HTMLKitMutationAlgorithmsTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation HTMLKitMutationAlgorithmsTests
|
||||
|
||||
- (void)testValidParentNodeWhenAppending
|
||||
{
|
||||
HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
|
||||
id parent = [HTMLDocument new];
|
||||
XCTAssertNoThrow([parent appendNode:element]);
|
||||
|
||||
parent = [HTMLDocumentFragment new];
|
||||
XCTAssertNoThrow([parent appendNode:element]);
|
||||
|
||||
parent = [HTMLElement new];
|
||||
XCTAssertNoThrow([parent appendNode:element]);
|
||||
|
||||
parent = [HTMLTemplate new];
|
||||
XCTAssertNoThrow([parent appendNode:element]);
|
||||
|
||||
parent = [HTMLDocumentType new];
|
||||
XCTAssertThrows([parent appendNode:element]);
|
||||
|
||||
parent = [HTMLComment new];
|
||||
XCTAssertThrows([parent appendNode:element]);
|
||||
|
||||
parent = [HTMLText new];
|
||||
XCTAssertThrows([parent appendNode:element]);
|
||||
}
|
||||
|
||||
- (void)testValidParentNodeWhenInserting
|
||||
{
|
||||
HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
|
||||
id parent = [HTMLDocument new];
|
||||
XCTAssertNoThrow([parent insertNode:element beforeChildNode:nil]);
|
||||
|
||||
parent = [HTMLDocumentFragment new];
|
||||
XCTAssertNoThrow([parent insertNode:element beforeChildNode:nil]);
|
||||
|
||||
parent = [HTMLElement new];
|
||||
XCTAssertNoThrow([parent insertNode:element beforeChildNode:nil]);
|
||||
|
||||
parent = [HTMLTemplate new];
|
||||
XCTAssertNoThrow([parent insertNode:element beforeChildNode:nil]);
|
||||
|
||||
parent = [HTMLDocumentType new];
|
||||
XCTAssertThrows([parent insertNode:element beforeChildNode:nil]);
|
||||
|
||||
parent = [HTMLComment new];
|
||||
XCTAssertThrows([parent insertNode:element beforeChildNode:nil]);
|
||||
|
||||
parent = [HTMLText new];
|
||||
XCTAssertThrows([parent insertNode:element beforeChildNode:nil]);
|
||||
}
|
||||
|
||||
- (void)testValidChildNodeWhenInserting
|
||||
{
|
||||
HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
HTMLElement *p = [[HTMLElement alloc] initWithTagName:@"p"];
|
||||
[div appendNode:p];
|
||||
|
||||
HTMLElement *table = [[HTMLElement alloc] initWithTagName:@"table"];
|
||||
|
||||
XCTAssertNoThrow([div insertNode:table beforeChildNode:p]);
|
||||
|
||||
[div removeChildNode:p];
|
||||
|
||||
HTMLElement *section = [[HTMLElement alloc] initWithTagName:@"section"];
|
||||
XCTAssertThrows([div insertNode:section beforeChildNode:p]);
|
||||
}
|
||||
|
||||
- (void)testValidChildNodeWhenReplacing
|
||||
{
|
||||
HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
HTMLElement *p = [[HTMLElement alloc] initWithTagName:@"p"];
|
||||
[div appendNode:p];
|
||||
|
||||
HTMLElement *table = [[HTMLElement alloc] initWithTagName:@"table"];
|
||||
|
||||
XCTAssertNoThrow([div replaceChildNode:p withNode:table]);
|
||||
|
||||
XCTAssertThrows([div replaceChildNode:p withNode:[HTMLComment new]]);
|
||||
}
|
||||
|
||||
- (void)testValidChildNodeWhenRemoving
|
||||
{
|
||||
HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
HTMLElement *p = [[HTMLElement alloc] initWithTagName:@"p"];
|
||||
[div appendNode:p];
|
||||
|
||||
XCTAssertNoThrow([div removeChildNode:p]);
|
||||
XCTAssertThrows([div removeChildNode:p]);
|
||||
}
|
||||
|
||||
- (void)testValidInsertedNode
|
||||
{
|
||||
HTMLDocument *document = [HTMLDocument new];
|
||||
|
||||
XCTAssertNoThrow([document appendNode:[HTMLDocumentFragment new]]);
|
||||
XCTAssertNoThrow([document appendNode:[HTMLDocumentType new]]);
|
||||
XCTAssertNoThrow([document appendNode:[HTMLElement new]]);
|
||||
|
||||
HTMLElement *element = [HTMLElement new];
|
||||
|
||||
XCTAssertNoThrow([element appendNode:[HTMLTemplate new]]);
|
||||
XCTAssertNoThrow([element appendNode:[HTMLComment new]]);
|
||||
XCTAssertNoThrow([element appendNode:[HTMLText new]]);
|
||||
}
|
||||
|
||||
- (void)testValidParentForDoctype
|
||||
{
|
||||
HTMLDocumentType *doctype = [HTMLDocumentType new];
|
||||
|
||||
XCTAssertNoThrow([[HTMLDocument new] appendNode:doctype]);
|
||||
|
||||
XCTAssertThrows([[HTMLDocumentFragment new] appendNode:doctype]);
|
||||
XCTAssertThrows([[HTMLDocumentType new] appendNode:doctype]);
|
||||
XCTAssertThrows([[HTMLElement new] appendNode:doctype]);
|
||||
XCTAssertThrows([[HTMLTemplate new] appendNode:doctype]);
|
||||
XCTAssertThrows([[HTMLComment new] appendNode:doctype]);
|
||||
XCTAssertThrows([[HTMLText new] appendNode:doctype]);
|
||||
}
|
||||
|
||||
- (void)testValidParentForText
|
||||
{
|
||||
HTMLText *text = [HTMLText new];
|
||||
|
||||
XCTAssertThrows([[HTMLDocument new] appendNode:text]);
|
||||
XCTAssertThrows([[HTMLDocumentType new] appendNode:text]);
|
||||
XCTAssertThrows([[HTMLComment new] appendNode:text]);
|
||||
XCTAssertThrows([[HTMLText new] appendNode:text]);
|
||||
|
||||
XCTAssertNoThrow([[HTMLDocumentFragment new] appendNode:text]);
|
||||
XCTAssertNoThrow([[HTMLElement new] appendNode:text]);
|
||||
XCTAssertNoThrow([[HTMLTemplate new] appendNode:text]);
|
||||
}
|
||||
|
||||
- (void)testValidDocumentFragmentInsertionIntoDocument
|
||||
{
|
||||
HTMLDocument *document = [HTMLDocument new];
|
||||
HTMLDocumentFragment *fragment = [[HTMLDocumentFragment alloc] initWithDocument:document];
|
||||
|
||||
void (^ reset)() = ^ {
|
||||
[fragment removeAllChildNodes];
|
||||
[document removeAllChildNodes];
|
||||
};
|
||||
|
||||
/**
|
||||
* Fragment has a Text node child
|
||||
*/
|
||||
[fragment appendNode:[HTMLText new]];
|
||||
XCTAssertThrows([document appendNode:fragment]);
|
||||
|
||||
/**
|
||||
* Fragment has more than one Element child
|
||||
*/
|
||||
reset();
|
||||
[fragment appendNode:[HTMLElement new]];
|
||||
[fragment appendNode:[HTMLElement new]];
|
||||
XCTAssertThrows([document appendNode:fragment]);
|
||||
|
||||
|
||||
/**
|
||||
* Fragment has one node child
|
||||
* Document has an Element child
|
||||
*/
|
||||
reset();
|
||||
[fragment appendNode:[HTMLElement new]];
|
||||
[document appendNode:[HTMLElement new]];
|
||||
XCTAssertThrows([document appendNode:fragment]);
|
||||
|
||||
/**
|
||||
* Fragment has one node child
|
||||
* "before child" is a Doctype
|
||||
*/
|
||||
reset();
|
||||
HTMLDocumentType *doctype = [HTMLDocumentType new];
|
||||
[fragment appendNode:[HTMLElement new]];
|
||||
[document appendNode:doctype];
|
||||
XCTAssertThrows([document insertNode:fragment beforeChildNode:doctype]);
|
||||
|
||||
/**
|
||||
* Fragment has one node child
|
||||
* "before child" is following a Doctype
|
||||
*/
|
||||
reset();
|
||||
HTMLComment *doctypePreviousSibling = [HTMLComment new];
|
||||
[fragment appendNode:[HTMLElement new]];
|
||||
[document appendNode:doctypePreviousSibling];
|
||||
[document appendNode:doctype];
|
||||
XCTAssertThrows([document insertNode:fragment beforeChildNode:doctypePreviousSibling]);
|
||||
}
|
||||
|
||||
- (void)testValidElementInsertionIntoDocument
|
||||
{
|
||||
HTMLDocument *document = [HTMLDocument new];
|
||||
HTMLElement *element = [HTMLElement new];
|
||||
|
||||
void (^ reset)() = ^ {
|
||||
[element removeAllChildNodes];
|
||||
[document removeAllChildNodes];
|
||||
};
|
||||
|
||||
/**
|
||||
* Document has an Element child
|
||||
*/
|
||||
[document appendNode:[HTMLElement new]];
|
||||
XCTAssertThrows([document appendNode:element]);
|
||||
|
||||
/**
|
||||
* "before child" is a Doctype
|
||||
*/
|
||||
reset();
|
||||
HTMLDocumentType *doctype = [HTMLDocumentType new];
|
||||
[document appendNode:doctype];
|
||||
XCTAssertThrows([document insertNode:element beforeChildNode:doctype]);
|
||||
|
||||
/**
|
||||
* Doctype is following the "before child"
|
||||
*/
|
||||
reset();
|
||||
HTMLComment *doctypePreviousSibling = [HTMLComment new];
|
||||
[document appendNode:doctypePreviousSibling];
|
||||
[document appendNode:doctype];
|
||||
XCTAssertThrows([document insertNode:element beforeChildNode:doctypePreviousSibling]);
|
||||
}
|
||||
|
||||
- (void)testValidDoctypeInsertionIntoDocument
|
||||
{
|
||||
HTMLDocument *document = [HTMLDocument new];
|
||||
HTMLDocumentType *doctype = [HTMLDocumentType new];
|
||||
|
||||
void (^ reset)() = ^ {
|
||||
[document removeAllChildNodes];
|
||||
};
|
||||
|
||||
/**
|
||||
* Document has a Doctype child
|
||||
*/
|
||||
[document appendNode:[HTMLDocumentType new]];
|
||||
XCTAssertThrows([document appendNode:doctype]);
|
||||
|
||||
/**
|
||||
* An Element is preceding the "before child"
|
||||
*/
|
||||
reset();
|
||||
HTMLComment *secondChild = [HTMLComment new];
|
||||
[document appendNode:[HTMLElement new]];
|
||||
[document appendNode:secondChild];
|
||||
XCTAssertThrows([document insertNode:doctype beforeChildNode:secondChild]);
|
||||
|
||||
/**
|
||||
* Document has an Element child
|
||||
*/
|
||||
reset();
|
||||
[document appendNode:[HTMLElement new]];
|
||||
XCTAssertThrows([document appendNode:doctype]);
|
||||
}
|
||||
|
||||
- (void)testValidDocumentFragmentReplacementIntoDocument
|
||||
{
|
||||
HTMLDocument *document = [HTMLDocument new];
|
||||
HTMLComment *child = [HTMLComment new];
|
||||
HTMLDocumentFragment *replacement = [[HTMLDocumentFragment alloc] initWithDocument:document];
|
||||
|
||||
void (^ reset)() = ^ {
|
||||
[replacement removeAllChildNodes];
|
||||
[document removeAllChildNodes];
|
||||
[document appendNode:child];
|
||||
};
|
||||
|
||||
/**
|
||||
* Replacement Fragment has a Text node child
|
||||
*/
|
||||
[replacement appendNode:[HTMLText new]];
|
||||
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
|
||||
|
||||
/**
|
||||
* Replacement Fragment has more than one Element child
|
||||
*/
|
||||
reset();
|
||||
[replacement appendNode:[HTMLElement new]];
|
||||
[replacement appendNode:[HTMLElement new]];
|
||||
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
|
||||
|
||||
/**
|
||||
* Replacement Fragment has one Element child
|
||||
* Document has an Element child that is not the Replacement
|
||||
*/
|
||||
reset();
|
||||
[replacement appendNode:[HTMLElement new]];
|
||||
[document appendNode:[HTMLElement new]];
|
||||
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
|
||||
|
||||
/**
|
||||
* Replacement Fragment has one Element child
|
||||
* Doctype is following the child node
|
||||
*/
|
||||
reset();
|
||||
HTMLDocumentType *doctype = [HTMLDocumentType new];
|
||||
[replacement appendNode:[HTMLElement new]];
|
||||
[document appendNode:doctype];
|
||||
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
|
||||
}
|
||||
|
||||
- (void)testValidElementReplacementIntoDocument
|
||||
{
|
||||
HTMLDocument *document = [HTMLDocument new];
|
||||
HTMLComment *child = [HTMLComment new];
|
||||
HTMLElement *replacement = [HTMLElement new];
|
||||
|
||||
void (^ reset)() = ^ {
|
||||
[replacement removeAllChildNodes];
|
||||
[document removeAllChildNodes];
|
||||
[document appendNode:child];
|
||||
};
|
||||
|
||||
/**
|
||||
* Docment has an Element child that is not replacement
|
||||
*/
|
||||
[document appendNode:[HTMLElement new]];
|
||||
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
|
||||
|
||||
/**
|
||||
* Doctype is following the child node
|
||||
*/
|
||||
reset();
|
||||
HTMLDocumentType *doctype = [HTMLDocumentType new];
|
||||
[document appendNode:doctype];
|
||||
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
|
||||
}
|
||||
|
||||
- (void)testValidDoctypeReplacementIntoDocument
|
||||
{
|
||||
HTMLDocument *document = [HTMLDocument new];
|
||||
HTMLComment *child = [HTMLComment new];
|
||||
HTMLDocumentType *replacement = [HTMLDocumentType new];
|
||||
|
||||
void (^ reset)() = ^ {
|
||||
[replacement removeAllChildNodes];
|
||||
[document removeAllChildNodes];
|
||||
[document appendNode:child];
|
||||
};
|
||||
|
||||
/**
|
||||
* Docment has an Doctype child that is not replacement
|
||||
*/
|
||||
[document appendNode:[HTMLDocumentType new]];
|
||||
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
|
||||
|
||||
/**
|
||||
* An Element is preceding the child node
|
||||
*/
|
||||
reset();
|
||||
[document insertNode:[HTMLElement new] beforeChildNode:child];
|
||||
XCTAssertThrows([document replaceChildNode:child withNode:replacement]);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,568 @@
|
||||
//
|
||||
// HTMLKitNodeTreeEnumratorTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 28/03/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "HTMLDOM.h"
|
||||
|
||||
@interface HTMLKitNodeIteratorTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation HTMLKitNodeIteratorTests
|
||||
|
||||
#pragma mark - Test DOM
|
||||
|
||||
- (HTMLElement *)div
|
||||
{
|
||||
return [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
}
|
||||
|
||||
- (HTMLElement *)simpleTree
|
||||
{
|
||||
/*
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
*/
|
||||
HTMLElement *div = self.div;
|
||||
[div appendNode:[[HTMLElement alloc] initWithTagName:@"a"]];
|
||||
[div appendNode:[[HTMLElement alloc] initWithTagName:@"b"]];
|
||||
[div appendNode:[[HTMLElement alloc] initWithTagName:@"c"]];
|
||||
return div;
|
||||
}
|
||||
|
||||
- (HTMLElement *)nestedSimpleTree
|
||||
{
|
||||
/*
|
||||
| div
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
*/
|
||||
HTMLElement *div = self.div;
|
||||
[div appendNode:self.simpleTree];
|
||||
[div appendNode:self.simpleTree];
|
||||
return div;
|
||||
}
|
||||
|
||||
- (HTMLElement *)complexTree
|
||||
{
|
||||
/*
|
||||
| div
|
||||
| div
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
| e
|
||||
| f
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
*/
|
||||
HTMLElement *root = self.div;
|
||||
|
||||
HTMLElement *div = self.div;
|
||||
[div appendNode:self.simpleTree];
|
||||
[root appendNode:div];
|
||||
|
||||
HTMLElement *e = [[HTMLElement alloc] initWithTagName:@"e"];
|
||||
[e appendNode:[[HTMLElement alloc] initWithTagName:@"f"]];
|
||||
[root appendNode:e];
|
||||
[root appendNode:self.simpleTree];
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
- (HTMLDocument *)mixedTree
|
||||
{
|
||||
|
||||
/*
|
||||
| doctype
|
||||
| #comment <!-- This is a Comment -->
|
||||
| #comment <!-- This is a second Comment -->
|
||||
| html
|
||||
| #text "This is a Text"
|
||||
| div
|
||||
*/
|
||||
HTMLDocument *document = [HTMLDocument new];
|
||||
document.documentType = [HTMLDocumentType new];;
|
||||
|
||||
HTMLComment *comment = [[HTMLComment alloc] initWithData:@"This is a Comment"];
|
||||
[document appendNode:comment];
|
||||
|
||||
HTMLComment *secondCommnet = [[HTMLComment alloc] initWithData:@"This is a second Comment"];
|
||||
[document appendNode:secondCommnet];
|
||||
|
||||
HTMLElement *root = [[HTMLElement alloc] initWithTagName:@"html"];
|
||||
[document appendNode:root];
|
||||
|
||||
[root appendNode:[[HTMLText alloc] initWithData:@"This is a Text"]];
|
||||
|
||||
[root appendNode:[[HTMLElement alloc] initWithTagName:@"div"]];
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
- (HTMLDocument *)document
|
||||
{
|
||||
NSString *htmlString =
|
||||
@"<!DOCTYPE html>"
|
||||
@"<html>"
|
||||
@"<head>"
|
||||
@"<title>Title</title>"
|
||||
@"</head>"
|
||||
@"<body>"
|
||||
@"<span>Hello<strong>World!</strong><strong>HTML <!-- This is a Comment! --> Kit</strong></span>"
|
||||
@"<p>This is an <em>Important</em> paragraph</p>"
|
||||
@"</body>"
|
||||
@"</html>";
|
||||
|
||||
HTMLDocument *document = [HTMLDocument documentWithString:htmlString];
|
||||
return document;
|
||||
}
|
||||
|
||||
#pragma mark - Test Iterator
|
||||
|
||||
- (void)testNodeIteratorInit
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
HTMLNodeIterator *iterator = tree.nodeIterator;
|
||||
|
||||
XCTAssertEqualObjects(iterator.root, tree);
|
||||
XCTAssertEqualObjects(iterator.referenceNode, tree);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
XCTAssertEqualObjects(iterator.filter, nil);
|
||||
XCTAssertEqual(iterator.whatToShow, HTMLNodeFilterShowAll);
|
||||
}
|
||||
|
||||
- (void)testNewIteratorNextNodeShouldBeRoot
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
HTMLNodeIterator *iterator = tree.nodeIterator;
|
||||
|
||||
XCTAssertEqualObjects(iterator.nextNode, tree);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
}
|
||||
|
||||
- (void)testNewIteratorPreviousNodeShouldBeNil
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
HTMLNodeIterator *iterator = tree.nodeIterator;
|
||||
|
||||
XCTAssertEqualObjects(iterator.previousNode, nil);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
}
|
||||
|
||||
- (void)testNewIteratorPreviousNodeShouldBeNextNode
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
HTMLNodeIterator *iterator = tree.nodeIterator;
|
||||
|
||||
HTMLNode *node = iterator.nextNode;
|
||||
|
||||
XCTAssertEqualObjects(iterator.previousNode, node);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
}
|
||||
|
||||
- (void)testNextPreviousIteration
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
HTMLNodeIterator *iterator = tree.nodeIterator;
|
||||
|
||||
XCTAssertEqualObjects(iterator.previousNode, nil);
|
||||
XCTAssertEqualObjects(iterator.nextNode.name, @"div");
|
||||
XCTAssertEqualObjects(iterator.nextNode.name, @"a");
|
||||
XCTAssertEqualObjects(iterator.previousNode.name, @"a");
|
||||
XCTAssertEqualObjects(iterator.previousNode.name, @"div");
|
||||
XCTAssertEqualObjects(iterator.nextNode.name, @"div");
|
||||
XCTAssertEqualObjects(iterator.nextNode.name, @"a");
|
||||
XCTAssertEqualObjects(iterator.nextNode.name, @"b");
|
||||
XCTAssertEqualObjects(iterator.nextNode.name, @"c");
|
||||
XCTAssertEqualObjects(iterator.previousNode.name, @"c");
|
||||
XCTAssertEqualObjects(iterator.previousNode.name, @"b");
|
||||
XCTAssertEqualObjects(iterator.previousNode.name, @"a");
|
||||
XCTAssertEqualObjects(iterator.previousNode.name, @"div");
|
||||
}
|
||||
|
||||
- (void)testSingleNodeIteration
|
||||
{
|
||||
HTMLElement *div = self.div;
|
||||
NSArray *result = div.nodeIterator.allObjects;
|
||||
NSArray *expected = @[@"div"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testSimpleTreeIteration
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
NSArray *result = tree.nodeIterator.allObjects;
|
||||
NSArray *expected = @[@"div", @"a", @"b", @"c"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testNestedSimpleTreeIteration
|
||||
{
|
||||
HTMLElement *tree = self.nestedSimpleTree;
|
||||
NSArray *result = tree.nodeIterator.allObjects;
|
||||
NSArray *expected = @[@"div", @"div", @"a", @"b", @"c", @"div", @"a", @"b", @"c"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testComplexTreeIteration
|
||||
{
|
||||
HTMLElement *tree = self.complexTree;
|
||||
NSArray *result = tree.nodeIterator.allObjects;
|
||||
NSArray *expected = @[@"div", @"div",@"div", @"a", @"b", @"c", @"e", @"f", @"div", @"a", @"b", @"c"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
#pragma mark - Test Iterator ShowOptions (WhatToShow)
|
||||
|
||||
- (void)testShowDocument
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowDocument filter:nil];
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"#document"];
|
||||
XCTAssertEqual(result.count, 1);
|
||||
XCTAssertEqual([result.firstObject class], [HTMLDocument class]);
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testShowDocumentType
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowDocumentType filter:nil];
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"html"];
|
||||
XCTAssertEqual(result.count, 1);
|
||||
XCTAssertEqual([result.firstObject class], [HTMLDocumentType class]);
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testShowComment
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowComment filter:nil];
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"#comment", @"#comment"];
|
||||
XCTAssertEqual(result.count, 2);
|
||||
XCTAssertEqual([result[0] class], [HTMLComment class]);
|
||||
XCTAssertEqual([result[1] class], [HTMLComment class]);
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testShowText
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowText filter:nil];
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"#text"];
|
||||
XCTAssertEqual(result.count, 1);
|
||||
XCTAssertEqual([result.firstObject class], [HTMLText class]);
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testShowElement
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil];
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"html", @"div"];
|
||||
XCTAssertEqual(result.count, 2);
|
||||
XCTAssertEqual([result.firstObject class], [HTMLElement class]);
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testShowBitmask
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowElement | HTMLNodeFilterShowText
|
||||
filter:nil];
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"html", @"#text", @"div"];
|
||||
XCTAssertEqual(result.count, 3);
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
#pragma mark - Test Iterator Filter
|
||||
|
||||
- (void)testNodeFilter
|
||||
{
|
||||
HTMLDocument *document = self.mixedTree;
|
||||
|
||||
HTMLNodeIterator *iterator = [document nodeIteratorWithShowOptions:HTMLNodeFilterShowAll
|
||||
filterBlock:^HTMLNodeFilterValue(HTMLNode *node) {
|
||||
if (node.nodeType == HTMLNodeComment) {
|
||||
if ([[(HTMLComment *)node data] rangeOfString:@"second"].location != NSNotFound) {
|
||||
return HTMLNodeFilterAccept;
|
||||
}
|
||||
}
|
||||
return HTMLNodeFilterSkip;
|
||||
}];
|
||||
|
||||
NSArray *result = iterator.allObjects;
|
||||
NSArray *expected = @[@"#comment"];
|
||||
XCTAssertEqual(result.count, 1);
|
||||
XCTAssertEqualObjects([result[0] data], @"This is a second Comment");
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
#pragma mark - Test Removing Steps
|
||||
|
||||
/*
|
||||
Test cases for the Removing Steps
|
||||
https://dom.spec.whatwg.org/#interface-nodeiterator
|
||||
|
||||
Following DOM is used:
|
||||
|
||||
| <html>
|
||||
| <head>
|
||||
| <title>
|
||||
| "Title"
|
||||
| <body>
|
||||
| <span>
|
||||
| "Hello"
|
||||
| <strong>
|
||||
| "World!"
|
||||
| <strong>
|
||||
| "HTML "
|
||||
| <!-- This is a Comment! -->
|
||||
| " Kit"
|
||||
| <p>
|
||||
| "This is an "
|
||||
| <em>
|
||||
| "Important"
|
||||
| " paragraph"
|
||||
*/
|
||||
|
||||
static void (^ RemoveThenInsertNode)(HTMLNode *) = ^ (HTMLNode *node) {
|
||||
HTMLNode *parent = node.parentNode;
|
||||
HTMLNode *nextSibling = node.nextSibling;
|
||||
[parent removeChildNode:node];
|
||||
[parent insertNode:node beforeChildNode:nextSibling];
|
||||
};
|
||||
|
||||
static void (^ IterateUpToNode)(HTMLNodeIterator *, HTMLNode *) = ^ (HTMLNodeIterator *iterator, HTMLNode *target) {
|
||||
for(HTMLNode *node = iterator.referenceNode; node && (node != target); node = iterator.nextNode);
|
||||
};
|
||||
|
||||
static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node) {
|
||||
while (node.lastChild) {
|
||||
node = node.lastChild;
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
- (void)testThatRemovingRootNodeShouldNotAffectIterator
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *node = document.body.firstChild; // <span>
|
||||
|
||||
HTMLNodeIterator *iterator = node.nodeIterator;
|
||||
|
||||
[document.body removeChildNode:node];
|
||||
|
||||
XCTAssertEqualObjects(iterator.root, node);
|
||||
XCTAssertEqualObjects(iterator.referenceNode, node);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
XCTAssertEqualObjects(iterator.referenceNode.parentNode, nil);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingANonInclusiveAnscestorOfReferenceShouldNotAffectIterator
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
HTMLNodeIterator *iterator = body.nodeIterator;
|
||||
|
||||
[iterator nextNode]; // Reference node: <body>
|
||||
[iterator nextNode]; // Reference node: <span>
|
||||
|
||||
RemoveThenInsertNode(iterator.root.childNodes[1]); // Remove <p>
|
||||
|
||||
XCTAssertEqualObjects(iterator.root, body);
|
||||
XCTAssertEqualObjects(iterator.referenceNode, body.firstChild);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingReferenceNodeShouldUpdateIterator_NilOldPreviousSibling
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
|
||||
HTMLNodeIterator *iterator = document.body.nodeIterator;
|
||||
|
||||
[iterator nextNode]; // Reference node: <body>
|
||||
|
||||
HTMLNode *node = iterator.nextNode; // Reference node: <span>
|
||||
RemoveThenInsertNode(node); // Remove <span> with old previos sibling being nil
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, iterator.root);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
|
||||
HTMLNode *next = iterator.nextNode; // "Hello"
|
||||
XCTAssertEqualObjects(next, iterator.root.firstChild);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingReferenceNodeShouldUpdateIterator_NonNilOldPreviousSibling_NotBeforeReference
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
HTMLNodeIterator *iterator = body.nodeIterator;
|
||||
|
||||
HTMLNode *node = iterator.root.childNodes[1]; // <p>
|
||||
IterateUpToNode(iterator, node); // Reference node: <p>, pointer-before-reference: NO
|
||||
RemoveThenInsertNode(node); // Remove <p> with old previos sibling being <span>
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, LastDescendant(body.firstChild));
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingReferenceNodeShouldUpdateIterator_NonNilOldPreviousSibling_BeforeReference
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
HTMLNodeIterator *iterator = body.nodeIterator;
|
||||
|
||||
HTMLNode *node = iterator.root.childNodes[1]; // <p>
|
||||
IterateUpToNode(iterator, node); // Reference node: <p>, pointer-before-reference: NO
|
||||
[iterator previousNode]; // pointer-before-reference: YES
|
||||
RemoveThenInsertNode(node); // Remove <p> with old previos sibling being <span>
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, body.firstChild);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingThenReinsertingReferenceNodeAfterNextShouldReturnItAgain
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNodeIterator *iterator = document.body.nodeIterator;
|
||||
|
||||
[iterator nextNode]; // Reference node: <body>
|
||||
|
||||
HTMLNode *node = iterator.nextNode; // <span>
|
||||
RemoveThenInsertNode(node);
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, iterator.root);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
|
||||
HTMLNode *next = iterator.nextNode;
|
||||
XCTAssertEqualObjects(next, node);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingThenReinsertingReferenceNodeAfterPreviousShouldReturnItAgain
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNodeIterator *iterator = document.body.nodeIterator;
|
||||
|
||||
[iterator nextNode]; // Reference node: <body>
|
||||
[iterator nextNode]; // Reference node: <span>
|
||||
|
||||
HTMLNode *node = iterator.previousNode; // Reference node: <span>, pointer-before-reference: YES
|
||||
HTMLNode *next = node.nextSibling; // <p>
|
||||
RemoveThenInsertNode(node);
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, next);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
|
||||
HTMLNode *previous = iterator.previousNode;
|
||||
XCTAssertEqualObjects(previous, LastDescendant(node));
|
||||
}
|
||||
|
||||
- (void)testThatRemovingParentOfReferenceNodeShouldUpdateIterator_NotBeforeReference
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
HTMLNodeIterator *iterator = body.nodeIterator;
|
||||
HTMLNode *parent = body.childNodes[1];
|
||||
|
||||
IterateUpToNode(iterator, parent); // Reference node: <p>, pointer-before-reference: NO
|
||||
[iterator nextNode]; // Reference node: "This is an "
|
||||
RemoveThenInsertNode(parent);
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, LastDescendant(body.firstChild));
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
}
|
||||
|
||||
- (void)testThatRemovingParentOfReferenceNodeShouldUpdateIterator_BeforeReference
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
HTMLNodeIterator *iterator = body.nodeIterator;
|
||||
HTMLNode *parent = body.childNodes[1];
|
||||
|
||||
IterateUpToNode(iterator, parent); // Reference node: <p>, pointer-before-reference: NO
|
||||
[iterator nextNode]; // Reference node: "This is an "
|
||||
[iterator previousNode]; // pointer-before-reference: YES
|
||||
RemoveThenInsertNode(parent);
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, body.firstChild);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
}
|
||||
|
||||
- (void)testRemoveReferenceNode_NilPreviousSibling_NonNilParentFirstChild
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
HTMLNodeIterator *iterator = body.nodeIterator;
|
||||
|
||||
[iterator nextNode]; // Reference node: <body>
|
||||
[iterator nextNode]; // Reference node: <span>
|
||||
|
||||
HTMLNode *node = iterator.previousNode; // Reference node: <span>, pointer-before-reference: YES
|
||||
XCTAssertNil(node.previousSibling);
|
||||
XCTAssertNotNil(node.nextSibling);
|
||||
|
||||
HTMLNode *nextSibling = node.nextSibling; // <p>
|
||||
RemoveThenInsertNode(node);
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, nextSibling);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, YES);
|
||||
|
||||
HTMLNode *next = iterator.nextNode; // <p>
|
||||
XCTAssertNotEqualObjects(next, node);
|
||||
XCTAssertEqualObjects(next, nextSibling);
|
||||
}
|
||||
|
||||
- (void)testRemoveReferenceNode_NodeAfterOldParentIsOutsideRoot_BeforeReference
|
||||
{
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNode *body = document.body;
|
||||
|
||||
body.innerHTML = @"<div><p><a></a></p></div><div></div>";
|
||||
|
||||
HTMLNodeIterator *iterator = body.firstChild.nodeIterator;
|
||||
|
||||
IterateUpToNode(iterator, LastDescendant(body.firstChild)); // Referecne node: <a>
|
||||
HTMLNode *node = [iterator previousNode]; // pointer-before-reference: YES
|
||||
RemoveThenInsertNode(node);
|
||||
|
||||
XCTAssertEqualObjects(iterator.referenceNode, iterator.root.firstChild);
|
||||
XCTAssertEqual(iterator.pointerBeforeReferenceNode, NO);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,148 +0,0 @@
|
||||
//
|
||||
// HTMLKitNodeTreeEnumratorTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 28/03/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "HTMLNodes.h"
|
||||
|
||||
@interface HTMLKitNodeTreeEnumratorTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation HTMLKitNodeTreeEnumratorTests
|
||||
|
||||
#pragma mark - Elements
|
||||
|
||||
- (HTMLElement *)div
|
||||
{
|
||||
return [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
}
|
||||
|
||||
- (HTMLElement *)simpleTree
|
||||
{
|
||||
/*
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
*/
|
||||
HTMLElement *div = self.div;
|
||||
[div appendNode:[[HTMLElement alloc] initWithTagName:@"a"]];
|
||||
[div appendNode:[[HTMLElement alloc] initWithTagName:@"b"]];
|
||||
[div appendNode:[[HTMLElement alloc] initWithTagName:@"c"]];
|
||||
return div;
|
||||
}
|
||||
|
||||
- (HTMLElement *)nestedSimpleTree
|
||||
{
|
||||
/*
|
||||
| div
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
*/
|
||||
HTMLElement *div = self.div;
|
||||
[div appendNode:self.simpleTree];
|
||||
[div appendNode:self.simpleTree];
|
||||
return div;
|
||||
}
|
||||
|
||||
- (HTMLElement *)complexTree
|
||||
{
|
||||
/*
|
||||
| div
|
||||
| div
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
| e
|
||||
| f
|
||||
| div
|
||||
| a
|
||||
| b
|
||||
| c
|
||||
*/
|
||||
HTMLElement *root = self.div;
|
||||
|
||||
HTMLElement *div = self.div;
|
||||
[div appendNode:self.simpleTree];
|
||||
[root appendNode:div];
|
||||
|
||||
HTMLElement *e = [[HTMLElement alloc] initWithTagName:@"e"];
|
||||
[e appendNode:[[HTMLElement alloc] initWithTagName:@"f"]];
|
||||
[root appendNode:e];
|
||||
[root appendNode:self.simpleTree];
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
#pragma mark - Tests
|
||||
|
||||
- (void)testSingle
|
||||
{
|
||||
HTMLElement *div = self.div;
|
||||
NSArray *result = div.treeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testSimpleTree
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
NSArray *result = tree.treeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div", @"a", @"b", @"c"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testSimpleTreeReversed
|
||||
{
|
||||
HTMLElement *tree = self.simpleTree;
|
||||
NSArray *result = tree.reverseTreeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div", @"c", @"b", @"a"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testNestedSimpleTree
|
||||
{
|
||||
HTMLElement *tree = self.nestedSimpleTree;
|
||||
NSArray *result = tree.treeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div", @"div", @"a", @"b", @"c", @"div", @"a", @"b", @"c"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testNestedSimpleTreeReversed
|
||||
{
|
||||
HTMLElement *tree = self.nestedSimpleTree;
|
||||
NSArray *result = tree.reverseTreeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div", @"div", @"c", @"b", @"a", @"div", @"c", @"b", @"a"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testComplexSimpleTree
|
||||
{
|
||||
HTMLElement *tree = self.complexTree;
|
||||
NSArray *result = tree.treeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div", @"div",@"div", @"a", @"b", @"c", @"e", @"f", @"div", @"a", @"b", @"c"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
- (void)testComplexSimpleTreeReversed
|
||||
{
|
||||
HTMLElement *tree = self.complexTree;
|
||||
NSArray *result = tree.reverseTreeEnumerator.allObjects;
|
||||
NSArray *expected = @[@"div", @"div", @"c", @"b", @"a", @"e", @"f", @"div", @"div", @"c", @"b", @"a"];
|
||||
XCTAssertEqualObjects([result valueForKey:@"name"], expected);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,485 @@
|
||||
//
|
||||
// HTMLKitNodesTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 20/04/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "HTMLDOM.h"
|
||||
|
||||
@interface HTMLKitNodesTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation HTMLKitNodesTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testInitNode
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
XCTAssertNotNil(node);
|
||||
XCTAssertEqualObjects(node.name, @"name");
|
||||
XCTAssertEqual(node.nodeType, HTMLNodeElement);
|
||||
XCTAssertNotNil(node.childNodes);
|
||||
XCTAssertEqual(node.childNodes.count, 0);
|
||||
|
||||
XCTAssertNil(node.ownerDocument);
|
||||
XCTAssertNil(node.parentNode);
|
||||
XCTAssertNil(node.parentElement);
|
||||
XCTAssertNil(node.firstChild);
|
||||
XCTAssertNil(node.lastChild);
|
||||
XCTAssertNil(node.previousSibling);
|
||||
XCTAssertNil(node.lastChild);
|
||||
}
|
||||
|
||||
- (void)testAppendNode
|
||||
{
|
||||
HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
HTMLComment *comment = [HTMLComment new];
|
||||
[element appendNode:comment];
|
||||
|
||||
XCTAssertEqual(element.childNodesCount, 1);
|
||||
XCTAssertEqual(element.firstChild, comment);
|
||||
|
||||
HTMLElement *firstElement = [HTMLElement new];
|
||||
HTMLElement *secondElement = [HTMLElement new];
|
||||
NSArray *nodes = @[firstElement, secondElement];
|
||||
|
||||
[element appendNodes:nodes];
|
||||
|
||||
XCTAssertEqual(element.childNodesCount, 3);
|
||||
XCTAssertEqual(element.firstChild, comment);
|
||||
XCTAssertEqual(element.lastChild, secondElement);
|
||||
}
|
||||
|
||||
- (void)testPrependNode
|
||||
{
|
||||
HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
HTMLText *text = [HTMLText new];
|
||||
[element appendNode:text];
|
||||
|
||||
HTMLComment *comment = [HTMLComment new];
|
||||
[element prependNode:comment];
|
||||
|
||||
XCTAssertEqual(element.childNodesCount, 2);
|
||||
XCTAssertEqual(element.firstChild, comment);
|
||||
|
||||
HTMLElement *firstElement = [HTMLElement new];
|
||||
HTMLElement *secondElement = [HTMLElement new];
|
||||
NSArray *nodes = @[firstElement, secondElement];
|
||||
|
||||
[element prependNodes:nodes];
|
||||
|
||||
XCTAssertEqual(element.childNodesCount, 4);
|
||||
XCTAssertEqual(element.firstChild, firstElement);
|
||||
XCTAssertEqual(element.lastChild, text);
|
||||
}
|
||||
|
||||
- (void)testAppendDocumentFragment
|
||||
{
|
||||
HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
HTMLComment *comment = [HTMLComment new];
|
||||
[element appendNode:comment];
|
||||
|
||||
HTMLDocumentFragment *fragment = [HTMLDocumentFragment new];
|
||||
HTMLElement *firstChild = [HTMLElement new];
|
||||
HTMLElement *secondChild = [HTMLElement new];
|
||||
[fragment appendNode:firstChild];
|
||||
[fragment appendNode:secondChild];
|
||||
|
||||
[element appendNode:fragment];
|
||||
XCTAssertEqual(element.childNodesCount, 3);
|
||||
XCTAssertEqual(fragment.childNodesCount, 0);
|
||||
|
||||
XCTAssertEqualObjects(firstChild.parentNode, element);
|
||||
XCTAssertEqualObjects(secondChild.parentNode, element);
|
||||
XCTAssertEqualObjects(element.firstChild, comment);
|
||||
XCTAssertEqualObjects(element.firstChild.nextSibling, firstChild);
|
||||
XCTAssertEqualObjects(element.lastChild.previousSibling, firstChild);
|
||||
XCTAssertEqualObjects(element.lastChild, secondChild);
|
||||
}
|
||||
|
||||
- (void)testParentNode
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
XCTAssertNil(firstChild.parentNode);
|
||||
|
||||
[node appendNode:firstChild];
|
||||
XCTAssertTrue(node.hasChildNodes);
|
||||
XCTAssertEqual(node.childNodesCount, 1);
|
||||
|
||||
XCTAssertNotNil(firstChild.parentNode);
|
||||
XCTAssertEqualObjects(firstChild.parentNode, node);
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
|
||||
[node appendNodes:@[secondChild, thirdChild]];
|
||||
XCTAssertTrue(node.hasChildNodes);
|
||||
XCTAssertEqual(node.childNodesCount, 3);
|
||||
|
||||
XCTAssertNotNil(secondChild.parentNode);
|
||||
XCTAssertEqualObjects(secondChild.parentNode, node);
|
||||
|
||||
XCTAssertNotNil(thirdChild.parentNode);
|
||||
XCTAssertEqualObjects(thirdChild.parentNode, node);
|
||||
}
|
||||
|
||||
- (void)testChildNodesCount
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
XCTAssertFalse(node.hasChildNodes);
|
||||
XCTAssertEqual(node.childNodesCount, 0);
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
XCTAssertTrue(node.hasChildNodes);
|
||||
XCTAssertEqual(node.childNodesCount, 1);
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
[node appendNode:secondChild];
|
||||
|
||||
XCTAssertTrue(node.hasChildNodes);
|
||||
XCTAssertEqual(node.childNodesCount, 2);
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
[node appendNode:thirdChild];
|
||||
|
||||
XCTAssertTrue(node.hasChildNodes);
|
||||
XCTAssertEqual(node.childNodesCount, 3);
|
||||
}
|
||||
|
||||
- (void)testFirstAndLastChildNodes
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
XCTAssertEqualObjects(node.firstChild, firstChild);
|
||||
XCTAssertEqualObjects(node.lastChild, firstChild);
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
[node appendNode:secondChild];
|
||||
|
||||
XCTAssertEqualObjects(node.firstChild, firstChild);
|
||||
XCTAssertEqualObjects(node.lastChild, secondChild);
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
[node appendNode:thirdChild];
|
||||
|
||||
XCTAssertEqualObjects(node.firstChild, firstChild);
|
||||
XCTAssertEqualObjects(node.lastChild, thirdChild);
|
||||
}
|
||||
|
||||
- (void)testNextAndPreviousSiblingNodes
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
[node appendNode:secondChild];
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
[node appendNode:thirdChild];
|
||||
|
||||
XCTAssertNil(firstChild.previousSibling);
|
||||
XCTAssertEqualObjects(firstChild.nextSibling, secondChild);
|
||||
|
||||
XCTAssertEqualObjects(secondChild.previousSibling, firstChild);
|
||||
XCTAssertEqualObjects(secondChild.nextSibling, thirdChild);
|
||||
|
||||
XCTAssertEqualObjects(thirdChild.previousSibling, secondChild);
|
||||
XCTAssertNil(thirdChild.nextSibling);
|
||||
}
|
||||
|
||||
- (void)testHasChildNodeOfType
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
XCTAssertFalse([node hasChildNodeOfType:HTMLNodeElement]);
|
||||
XCTAssertFalse([node hasChildNodeOfType:HTMLNodeText]);
|
||||
XCTAssertFalse([node hasChildNodeOfType:HTMLNodeComment]);
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
XCTAssertTrue([node hasChildNodeOfType:HTMLNodeElement]);
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeText];
|
||||
[node appendNode:secondChild];
|
||||
|
||||
XCTAssertTrue([node hasChildNodeOfType:HTMLNodeText]);
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeComment];
|
||||
[node appendNode:thirdChild];
|
||||
|
||||
XCTAssertTrue([node hasChildNodeOfType:HTMLNodeComment]);
|
||||
}
|
||||
|
||||
- (void)testChildNodeAtIndex
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
[node appendNode:secondChild];
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
[node appendNode:thirdChild];
|
||||
|
||||
XCTAssertEqualObjects([node childNodeAtIndex:0], firstChild);
|
||||
XCTAssertEqualObjects([node childNodeAtIndex:1], secondChild);
|
||||
XCTAssertEqualObjects([node childNodeAtIndex:2], thirdChild);
|
||||
}
|
||||
|
||||
- (void)testIndexOfChildNode
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
[node appendNode:secondChild];
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
[node appendNode:thirdChild];
|
||||
|
||||
XCTAssertEqual([node indexOfChildNode:firstChild], 0);
|
||||
XCTAssertEqual([node indexOfChildNode:secondChild], 1);
|
||||
XCTAssertEqual([node indexOfChildNode:thirdChild], 2);
|
||||
}
|
||||
|
||||
- (void)testIndertNodeBeforeChild
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
[node insertNode:secondChild beforeChildNode:firstChild];
|
||||
|
||||
XCTAssertEqual([node indexOfChildNode:firstChild], 1);
|
||||
XCTAssertEqual([node indexOfChildNode:secondChild], 0);
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
[node insertNode:thirdChild beforeChildNode:firstChild];
|
||||
|
||||
XCTAssertEqual([node indexOfChildNode:firstChild], 2);
|
||||
XCTAssertEqual([node indexOfChildNode:secondChild], 0);
|
||||
XCTAssertEqual([node indexOfChildNode:thirdChild], 1);
|
||||
}
|
||||
|
||||
- (void)testReplaceChildNode
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
[node appendNode:secondChild];
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
[node replaceChildNode:firstChild withNode:thirdChild];
|
||||
|
||||
XCTAssertNil(firstChild.parentNode);
|
||||
|
||||
XCTAssertEqual([node indexOfChildNode:firstChild], NSNotFound);
|
||||
XCTAssertEqual([node indexOfChildNode:secondChild], 1);
|
||||
XCTAssertEqual([node indexOfChildNode:thirdChild], 0);
|
||||
}
|
||||
|
||||
- (void)testReplaceAllChildNodes
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
[node appendNode:secondChild];
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
[node replaceAllChildNodesWithNode:thirdChild];
|
||||
|
||||
XCTAssertNil(firstChild.parentNode);
|
||||
XCTAssertNil(secondChild.parentNode);
|
||||
XCTAssertEqualObjects(thirdChild.parentNode, node);
|
||||
|
||||
XCTAssertEqual(node.childNodesCount, 1);
|
||||
XCTAssertEqual([node indexOfChildNode:thirdChild], 0);
|
||||
}
|
||||
|
||||
- (void)testRemoveFromParentNode
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
[firstChild removeFromParentNode];
|
||||
|
||||
XCTAssertNil(firstChild.parentNode);
|
||||
XCTAssertEqual(node.childNodesCount, 0);
|
||||
XCTAssertEqual([node indexOfChildNode:firstChild], NSNotFound);
|
||||
}
|
||||
|
||||
- (void)testRemoveChildNode
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
[node appendNode:secondChild];
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
[node appendNode:thirdChild];
|
||||
|
||||
[node removeChildNode:secondChild];
|
||||
XCTAssertEqual(node.childNodesCount, 2);
|
||||
|
||||
XCTAssertEqualObjects(firstChild.parentNode, node);
|
||||
XCTAssertNil(secondChild.parentNode);
|
||||
XCTAssertEqualObjects(thirdChild.parentNode, node);
|
||||
|
||||
XCTAssertEqual([node indexOfChildNode:firstChild], 0);
|
||||
XCTAssertEqual([node indexOfChildNode:secondChild], NSNotFound);
|
||||
XCTAssertEqual([node indexOfChildNode:thirdChild], 1);
|
||||
|
||||
[node removeChildNode:firstChild];
|
||||
XCTAssertEqual(node.childNodesCount, 1);
|
||||
|
||||
XCTAssertNil(firstChild.parentNode);
|
||||
XCTAssertNil(secondChild.parentNode);
|
||||
XCTAssertEqualObjects(thirdChild.parentNode, node);
|
||||
|
||||
XCTAssertEqual([node indexOfChildNode:firstChild], NSNotFound);
|
||||
XCTAssertEqual([node indexOfChildNode:secondChild], NSNotFound);
|
||||
XCTAssertEqual([node indexOfChildNode:thirdChild], 0);
|
||||
}
|
||||
|
||||
- (void)testRemoveChildNodeAtIndex
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
[node appendNode:secondChild];
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
[node appendNode:thirdChild];
|
||||
|
||||
[node removeChildNodeAtIndex:1];
|
||||
XCTAssertEqual(node.childNodesCount, 2);
|
||||
|
||||
XCTAssertEqualObjects(firstChild.parentNode, node);
|
||||
XCTAssertNil(secondChild.parentNode);
|
||||
XCTAssertEqualObjects(thirdChild.parentNode, node);
|
||||
|
||||
XCTAssertEqual([node indexOfChildNode:firstChild], 0);
|
||||
XCTAssertEqual([node indexOfChildNode:secondChild], NSNotFound);
|
||||
XCTAssertEqual([node indexOfChildNode:thirdChild], 1);
|
||||
|
||||
[node removeChildNodeAtIndex:0];
|
||||
XCTAssertEqual(node.childNodesCount, 1);
|
||||
|
||||
XCTAssertNil(firstChild.parentNode);
|
||||
XCTAssertNil(secondChild.parentNode);
|
||||
XCTAssertEqualObjects(thirdChild.parentNode, node);
|
||||
|
||||
XCTAssertEqual([node indexOfChildNode:firstChild], NSNotFound);
|
||||
XCTAssertEqual([node indexOfChildNode:secondChild], NSNotFound);
|
||||
XCTAssertEqual([node indexOfChildNode:thirdChild], 0);
|
||||
}
|
||||
|
||||
- (void)testRemoveAllChildNodes
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
[node appendNode:secondChild];
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
[node appendNode:thirdChild];
|
||||
|
||||
[node removeAllChildNodes];
|
||||
XCTAssertEqual(node.childNodesCount, 0);
|
||||
|
||||
XCTAssertNil(firstChild.parentNode);
|
||||
XCTAssertNil(secondChild.parentNode);
|
||||
XCTAssertNil(thirdChild.parentNode);
|
||||
|
||||
XCTAssertEqual([node indexOfChildNode:firstChild], NSNotFound);
|
||||
XCTAssertEqual([node indexOfChildNode:secondChild], NSNotFound);
|
||||
XCTAssertEqual([node indexOfChildNode:thirdChild], NSNotFound);
|
||||
}
|
||||
|
||||
- (void)testReparentChildNodes
|
||||
{
|
||||
HTMLNode *node = [[HTMLNode alloc] initWithName:@"name" type:HTMLNodeElement];
|
||||
|
||||
HTMLNode *firstChild = [[HTMLNode alloc] initWithName:@"first" type:HTMLNodeElement];
|
||||
[node appendNode:firstChild];
|
||||
|
||||
HTMLNode *secondChild = [[HTMLNode alloc] initWithName:@"second" type:HTMLNodeElement];
|
||||
[node appendNode:secondChild];
|
||||
|
||||
HTMLNode *thirdChild = [[HTMLNode alloc] initWithName:@"third" type:HTMLNodeElement];
|
||||
[node appendNode:thirdChild];
|
||||
|
||||
HTMLNode *newParent = [[HTMLNode alloc] initWithName:@"new-parent" type:HTMLNodeElement];
|
||||
|
||||
[node reparentChildNodesIntoNode:newParent];
|
||||
XCTAssertEqual(node.childNodesCount, 0);
|
||||
|
||||
XCTAssertEqual([node indexOfChildNode:firstChild], NSNotFound);
|
||||
XCTAssertEqual([node indexOfChildNode:secondChild], NSNotFound);
|
||||
XCTAssertEqual([node indexOfChildNode:thirdChild], NSNotFound);
|
||||
|
||||
XCTAssertEqualObjects(firstChild.parentNode, newParent);
|
||||
XCTAssertEqualObjects(secondChild.parentNode, newParent);
|
||||
XCTAssertEqualObjects(thirdChild.parentNode, newParent);
|
||||
}
|
||||
|
||||
- (void)testElementSetInnerHTML
|
||||
{
|
||||
HTMLElement *element = [[HTMLElement alloc] initWithTagName:@"div"];
|
||||
[element appendNode:[[HTMLElement alloc] initWithTagName:@"img"]];
|
||||
|
||||
[element setInnerHTML:@"<p></p><p></p>"];
|
||||
|
||||
XCTAssertEqual(element.childNodesCount, 2);
|
||||
|
||||
XCTAssertEqualObjects(element.firstChild.asElement.tagName, @"p");
|
||||
XCTAssertEqualObjects([element childNodeAtIndex:1].asElement.tagName, @"p");
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -38,9 +38,6 @@
|
||||
[_dictionary setObject:@"3" forKey:@"C"];
|
||||
expected = @[@"A", @"B", @"C"];
|
||||
XCTAssertEqualObjects(_dictionary.keyEnumerator.allObjects, expected);
|
||||
|
||||
XCTAssertThrows([_dictionary setObject:nil forKey:@"Key"]);
|
||||
XCTAssertThrows([_dictionary setObject:@"Object" forKey:nil]);
|
||||
}
|
||||
|
||||
- (void)testIndexOfKey
|
||||
@@ -51,7 +48,6 @@
|
||||
XCTAssertEqual([_dictionary indexOfKey:@"A"], 0);
|
||||
XCTAssertEqual([_dictionary indexOfKey:@"B"], 1);
|
||||
XCTAssertEqual([_dictionary indexOfKey:@"C"], 2);
|
||||
XCTAssertEqual([_dictionary indexOfKey:nil], NSNotFound);
|
||||
}
|
||||
|
||||
- (void)testObjectAtIndex
|
||||
@@ -64,8 +60,6 @@
|
||||
[_dictionary setObject:@"3" forKey:@"C" atIndex:1];
|
||||
XCTAssertEqualObjects([_dictionary objectAtIndex:1], @"3");
|
||||
|
||||
XCTAssertThrows([_dictionary setObject:nil forKey:@"Key" atIndex:0]);
|
||||
XCTAssertThrows([_dictionary setObject:@"Object" forKey:nil atIndex:0]);
|
||||
XCTAssertThrows([_dictionary setObject:@"Object" forKey:@"Key" atIndex:100]);
|
||||
}
|
||||
|
||||
@@ -120,8 +114,6 @@
|
||||
XCTAssertEqualObjects(_dictionary[2], @"5");
|
||||
XCTAssertEqualObjects(_dictionary[@"A"], @"5");
|
||||
|
||||
XCTAssertThrows([_dictionary setObject:nil forKey:@"Key" atIndex:0]);
|
||||
XCTAssertThrows([_dictionary setObject:@"Object" forKey:nil atIndex:0]);
|
||||
XCTAssertThrows([_dictionary setObject:@"Object" forKey:@"Key" atIndex:100]);
|
||||
}
|
||||
|
||||
@@ -158,8 +150,6 @@
|
||||
XCTAssertEqualObjects(_dictionary[0], @"5");
|
||||
XCTAssertEqualObjects(_dictionary[@"E"], @"5");
|
||||
|
||||
XCTAssertThrows([_dictionary replaceKeyValueAtIndex:1 withObject:nil andKey:@"Key"]);
|
||||
XCTAssertThrows([_dictionary replaceKeyValueAtIndex:1 withObject:@"Object" andKey:nil]);
|
||||
XCTAssertThrows([_dictionary replaceKeyValueAtIndex:100 withObject:@"Object" andKey:@"Key"]);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
@implementation HTMLKitParserPerformance
|
||||
|
||||
#define HTMLKIT_NO_DOM_CHECKS
|
||||
|
||||
- (void)testParserPerformance
|
||||
{
|
||||
NSString *path = [[NSBundle bundleForClass:self.class] resourcePath];
|
||||
@@ -28,4 +30,6 @@
|
||||
}];
|
||||
}
|
||||
|
||||
#undef HTMLKIT_NO_DOM_CHECKS
|
||||
|
||||
@end
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "HTML5LibTreeConstructionTest.h"
|
||||
#import "HTMLNodes.h"
|
||||
#import "HTMLDOM.h"
|
||||
#import "HTMLParser.h"
|
||||
|
||||
|
||||
@@ -96,8 +96,8 @@
|
||||
actual = [parser parseFragmentWithContextElement:contextElement];
|
||||
}
|
||||
|
||||
NSString *expectedNodes = [[test.nodes valueForKey:@"debugDescription"] componentsJoinedByString:@"\n"];
|
||||
NSString *actualNodes = [[parser.document.childNodes.array valueForKey:@"debugDescription"] componentsJoinedByString:@"\n"];
|
||||
NSString *expectedNodes = [[test.nodes valueForKey:@"treeDescription"] componentsJoinedByString:@"\n"];
|
||||
NSString *actualNodes = [[actual valueForKey:@"treeDescription"] componentsJoinedByString:@"\n"];
|
||||
|
||||
NSString *message = [NSString stringWithFormat:@"HTML5Lib test in file: \'%@\'\nInput:\n%@\nExpected:\n%@\nActual:\n%@\n",
|
||||
test.testFile,
|
||||
@@ -121,14 +121,14 @@
|
||||
{
|
||||
XCTAssertEqualObjects(actual.name, expected.name, @"Node name mismatch [%@ should be %@]:\n%@",
|
||||
actual.name, expected.name, message);
|
||||
XCTAssert(actual.type == expected.type, @"Node type mismatch [%hd should be %hd]:\n%@",
|
||||
actual.type, expected.type, message);
|
||||
XCTAssert(actual.nodeType == expected.nodeType, @"Node type mismatch [%hd should be %hd]:\n%@",
|
||||
actual.nodeType, expected.nodeType, message);
|
||||
|
||||
if (actual.type != expected.type) {
|
||||
if (actual.nodeType != expected.nodeType) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (actual.type) {
|
||||
switch (actual.nodeType) {
|
||||
case HTMLNodeDocumentType:
|
||||
XCTAssertEqualObjects([(HTMLDocumentType *)actual publicIdentifier], [(HTMLDocumentType *)expected publicIdentifier], @"%@", message);
|
||||
XCTAssertEqualObjects([(HTMLDocumentType *)actual systemIdentifier], [(HTMLDocumentType *)expected systemIdentifier], @"%@", message);
|
||||
|
||||
@@ -0,0 +1,503 @@
|
||||
//
|
||||
// HTMLTreeWalkerTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 05/06/15.
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "HTMLTreeWalker.h"
|
||||
#import "HTMLDOM.h"
|
||||
|
||||
@interface HTMLTreeWalkerTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation HTMLTreeWalkerTests
|
||||
|
||||
#pragma mark - Asserts
|
||||
|
||||
#define AssertElementWithId(input, id) \
|
||||
do { \
|
||||
HTMLNode *node = input;\
|
||||
XCTAssertEqual(node.nodeType, HTMLNodeElement);\
|
||||
XCTAssertEqualObjects(node.asElement[@"id"], id);\
|
||||
} while(0)
|
||||
|
||||
#define AssertTextWithValue(input, value) \
|
||||
do { \
|
||||
HTMLNode *node = input;\
|
||||
XCTAssertEqual(node.nodeType, HTMLNodeText);\
|
||||
XCTAssertEqualObjects(node.textContent, value);\
|
||||
} while(0)
|
||||
|
||||
#define AssertCommentWithValue(input, value) \
|
||||
do { \
|
||||
HTMLNode *node = input;\
|
||||
XCTAssertEqual(node.nodeType, HTMLNodeComment);\
|
||||
XCTAssertEqualObjects(node.textContent, value);\
|
||||
} while(0)
|
||||
|
||||
#pragma mark - Tests
|
||||
|
||||
- (void)testTreeWalkerInit
|
||||
{
|
||||
HTMLNode *root = self.basicWalkingDOM;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root];
|
||||
|
||||
XCTAssertNotNil(walker);
|
||||
XCTAssertNotNil(walker.root);
|
||||
XCTAssertNotNil(walker.currentNode);
|
||||
XCTAssertNil(walker.filter);
|
||||
XCTAssertEqual(walker.whatToShow, HTMLNodeFilterShowAll);
|
||||
|
||||
XCTAssertEqualObjects(walker.root, root);
|
||||
XCTAssertEqualObjects(walker.root, walker.currentNode);
|
||||
}
|
||||
|
||||
#pragma mark - Basic Walking
|
||||
|
||||
- (HTMLNode *)basicWalkingDOM
|
||||
{
|
||||
// Tree structure:
|
||||
// #a
|
||||
// |
|
||||
// +----+----+
|
||||
// | |
|
||||
// "b" #c
|
||||
// |
|
||||
// +----+----+
|
||||
// | |
|
||||
// #d <!--j-->
|
||||
// |
|
||||
// +----+----+
|
||||
// | | |
|
||||
// "e" #f "i"
|
||||
// |
|
||||
// +--+--+
|
||||
// | |
|
||||
// "g" <!--h-->
|
||||
|
||||
HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"a"}];
|
||||
|
||||
[div appendNode:[[HTMLText alloc] initWithData:@"b"]];
|
||||
|
||||
HTMLElement *c = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"c"}];
|
||||
[div appendNode:c];
|
||||
|
||||
HTMLElement *d = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"d"}];
|
||||
[c appendNode:d];
|
||||
[c appendNode:[[HTMLComment alloc] initWithData:@"j"]];
|
||||
|
||||
[d appendNode:[[HTMLText alloc] initWithData:@"e"]];
|
||||
|
||||
HTMLElement *f = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"f"}];
|
||||
[d appendNode:f];
|
||||
[d appendNode:[[HTMLText alloc] initWithData:@"i"]];
|
||||
|
||||
[f appendNode:[[HTMLText alloc] initWithData:@"g"]];
|
||||
[f appendNode:[[HTMLComment alloc] initWithData:@"h"]];
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
- (void)testBasicWalking
|
||||
{
|
||||
HTMLNode *root = self.basicWalkingDOM;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root];
|
||||
|
||||
HTMLNode *f = root.lastChild.firstChild.childNodes[1];
|
||||
|
||||
AssertElementWithId(walker.currentNode, @"a");
|
||||
XCTAssertNil(walker.parentNode);
|
||||
AssertElementWithId(walker.currentNode, @"a");
|
||||
|
||||
AssertTextWithValue(walker.firstChild, @"b");
|
||||
AssertTextWithValue(walker.currentNode, @"b");
|
||||
|
||||
AssertElementWithId(walker.nextSibling, @"c");
|
||||
AssertElementWithId(walker.currentNode, @"c");
|
||||
|
||||
AssertCommentWithValue(walker.lastChild, @"j");
|
||||
AssertCommentWithValue(walker.currentNode, @"j");
|
||||
|
||||
AssertElementWithId(walker.previousSibling, @"d");
|
||||
AssertElementWithId(walker.currentNode, @"d");
|
||||
|
||||
AssertTextWithValue(walker.nextNode, @"e");
|
||||
AssertTextWithValue(walker.currentNode, @"e");
|
||||
|
||||
AssertElementWithId(walker.parentNode, @"d");
|
||||
AssertElementWithId(walker.currentNode, @"d");
|
||||
|
||||
AssertElementWithId(walker.previousNode, @"c");
|
||||
AssertElementWithId(walker.currentNode, @"c");
|
||||
|
||||
XCTAssertNil(walker.nextSibling);
|
||||
AssertElementWithId(walker.currentNode, @"c");
|
||||
|
||||
walker.currentNode = f;
|
||||
XCTAssertEqualObjects(walker.currentNode, f);
|
||||
}
|
||||
|
||||
#pragma mark - Current Node
|
||||
|
||||
- (HTMLDocument *)currentNodeDOM
|
||||
{
|
||||
HTMLDocument *document = [HTMLDocument documentWithString:
|
||||
@"<div id='first'><p><a></a></p></div>"
|
||||
@"<div id='second'><p><b></b></p</div>"];
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
- (void)testThatTreeWalkerParentHasNoEffectCurrentNodeWhenParentIsNotUnderRoot
|
||||
{
|
||||
HTMLDocument *document = self.currentNodeDOM;
|
||||
HTMLNode *first = document.body.firstChild;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:first
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:nil];
|
||||
|
||||
AssertElementWithId(walker.currentNode, @"first");
|
||||
XCTAssertNil(walker.parentNode);
|
||||
AssertElementWithId(walker.currentNode, @"first");
|
||||
}
|
||||
|
||||
- (void)testThatSettingCurrentNodeToNodesNotUnderRootIsHandledCorrectly
|
||||
{
|
||||
HTMLDocument *document = self.currentNodeDOM;
|
||||
HTMLNode *first = document.body.firstChild;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:first
|
||||
showOptions:HTMLNodeFilterShowElement|HTMLNodeFilterShowComment
|
||||
filter:nil];
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertNil(walker.parentNode);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement);
|
||||
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertEqualObjects(walker.nextNode, document.documentElement.firstChild);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement.firstChild);
|
||||
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertNil(walker.previousNode);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement);
|
||||
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertEqualObjects(walker.firstChild, document.documentElement.firstChild);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement.firstChild);
|
||||
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertEqualObjects(walker.lastChild, document.documentElement.lastChild);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement.lastChild);
|
||||
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertNil(walker.nextSibling);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement);
|
||||
|
||||
walker.currentNode = document.documentElement;
|
||||
XCTAssertNil(walker.previousSibling);
|
||||
XCTAssertEqualObjects(walker.currentNode, document.documentElement);
|
||||
}
|
||||
|
||||
#pragma mark - Filter
|
||||
|
||||
- (HTMLElement *)filterBasicDOM
|
||||
{
|
||||
HTMLElement *root = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"root"}];
|
||||
|
||||
HTMLElement *a1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"A1"}];
|
||||
HTMLElement *b1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B1"}];
|
||||
HTMLElement *b2 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B2"}];
|
||||
|
||||
[root appendNode:a1];
|
||||
[a1 appendNode:b1];
|
||||
[a1 appendNode:b2];
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
- (void)testTreeWalkerNilFilter
|
||||
{
|
||||
HTMLElement *root = self.filterBasicDOM;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:nil];
|
||||
|
||||
AssertElementWithId(walker.currentNode, @"root");
|
||||
AssertElementWithId(walker.firstChild, @"A1");
|
||||
AssertElementWithId(walker.currentNode, @"A1");
|
||||
AssertElementWithId(walker.nextNode, @"B1");
|
||||
AssertElementWithId(walker.currentNode, @"B1");
|
||||
}
|
||||
|
||||
- (void)testTreeWalkerWithFilter
|
||||
{
|
||||
HTMLElement *root = self.filterBasicDOM;
|
||||
|
||||
id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) {
|
||||
if ([node.asElement[@"id"] isEqualToString:@"B1"]) {
|
||||
return HTMLNodeFilterSkip;
|
||||
}
|
||||
return HTMLNodeFilterAccept;
|
||||
}];
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.currentNode, @"root");
|
||||
AssertElementWithId(walker.firstChild, @"A1");
|
||||
AssertElementWithId(walker.currentNode, @"A1");
|
||||
AssertElementWithId(walker.nextNode, @"B2");
|
||||
AssertElementWithId(walker.currentNode, @"B2");
|
||||
}
|
||||
|
||||
#pragma mark - Filter Skip
|
||||
|
||||
- (HTMLElement *)filterDOM
|
||||
{
|
||||
HTMLElement *root = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"root"}];
|
||||
|
||||
HTMLElement *a1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"A1"}];
|
||||
HTMLElement *b1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B1"}];
|
||||
HTMLElement *b2 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B2"}];
|
||||
HTMLElement *b3 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"B3"}];
|
||||
HTMLElement *c1 = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"C1"}];
|
||||
|
||||
[root appendNode:a1];
|
||||
[a1 appendNode:b1];
|
||||
[a1 appendNode:b2];
|
||||
[a1 appendNode:b3];
|
||||
[b1 appendNode:c1];
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
- (id<HTMLNodeFilter>)skipB1Filter
|
||||
{
|
||||
id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) {
|
||||
if ([node.asElement[@"id"] isEqualToString:@"B1"]) {
|
||||
return HTMLNodeFilterSkip;
|
||||
}
|
||||
return HTMLNodeFilterAccept;
|
||||
}];
|
||||
return filter;
|
||||
}
|
||||
|
||||
- (id<HTMLNodeFilter>)skipB2Filter
|
||||
{
|
||||
id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) {
|
||||
if ([node.asElement[@"id"] isEqualToString:@"B2"]) {
|
||||
return HTMLNodeFilterSkip;
|
||||
}
|
||||
return HTMLNodeFilterAccept;
|
||||
}];
|
||||
return filter;
|
||||
}
|
||||
|
||||
- (id<HTMLNodeFilter>)rejectB1Filter
|
||||
{
|
||||
id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) {
|
||||
if ([node.asElement[@"id"] isEqualToString:@"B1"]) {
|
||||
return HTMLNodeFilterReject;
|
||||
}
|
||||
return HTMLNodeFilterAccept;
|
||||
}];
|
||||
return filter;
|
||||
}
|
||||
|
||||
- (id<HTMLNodeFilter>)rejectB2Filter
|
||||
{
|
||||
id<HTMLNodeFilter> filter = [HTMLNodeFilterBlock filterWithBlock:^HTMLNodeFilterValue(HTMLNode *node) {
|
||||
if ([node.asElement[@"id"] isEqualToString:@"B2"]) {
|
||||
return HTMLNodeFilterReject;
|
||||
}
|
||||
return HTMLNodeFilterAccept;
|
||||
}];
|
||||
return filter;
|
||||
}
|
||||
|
||||
static HTMLElement * (^ FindElementById)(HTMLNode *, NSString *) = ^ HTMLElement * (HTMLNode *root, NSString *id) {
|
||||
for (HTMLNode *node in [root nodeIteratorWithShowOptions:HTMLNodeFilterShowElement filter:nil]) {
|
||||
if ([node.asElement[@"id"] isEqualToString:id]) {
|
||||
return node.asElement;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
};
|
||||
|
||||
- (void)testThatFilterSkipsNextNode
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.skipB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.nextNode, @"A1");
|
||||
AssertElementWithId(walker.nextNode, @"C1");
|
||||
AssertElementWithId(walker.nextNode, @"B2");
|
||||
AssertElementWithId(walker.nextNode, @"B3");
|
||||
}
|
||||
|
||||
- (void)testThatFilterSkipsFirstChild
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.skipB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.firstChild, @"A1");
|
||||
AssertElementWithId(walker.firstChild, @"C1");
|
||||
}
|
||||
|
||||
- (void)testThatFilterSkipsNextSibling
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.skipB2Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.firstChild, @"A1");
|
||||
AssertElementWithId(walker.firstChild, @"B1");
|
||||
AssertElementWithId(walker.nextSibling, @"B3");
|
||||
}
|
||||
|
||||
- (void)testThatFilterSkipsParentNode
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.skipB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
walker.currentNode = FindElementById(root, @"C1");
|
||||
AssertElementWithId(walker.parentNode, @"A1");
|
||||
}
|
||||
|
||||
- (void)testThatFilterSkipsPreviousSibling
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.skipB2Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
walker.currentNode = FindElementById(root, @"B3");
|
||||
AssertElementWithId(walker.previousSibling, @"B1");
|
||||
}
|
||||
|
||||
- (void)testThatFilterSkipsPreviousNode
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.skipB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
walker.currentNode = FindElementById(root, @"B3");
|
||||
AssertElementWithId(walker.previousNode, @"B2");
|
||||
AssertElementWithId(walker.previousNode, @"C1");
|
||||
AssertElementWithId(walker.previousNode, @"A1");
|
||||
}
|
||||
|
||||
#pragma mark - Filter Reject
|
||||
|
||||
- (void)testThatFilterRejectsNextNode
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.rejectB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.nextNode, @"A1");
|
||||
AssertElementWithId(walker.nextNode, @"B2");
|
||||
AssertElementWithId(walker.nextNode, @"B3");
|
||||
}
|
||||
|
||||
- (void)testThatFilterRejectsFirstChild
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.rejectB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.firstChild, @"A1");
|
||||
AssertElementWithId(walker.firstChild, @"B2");
|
||||
}
|
||||
|
||||
- (void)testThatFilterRejectsNextSibling
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.rejectB2Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
AssertElementWithId(walker.firstChild, @"A1");
|
||||
AssertElementWithId(walker.firstChild, @"B1");
|
||||
AssertElementWithId(walker.nextSibling, @"B3");
|
||||
}
|
||||
|
||||
- (void)testThatFilterRejectsParentNode
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.rejectB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
walker.currentNode = FindElementById(root, @"C1");
|
||||
AssertElementWithId(walker.parentNode, @"A1");
|
||||
}
|
||||
|
||||
- (void)testThatFilterRejectsPreviousSibling
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.rejectB2Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
walker.currentNode = FindElementById(root, @"B3");
|
||||
AssertElementWithId(walker.previousSibling, @"B1");
|
||||
}
|
||||
|
||||
- (void)testThatFilterRejectsPreviousNode
|
||||
{
|
||||
HTMLElement *root = self.filterDOM;
|
||||
id<HTMLNodeFilter> filter = self.rejectB1Filter;
|
||||
|
||||
HTMLTreeWalker *walker = [[HTMLTreeWalker alloc] initWithNode:root
|
||||
showOptions:HTMLNodeFilterShowElement
|
||||
filter:filter];
|
||||
|
||||
walker.currentNode = FindElementById(root, @"B3");
|
||||
AssertElementWithId(walker.previousNode, @"B2");
|
||||
AssertElementWithId(walker.previousNode, @"A1");
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "li,p",
|
||||
"match": ["1", "2", "3"]
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<ul>
|
||||
<li id="1">The background of this list item should be green</li>
|
||||
<li id="2">The background of this second list item should be also green</li>
|
||||
</ul>
|
||||
<p id="3">The background of this paragraph should be green.</p>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "p[title$=\"bar\"]",
|
||||
"match": ["1"]
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<p id="1" title="foobar">This paragraph should have a green background because its title attribute ends with "bar"</p>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "p[title*=\"bar\"]",
|
||||
"match": ["1"]
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<p id="1" title="foobarufoo">This paragraph should have a green background because its title attribute contains "bar"</p>
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": ".t1",
|
||||
"match": ["1"]
|
||||
},
|
||||
{
|
||||
"selector": "li.t2",
|
||||
"match": ["2", "3"]
|
||||
},
|
||||
{
|
||||
"selector": ".t3",
|
||||
"match": []
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<ul>
|
||||
<li id="1" class="t1">This list item should have green background because its class is "t1"</li>
|
||||
<li id="2" class="t2">This list item should have green background because its class is "t2"</li>
|
||||
<li id="3" class="t2">
|
||||
<span id="4" class="t33">This list item should have green background because the inner SPAN does not match SPAN.t3</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,30 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "p.t1",
|
||||
"match": ["1"]
|
||||
},
|
||||
{
|
||||
"selector": "p.t2",
|
||||
"match": ["1"]
|
||||
},
|
||||
{
|
||||
"selector": "div.teST",
|
||||
"match": []
|
||||
},
|
||||
{
|
||||
"selector": "div.te",
|
||||
"match": []
|
||||
},
|
||||
{
|
||||
"selector": "div.st",
|
||||
"match": []
|
||||
},
|
||||
{
|
||||
"selector": "div.te.st",
|
||||
"match": []
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<p id="1" class="t1 t2">This paragraph should have a green background and a green thick solid border because it carries both classes t1 and t2.</p>
|
||||
<div id="2" class="test">This line should be green.</div>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "div :not(:enabled):not(:disabled)",
|
||||
"match": ["1", "2"]
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<div id="1">
|
||||
<p id="2">This paragraph should have a green background.</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "p:empty",
|
||||
"match": []
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<p id="1">This line should have a green background.</p>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "address:empty",
|
||||
"match": ["1"]
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<address id="1"></address>
|
||||
<div id="2" class="text">This line should have a green background.</div>
|
||||
</div>
|
||||
@@ -0,0 +1,22 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": ".t1.fail",
|
||||
"match": []
|
||||
},
|
||||
{
|
||||
"selector": ".fail.t2",
|
||||
"match": []
|
||||
},
|
||||
{
|
||||
"selector": ".t2.fail",
|
||||
"match": []
|
||||
},
|
||||
{
|
||||
"selector": ".fail.t2",
|
||||
"match": []
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<p id="1" class="t1">This line should be green.</p>
|
||||
<p id="2" class="t1 t2">This line should be green.</p>
|
||||
</div>
|
||||
@@ -0,0 +1,19 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "p.t1.t2",
|
||||
"match": ["1"]
|
||||
},
|
||||
{
|
||||
"selector": "div.t1",
|
||||
"match": []
|
||||
},
|
||||
{
|
||||
"selector": "address.t5.t5",
|
||||
"match": ["3"]
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<p id="1" class="t1 t2">This line should be green.</p>
|
||||
<div id="2" class="t3">This line should be green.</div>
|
||||
<address id="3" class="t4 t5 t6">This line should be green.</address>
|
||||
</div>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": ".t1:not(.t2)",
|
||||
"match": []
|
||||
},
|
||||
{
|
||||
"selector": ":not(.t2).t1",
|
||||
"match": []
|
||||
},
|
||||
{
|
||||
"selector": ".t2:not(.t1)",
|
||||
"match": []
|
||||
},
|
||||
{
|
||||
"selector": ":not(.t1).t2",
|
||||
"match": []
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<p id="1" class="t1 t2">This line should be green.</p>
|
||||
</div>
|
||||
@@ -0,0 +1,19 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "p:not(.t1):not(.t2)",
|
||||
"match": []
|
||||
},
|
||||
{
|
||||
"selector": "div:not(.t1)",
|
||||
"match": ["testDOM", "2"]
|
||||
},
|
||||
{
|
||||
"selector": "address:not(.t5):not(.t5)",
|
||||
"match": []
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<p id="1" class="t1 t2">This line should be green.</p>
|
||||
<div id="2" class="t3">This line should be green.</div>
|
||||
<address id="3" class="t4 t5 t6">This line should be green.</address>
|
||||
</div>
|
||||
@@ -0,0 +1,27 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "#t1",
|
||||
"match": ["t1"]
|
||||
},
|
||||
{
|
||||
"selector": "li#t2",
|
||||
"match": ["t2"]
|
||||
},
|
||||
{
|
||||
"selector": "li#t3",
|
||||
"match": ["t3"]
|
||||
},
|
||||
{
|
||||
"selector": "#t4",
|
||||
"match": []
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<ul id="1">
|
||||
<li id="t1">This list item should have a green background. because its ID is "t1"</li>
|
||||
<li id="t2">This list item should have a green background. because its ID is "t2"</li>
|
||||
<li id="t3">
|
||||
<span id="t44">This list item should have a green background. because the inner SPAN does not match "#t4"</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "address:empty",
|
||||
"match": ["1"]
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<address id="1"><!-- --><?test random PI></address>
|
||||
<div id="2" class="text">This line should have a green background.</div>
|
||||
<p id="3">(Note: This test is based on unpublished errata.)</p>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "address:empty",
|
||||
"match": []
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<address id="1"> </address>
|
||||
<div id="2" class="text">This line should have a green background.</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "address:empty",
|
||||
"match": []
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<address id="1"><span id="2"></span></address>
|
||||
<div id="3" class="text">This line should have a green background.</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": "p,",
|
||||
"match": [],
|
||||
"error": 1
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<p id="1">This line should have a green background.</p>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": ".5cm",
|
||||
"match": [],
|
||||
"error": 1
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<p id="1" class="5cm">This line should have a green background.</p>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
<script type="application/json" id="selectors">
|
||||
[{
|
||||
"selector": ".\\5cm",
|
||||
"match": []
|
||||
}]
|
||||
</script>
|
||||
<div id="testDOM">
|
||||
<p class="5cm">This line should have a green background.</p>
|
||||
</div>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user