Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8038ec9654 | |||
| c13abcb833 | |||
| 785ca48f52 | |||
| 1c8be332a4 | |||
| ef29e27f39 | |||
| 482d936196 |
@@ -1,30 +0,0 @@
|
||||
name: HTMLKit CI
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
macOS:
|
||||
name: Test macOS
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: macOS
|
||||
run: xcodebuild -workspace "HTMLKit.xcworkspace" -scheme "HTMLKit-macOS" -destination "platform=macOS" -enableCodeCoverage YES clean test | xcpretty
|
||||
- name: code coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
iOS:
|
||||
name: Test iOS
|
||||
runs-on: macOS-latest
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_11.5.app/Contents/Developer
|
||||
strategy:
|
||||
matrix:
|
||||
destination: ["OS=13.5,name=iPhone 11 Pro", "OS=12.4,name=iPhone XS", "OS=11.4,name=iPhone X"]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: iOS - ${{ matrix.destination }}
|
||||
run: xcodebuild -workspace "HTMLKit.xcworkspace" -scheme "HTMLKit-iOS" -destination "${{ matrix.destination }}" clean test | xcpretty
|
||||
+1
-4
@@ -1,5 +1,5 @@
|
||||
module: HTMLKit
|
||||
module_version: 4.1.0
|
||||
module_version: 2.1.4
|
||||
author: Iskandar Abudiab
|
||||
author_url: https://twitter.com/iabudiab
|
||||
github_url: https://github.com/iabudiab/HTMLKit
|
||||
@@ -33,7 +33,6 @@ custom_categories:
|
||||
- HTMLTemplate
|
||||
- HTMLDOMTokenList
|
||||
- HTMLRange
|
||||
- HTMLSerializer
|
||||
|
||||
- name: Iteration & Filtering
|
||||
children:
|
||||
@@ -42,9 +41,7 @@ custom_categories:
|
||||
- HTMLNodeFilterShowOptions
|
||||
- HTMLNodeFilterValue
|
||||
- HTMLNodeFilterBlock
|
||||
- HTMLNodeVisitor
|
||||
- HTMLSelectorNodeFilter
|
||||
- HTMLTreeVisitor
|
||||
- HTMLTreeWalker
|
||||
|
||||
- name: Structures
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
language: objective-c
|
||||
osx_image: xcode9
|
||||
|
||||
branches:
|
||||
except:
|
||||
- gh-pages
|
||||
|
||||
install:
|
||||
- gem install xcpretty
|
||||
|
||||
env:
|
||||
global:
|
||||
- LC_CTYPE=en_US.UTF-8
|
||||
- LANG=en_US.UTF-8
|
||||
- WORKSPACE=HTMLKit.xcworkspace
|
||||
- IOS_FRAMEWORK_SCHEME=HTMLKit-iOS
|
||||
- MACOS_FRAMEWORK_SCHEME=HTMLKit-macOS
|
||||
- WATCHOS_FRAMEWORK_SCHEME="HTMLKit-watchOS"
|
||||
- TVOS_FRAMEWORK_SCHEME="HTMLKit-tvOS"
|
||||
- IOS_SDK=iphonesimulator11.0
|
||||
- MACOS_SDK=macosx10.13
|
||||
- WATCHOS_SDK=watchsimulator4.0
|
||||
- TVOS_SDK=appletvsimulator11.0
|
||||
matrix:
|
||||
- DESTINATION="arch=x86_64" SCHEME="$MACOS_FRAMEWORK_SCHEME" SDK="$MACOS_SDK"
|
||||
- DESTINATION="OS=9.3,name=iPhone 6s Plus" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK"
|
||||
- DESTINATION="OS=10.3.1,name=iPhone 7 Plus" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK"
|
||||
- DESTINATION="OS=11.0,name=iPhone X" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK"
|
||||
- DESTINATION="OS=3.2,name=Apple Watch Series 2 - 42mm" SCHEME="$WATCHOS_FRAMEWORK_SCHEME" SDK="$WATCHOS_SDK"
|
||||
- DESTINATION="OS=4.0,name=Apple Watch Series 3 - 42mm" SCHEME="$WATCHOS_FRAMEWORK_SCHEME" SDK="$WATCHOS_SDK"
|
||||
- DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK"
|
||||
- DESTINATION="OS=11.0,name=Apple TV 4K" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK"
|
||||
|
||||
script:
|
||||
- set -o pipefail
|
||||
- xcodebuild -version
|
||||
- xcodebuild -showsdks
|
||||
- travis_retry xcodebuild -workspace "$WORKSPACE" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO clean build | xcpretty -c
|
||||
- if [ "$SDK" != "$WATCHOS_SDK" ]; then
|
||||
travis_retry xcodebuild -workspace "$WORKSPACE" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES test | xcpretty -c;
|
||||
fi
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
@@ -1,51 +1,5 @@
|
||||
# Change Log
|
||||
|
||||
## [4.1.0](https://github.com/iabudiab/HTMLKit/releases/tag/4.1.0)
|
||||
|
||||
- Updated project for Xcode 12.5
|
||||
|
||||
## [4.0.0](https://github.com/iabudiab/HTMLKit/releases/tag/4.0.0)
|
||||
|
||||
Release on 2020.07.16
|
||||
|
||||
### Breaking Change
|
||||
|
||||
- Swift package version updated to 5.1
|
||||
|
||||
|
||||
## [3.1.0](https://github.com/iabudiab/HTMLKit/releases/tag/3.1.0)
|
||||
|
||||
Release on 2019.08.20
|
||||
|
||||
### Added
|
||||
|
||||
- `HTMLTreeVisitor` that walks the DOM in tree order
|
||||
- New HTML serialization implementation based on visitor pattern
|
||||
|
||||
### Fixes
|
||||
|
||||
- HTML serialization for deeply nested DOM trees (issue #33)
|
||||
- Occasional Internal Consistency exceptions when deallocating node iterator (issue #36)
|
||||
|
||||
|
||||
## [3.0.0](https://github.com/iabudiab/HTMLKit/releases/tag/3.0.0)
|
||||
|
||||
Released on 2019.03.28
|
||||
|
||||
### Breaking Change
|
||||
|
||||
- Introduce prefix for `NSString` and `NSCharacterSet` categories to prevent collision with existing code (issue #35)
|
||||
|
||||
|
||||
## [2.1.5](https://github.com/iabudiab/HTMLKit/releases/tag/2.1.5)
|
||||
|
||||
Released on 2018.07.16
|
||||
|
||||
### Fixes
|
||||
|
||||
- Parser would handle foreign attributes incorrectly (issue #30)
|
||||
|
||||
|
||||
## [2.1.4](https://github.com/iabudiab/HTMLKit/releases/tag/2.1.4)
|
||||
|
||||
Released on 2018.05.01
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0800;
|
||||
LastUpgradeCheck = 1250;
|
||||
LastUpgradeCheck = 0900;
|
||||
ORGANIZATIONNAME = iabudiab;
|
||||
TargetAttributes = {
|
||||
629A63C81D9AFE0E0089679F = {
|
||||
@@ -100,11 +100,10 @@
|
||||
};
|
||||
buildConfigurationList = 629A63C41D9AFE0E0089679F /* Build configuration list for PBXProject "HTMLKitExample" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = en;
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 629A63C01D9AFE0E0089679F;
|
||||
productRefGroup = 629A63CA1D9AFE0E0089679F /* Products */;
|
||||
@@ -132,7 +131,6 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
@@ -142,7 +140,6 @@
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
@@ -150,10 +147,8 @@
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -191,7 +186,6 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
@@ -201,7 +195,6 @@
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
@@ -209,10 +202,8 @@
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -242,18 +233,16 @@
|
||||
629A63D11D9AFE0E0089679F /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
629A63D21D9AFE0E0089679F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
+9
-3
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1250"
|
||||
LastUpgradeVersion = "0900"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,7 +26,10 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
@@ -36,13 +39,14 @@
|
||||
ReferencedContainer = "container:HTMLKitExample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
@@ -59,6 +63,8 @@
|
||||
ReferencedContainer = "container:HTMLKitExample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -112,7 +112,7 @@ do {
|
||||
try scraper.load()
|
||||
|
||||
// Parse the selector
|
||||
let repositoryContent = try CSSSelectorParser.parseSelector(".repository-content > .file-wrap > table.files tr.js-navigation-item")
|
||||
let repositoryContent = try CSSSelectorParser.parseSelector("[role='main'] .repository-content > .file-wrap > .files tr.js-navigation-item")
|
||||
|
||||
// Query matching elements
|
||||
let files = try scraper.listElements(matching: repositoryContent)
|
||||
@@ -131,10 +131,13 @@ do {
|
||||
// The following selector: "[role='main'] div.file table.js-file-line-container td:nth-child(2)"
|
||||
// can be defined in type-safe manner:
|
||||
let selector = allOf([
|
||||
descendantOfElementSelector(
|
||||
attributeSelector(.exactMatch, "role", "main")
|
||||
),
|
||||
descendantOfElementSelector(
|
||||
allOf([
|
||||
typeSelector("div"),
|
||||
classSelector("repository-content")
|
||||
classSelector("file")
|
||||
])
|
||||
),
|
||||
descendantOfElementSelector(
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
import HTMLKit
|
||||
|
||||
HTMLSanitizingPolicy { (builder) in
|
||||
builder
|
||||
.allowCommonBlockElements()
|
||||
.allowCommonInlineFormattingElements()
|
||||
.allowElements(["p", "div"])
|
||||
.allow(HTMLElementPolicy.identity(), onElements: ["b", "p"])
|
||||
.allow(HTMLAttributePolicy.init(), onElements: [])
|
||||
.disallowText(inElements: ["a"])
|
||||
}
|
||||
|
||||
HTMLElementPolicy { (str) -> String in
|
||||
return str
|
||||
}
|
||||
|
||||
|
||||
HTMLSanitizer { (builder) in
|
||||
builder
|
||||
.allowCommonBlockElements()
|
||||
.allowCommonInlineFormattingElements()
|
||||
.allowElements(["p", "div"])
|
||||
.allow(HTMLElementPolicy.identity() , onElements: ["b", "p"])
|
||||
.allow(HTMLAttributePolicy.init(), onElements: [])
|
||||
.disallowText(inElements: ["a"])
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<playground version='6.0' target-platform='macos' display-mode='rendered' last-migration='0800'>
|
||||
<playground version='6.0' target-platform='macos' display-mode='raw' last-migration='0800'>
|
||||
<pages>
|
||||
<page name='Intro'/>
|
||||
<page name='Parsing Documents'/>
|
||||
<page name='Parsing Fragments'/>
|
||||
<page name='The DOM'/>
|
||||
<page name='CSS Selectors'/>
|
||||
<page name='Sanitizing HTML'/>
|
||||
</pages>
|
||||
</playground>
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "HTMLKit"
|
||||
s.version = "4.1.0"
|
||||
s.version = "2.1.4"
|
||||
s.summary = "HTMLKit, an Objective-C framework for your everyday HTML needs."
|
||||
s.license = "MIT"
|
||||
s.homepage = "https://github.com/iabudiab/HTMLKit"
|
||||
|
||||
+192
-197
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1250"
|
||||
LastUpgradeVersion = "0900"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,17 +26,9 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "62ECBF4C1C0B6C7600AF847B"
|
||||
BuildableName = "HTMLKit.framework"
|
||||
BlueprintName = "HTMLKit-iOS"
|
||||
ReferencedContainer = "container:HTMLKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -63,11 +55,23 @@
|
||||
</SkippedTests>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "62ECBF4C1C0B6C7600AF847B"
|
||||
BuildableName = "HTMLKit.framework"
|
||||
BlueprintName = "HTMLKit-iOS"
|
||||
ReferencedContainer = "container:HTMLKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
@@ -83,6 +87,8 @@
|
||||
ReferencedContainer = "container:HTMLKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1250"
|
||||
LastUpgradeVersion = "0900"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,17 +26,9 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "625A14AB19C7829400AD0C32"
|
||||
BuildableName = "HTMLKit.framework"
|
||||
BlueprintName = "HTMLKit-macOS"
|
||||
ReferencedContainer = "container:HTMLKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -63,11 +55,23 @@
|
||||
</SkippedTests>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "625A14AB19C7829400AD0C32"
|
||||
BuildableName = "HTMLKit.framework"
|
||||
BlueprintName = "HTMLKit-macOS"
|
||||
ReferencedContainer = "container:HTMLKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
@@ -83,6 +87,8 @@
|
||||
ReferencedContainer = "container:HTMLKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1250"
|
||||
LastUpgradeVersion = "0900"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,17 +26,9 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "62857CE91D39A262008DC254"
|
||||
BuildableName = "HTMLKit.framework"
|
||||
BlueprintName = "HTMLKit-tvOS"
|
||||
ReferencedContainer = "container:HTMLKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -57,11 +49,23 @@
|
||||
</SkippedTests>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "62857CE91D39A262008DC254"
|
||||
BuildableName = "HTMLKit.framework"
|
||||
BlueprintName = "HTMLKit-tvOS"
|
||||
ReferencedContainer = "container:HTMLKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
@@ -77,6 +81,8 @@
|
||||
ReferencedContainer = "container:HTMLKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1250"
|
||||
LastUpgradeVersion = "0900"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,15 +26,19 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
@@ -50,6 +54,8 @@
|
||||
ReferencedContainer = "container:HTMLKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2020 Iskandar Abudiab
|
||||
Copyright (c) 2014 Iskandar Abudiab
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+1
-4
@@ -1,9 +1,6 @@
|
||||
// swift-tools-version:5.1
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "HTMLKit",
|
||||
products: [.library(name: "HTMLKit", targets: ["HTMLKit"])],
|
||||
targets: [.target(name: "HTMLKit", dependencies: [], path: "Sources")],
|
||||
swiftLanguageVersions: [.v5]
|
||||
exclude: ["Tests/Fixtures", "Tests/css-tests", "Tests/html5lib-tests"]
|
||||
)
|
||||
|
||||
@@ -77,7 +77,7 @@ To add `HTMLKit` as a dependency into your project using CocoaPods just add the
|
||||
|
||||
```ruby
|
||||
target 'MyTarget' do
|
||||
pod 'HTMLKit', '~> 4.1'
|
||||
pod 'HTMLKit', '~> 2.1'
|
||||
end
|
||||
```
|
||||
|
||||
@@ -94,7 +94,7 @@ $ pod install
|
||||
Add `HTMLKit` to your `Package.swift` dependecies:
|
||||
|
||||
```swift
|
||||
.package(url: "https://github.com/iabudiab/HTMLKit", .upToNextMajor(from: "4.0.0")),
|
||||
.Package(url: "https://github.com/iabudiab/HTMLKit", majorVersion: 2)
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
}
|
||||
case CSSAttributeSelectorIncludes:
|
||||
{
|
||||
NSArray *components = [element[_name] componentsSeparatedByCharactersInSet:[NSCharacterSet htmlkit_HTMLWhitespaceCharacterSet]];
|
||||
NSArray *components = [element[_name] componentsSeparatedByCharactersInSet:[NSCharacterSet HTMLWhitespaceCharacterSet]];
|
||||
return [components containsObject:_value];
|
||||
}
|
||||
case CSSAttributeSelectorBegins:
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#import "CSSNthExpressionParser.h"
|
||||
#import "CSSCodePoints.h"
|
||||
#import "NSString+Private.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
#import "NSCharacterSet+HTMLKit.h"
|
||||
|
||||
@implementation CSSNthExpressionParser
|
||||
@@ -26,7 +26,7 @@
|
||||
return CSSNthExpressionEven;
|
||||
}
|
||||
|
||||
NSCharacterSet *set = [[NSCharacterSet htmlkit_CSSNthExpressionCharacterSet] invertedSet];
|
||||
NSCharacterSet *set = [[NSCharacterSet CSSNthExpressionCharacterSet] invertedSet];
|
||||
if ([string rangeOfCharacterFromSet:set].location != NSNotFound) {
|
||||
return CSSNthExpressionMake(0, 0);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#import "CSSInputStream.h"
|
||||
#import "CSSCodePoints.h"
|
||||
#import "CSSSelectors.h"
|
||||
#import "NSString+Private.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
#import "NSCharacterSet+HTMLKit.h"
|
||||
#import "CSSNthExpressionParser.h"
|
||||
#import "CSSCompoundSelector.h"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#import "CSSStructuralPseudoSelectors.h"
|
||||
#import "CSSSelectors.h"
|
||||
#import "HTMLElement.h"
|
||||
#import "NSString+Private.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
|
||||
#pragma mark - Elements
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#import "CSSTypeSelector.h"
|
||||
#import "HTMLElement.h"
|
||||
#import "NSString+Private.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
|
||||
@interface CSSTypeSelector ()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// HTMLAttributePolicy.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 28.05.18.
|
||||
// Copyright © 2018 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NSString * _Nullable (^ SanitizeAttrbiuteValueBlock) (NSString * _Nullable value, NSString * key);
|
||||
|
||||
@interface HTMLAttributePolicy : NSObject
|
||||
|
||||
+ (instancetype)identity;
|
||||
+ (instancetype)rejectAll;
|
||||
+ (instancetype)policyWithBlock:(SanitizeAttrbiuteValueBlock)block;
|
||||
|
||||
- (NSString *)sanitizeValue:(NSString *)value forKey:(NSString *)key;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// HTMLAttributePolicy.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 28.05.18.
|
||||
// Copyright © 2018 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLAttributePolicy.h"
|
||||
|
||||
@interface HTMLAttributePolicy()
|
||||
{
|
||||
SanitizeAttrbiuteValueBlock _block;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLAttributePolicy
|
||||
|
||||
+ (instancetype)identity
|
||||
{
|
||||
return [self policyWithBlock:^NSString * _Nullable (NSString * _Nullable value, NSString * _Nonnull key) {
|
||||
return value;
|
||||
}];
|
||||
}
|
||||
|
||||
+ (instancetype)rejectAll
|
||||
{
|
||||
return [self policyWithBlock:^NSString * _Nullable (NSString * _Nullable value, NSString * _Nonnull key) {
|
||||
return nil;
|
||||
}];
|
||||
}
|
||||
|
||||
+ (instancetype)policyWithBlock:(SanitizeAttrbiuteValueBlock)block
|
||||
{
|
||||
HTMLAttributePolicy *policy = [[HTMLAttributePolicy alloc] initWithBlock:block];
|
||||
return policy;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBlock:(SanitizeAttrbiuteValueBlock)block
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_block = block;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)sanitizeValue:(NSString *)value forKey:(NSString *)key
|
||||
{
|
||||
if (_block) {
|
||||
return _block(value, key);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
- (BOOL)isWhitespaceToken
|
||||
{
|
||||
return [_characters htmlkit_isHTMLWhitespaceString];
|
||||
return [_characters isHTMLWhitespaceString];
|
||||
}
|
||||
|
||||
- (BOOL)isEmpty
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
- (void)retainLeadingWhitespace
|
||||
{
|
||||
NSUInteger index = _characters.htmlkit_leadingHTMLWhitespaceLength;
|
||||
NSUInteger index = _characters.leadingHTMLWhitespaceLength;
|
||||
if (index > 0) {
|
||||
[_characters setString:[_characters substringToIndex:index]];
|
||||
}
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
- (void)trimLeadingWhitespace
|
||||
{
|
||||
NSUInteger index = _characters.htmlkit_leadingHTMLWhitespaceLength;
|
||||
NSUInteger index = _characters.leadingHTMLWhitespaceLength;
|
||||
if (index > 0) {
|
||||
[_characters setString:[_characters substringFromIndex:index]];
|
||||
}
|
||||
@@ -67,7 +67,7 @@
|
||||
|
||||
- (HTMLCharacterToken *)tokenBySplitingLeadingWhiteSpace
|
||||
{
|
||||
NSUInteger index = _characters.htmlkit_leadingHTMLWhitespaceLength;
|
||||
NSUInteger index = _characters.leadingHTMLWhitespaceLength;
|
||||
if (index > 0) {
|
||||
NSString *leading = [_characters substringToIndex:index];
|
||||
[_characters setString:[_characters substringFromIndex:index]];
|
||||
|
||||
@@ -21,6 +21,13 @@
|
||||
return [super initWithName:@"#comment" type:HTMLNodeComment data:data];
|
||||
}
|
||||
|
||||
#pragma mark - Serialization
|
||||
|
||||
- (NSString *)outerHTML
|
||||
{
|
||||
return [NSString stringWithFormat:@"<!--%@-->", self.data];
|
||||
}
|
||||
|
||||
#pragma mark - Description
|
||||
|
||||
- (NSString *)description
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
|
||||
- (void)detachNodeIterator:(HTMLNodeIterator *)iterator
|
||||
{
|
||||
// NOOP
|
||||
[_nodeIterators removeObject:iterator];
|
||||
}
|
||||
|
||||
#pragma mark - Ranges
|
||||
@@ -153,7 +153,7 @@
|
||||
|
||||
- (void)detachRange:(HTMLRange *)range
|
||||
{
|
||||
// NOOP
|
||||
[_ranges removeObject:range];
|
||||
}
|
||||
|
||||
- (void)didRemoveCharacterDataInNode:(HTMLCharacterData *)node atOffset:(NSUInteger)offset withLength:(NSUInteger)length
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#import "HTMLDocumentType.h"
|
||||
#import "NSString+Private.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
#import "HTMLNode+Private.h"
|
||||
|
||||
NS_INLINE BOOL nilOrEqual(id first, id second) {
|
||||
@@ -144,6 +144,13 @@ NS_INLINE BOOL nilOrEqual(id first, id second) {
|
||||
return copy;
|
||||
}
|
||||
|
||||
#pragma mark - Serialization
|
||||
|
||||
- (NSString *)outerHTML
|
||||
{
|
||||
return [NSString stringWithFormat:@"<!DOCTYPE %@>", self.name];
|
||||
}
|
||||
|
||||
#pragma mark - Description
|
||||
|
||||
- (NSString *)description
|
||||
|
||||
+37
-1
@@ -12,7 +12,7 @@
|
||||
#import "HTMLText.h"
|
||||
#import "HTMLDOMTokenList.h"
|
||||
#import "HTMLOrderedDictionary.h"
|
||||
#import "NSString+Private.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
#import "HTMLNode+Private.h"
|
||||
|
||||
@interface HTMLElement ()
|
||||
@@ -149,6 +149,42 @@
|
||||
return copy;
|
||||
}
|
||||
|
||||
#pragma mark - Serialization
|
||||
|
||||
- (NSString *)outerHTML
|
||||
{
|
||||
NSMutableString *result = [NSMutableString string];
|
||||
|
||||
[result appendFormat:@"<%@", self.tagName];
|
||||
[self.attributes enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
|
||||
NSMutableString *escaped = [value mutableCopy];
|
||||
[escaped replaceOccurrencesOfString:@"&" withString:@"&" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@"0x00A0" withString:@" " options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@"\"" withString:@""" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
|
||||
[result appendFormat:@" %@=\"%@\"", key, escaped];
|
||||
}];
|
||||
|
||||
[result appendString:@">"];
|
||||
|
||||
if ([self.tagName isEqualToAny:@"area", @"base", @"basefont", @"bgsound", @"br", @"col", @"embed",
|
||||
@"frame", @"hr", @"img", @"input", @"keygen", @"link", @"menuitem", @"meta", @"param", @"source",
|
||||
@"track", @"wbr", nil]) {
|
||||
return result;
|
||||
}
|
||||
|
||||
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"];
|
||||
}
|
||||
}
|
||||
[result appendString:self.innerHTML];
|
||||
[result appendFormat:@"</%@>", self.tagName];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma mark - Description
|
||||
|
||||
- (NSString *)description
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// HTMLElementPolicy.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 26.05.18.
|
||||
// Copyright © 2018 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLSanitizingPolicy.h"
|
||||
#import "HTMLOrderedDictionary.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NSString * _Nullable (^ SanitizeElementNameBlock) (NSString *);
|
||||
typedef HTMLOrderedDictionary * _Nullable (^ SanitizeElementAttributesBlock) (HTMLOrderedDictionary * _Nullable);
|
||||
|
||||
@interface HTMLElementPolicy : NSObject
|
||||
|
||||
+ (instancetype)identity;
|
||||
+ (instancetype)rejectAll;
|
||||
+ (instancetype)policyWithNameBlock:(SanitizeElementNameBlock)nameBlock;
|
||||
+ (instancetype)policyWithNameBlock:(SanitizeElementNameBlock)nameBlock
|
||||
attributesBlock:(nullable SanitizeElementAttributesBlock)attributesBlock;
|
||||
|
||||
- (NSString *)sanitizeName:(NSString *)name;
|
||||
- (HTMLOrderedDictionary *)sanitzeAttributes:(HTMLOrderedDictionary *)attributes;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// HTMLElementPolicy.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 26.05.18.
|
||||
// Copyright © 2018 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLElementPolicy.h"
|
||||
|
||||
@interface HTMLElementPolicy()
|
||||
{
|
||||
SanitizeElementNameBlock _nameBlock;
|
||||
SanitizeElementAttributesBlock _attributesBlock;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLElementPolicy
|
||||
|
||||
+ (instancetype)identity
|
||||
{
|
||||
return [self policyWithNameBlock:^NSString * _Nullable (NSString * _Nonnull name) {
|
||||
return name;
|
||||
}];
|
||||
}
|
||||
|
||||
+ (instancetype)rejectAll
|
||||
{
|
||||
return [self policyWithNameBlock:^NSString *_Nullable (NSString * _Nonnull name) {
|
||||
return nil;
|
||||
}];
|
||||
}
|
||||
|
||||
+ (instancetype)policyWithNameBlock:(NSString * _Nonnull (^)(NSString * _Nonnull))nameBlock
|
||||
{
|
||||
return [self policyWithNameBlock:nameBlock attributesBlock:nil];
|
||||
}
|
||||
|
||||
+ (instancetype)policyWithNameBlock:(SanitizeElementNameBlock)nameBlock
|
||||
attributesBlock:(SanitizeElementAttributesBlock)attributesBlock
|
||||
{
|
||||
HTMLElementPolicy *policy = [[HTMLElementPolicy alloc] initWithNameBlock:nameBlock attributesBlock:attributesBlock];
|
||||
return policy;
|
||||
}
|
||||
|
||||
- (instancetype)initWithNameBlock:(SanitizeElementNameBlock)nameBlock
|
||||
attributesBlock:(SanitizeElementAttributesBlock)attributesBlock
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_nameBlock = nameBlock;
|
||||
_attributesBlock = attributesBlock;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)sanitizeName:(NSString *)name
|
||||
{
|
||||
if (_nameBlock) {
|
||||
return _nameBlock(name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
- (HTMLOrderedDictionary *)sanitzeAttributes:(HTMLOrderedDictionary *)attributes
|
||||
{
|
||||
if (_attributesBlock) {
|
||||
return _attributesBlock(attributes);
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -170,7 +170,7 @@
|
||||
|
||||
- (BOOL)consumeHexNumber:(unsigned long long *)result
|
||||
{
|
||||
NSCharacterSet *set = [NSCharacterSet htmlkit_HTMLHexNumberCharacterSet];
|
||||
NSCharacterSet *set = [NSCharacterSet HTMLHexNumberCharacterSet];
|
||||
|
||||
NSString *string = nil;
|
||||
BOOL success = [_scanner scanCharactersFromSet:set intoString:&string];
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<string>2.1.4</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2014 iabudiab. All rights reserved.</string>
|
||||
<string>Copyright © 2014 BrainCookie. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
|
||||
+7
-21
@@ -18,7 +18,6 @@
|
||||
#import "CSSSelector.h"
|
||||
#import "HTMLDocument+Private.h"
|
||||
#import "HTMLDOMUtils.h"
|
||||
#import "HTMLSerializer.h"
|
||||
|
||||
NSString * const ValidationNodePreInsertion = @"-ensurePreInsertionValidityOfNode:beforeChildNode:";
|
||||
NSString * const ValidationNodeReplacement = @"-ensureReplacementValidityOfChildNode:withNode:";
|
||||
@@ -157,20 +156,6 @@ NSString * const RemoveChildNode = @"-removeChildNode:";
|
||||
return (HTMLElement *)self;
|
||||
}
|
||||
|
||||
- (HTMLText *)asText
|
||||
{
|
||||
return (HTMLText *)self;
|
||||
}
|
||||
|
||||
- (HTMLComment *)asComment
|
||||
{
|
||||
return (HTMLComment *)self;
|
||||
}
|
||||
- (HTMLDocumentType *)asDocumentType
|
||||
{
|
||||
return (HTMLDocumentType *)self;
|
||||
}
|
||||
|
||||
#pragma mark - Child Nodes
|
||||
|
||||
- (BOOL)hasChildNodes
|
||||
@@ -383,16 +368,16 @@ NSString * const RemoveChildNode = @"-removeChildNode:";
|
||||
}
|
||||
|
||||
if (self.ownerDocument != otherNode.ownerDocument) {
|
||||
return ((HTMLDocumentPositionDisconnected | HTMLDocumentPositionImplementationSpecific |
|
||||
self.hash < otherNode.hash) ? HTMLDocumentPositionPreceding : HTMLDocumentPositionFollowing);
|
||||
return (HTMLDocumentPositionDisconnected | HTMLDocumentPositionImplementationSpecific |
|
||||
self.hash < otherNode.hash ? HTMLDocumentPositionPreceding : HTMLDocumentPositionFollowing);
|
||||
}
|
||||
|
||||
NSArray *ancestors1 = GetAncestorNodes(self);
|
||||
NSArray *ancestors2 = GetAncestorNodes(otherNode);
|
||||
|
||||
if (ancestors1.lastObject != ancestors2.lastObject) {
|
||||
return ((HTMLDocumentPositionDisconnected | HTMLDocumentPositionImplementationSpecific |
|
||||
self.hash < otherNode.hash) ? HTMLDocumentPositionPreceding : HTMLDocumentPositionFollowing);
|
||||
return (HTMLDocumentPositionDisconnected | HTMLDocumentPositionImplementationSpecific |
|
||||
self.hash < otherNode.hash ? HTMLDocumentPositionPreceding : HTMLDocumentPositionFollowing);
|
||||
}
|
||||
|
||||
NSUInteger index1 = ancestors1.count;
|
||||
@@ -733,12 +718,13 @@ NS_INLINE void CheckInvalidCombination(HTMLNode *parent, HTMLNode *node, NSStrin
|
||||
|
||||
- (NSString *)outerHTML
|
||||
{
|
||||
return [HTMLSerializer serializeNode:self scope:HTMLSerializationScopeIncludeRoot];
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)innerHTML
|
||||
{
|
||||
return [HTMLSerializer serializeNode:self scope:HTMLSerializationScopeChildrenOnly];
|
||||
return [[self.childNodes.array valueForKey:@"outerHTML"] componentsJoinedByString:@""];
|
||||
}
|
||||
|
||||
- (void)setInnerHTML:(NSString *)outerHTML
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
//
|
||||
// HTMLNodeVisitor.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 30.07.19.
|
||||
// Copyright © 2019 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLNodeVisitor.h"
|
||||
|
||||
#pragma mark - Block Visitor
|
||||
|
||||
@interface HTMLNodeVisitorBlock ()
|
||||
{
|
||||
void (^ _enter)(HTMLNode *);
|
||||
void (^ _leave)(HTMLNode *);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLNodeVisitorBlock
|
||||
|
||||
+ (instancetype)visitorWithEnterBlock:(void (^)(HTMLNode * _Nonnull))enterBlock
|
||||
leaveBlock:(void (^)(HTMLNode * _Nonnull))leaveBlock
|
||||
{
|
||||
return [[HTMLNodeVisitorBlock alloc] initWithEnterBlock:enterBlock leaveBlock:leaveBlock];
|
||||
}
|
||||
|
||||
- (instancetype)initWithEnterBlock:(void (^)(HTMLNode * _Nonnull))enterBlock
|
||||
leaveBlock:(void (^)(HTMLNode * _Nonnull))leaveBlock
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_enter = [enterBlock copy];
|
||||
_leave = [leaveBlock copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)enter:(HTMLNode *)node
|
||||
{
|
||||
if (_enter) {
|
||||
_enter(node);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)leave:(HTMLNode *)node
|
||||
{
|
||||
if (_leave) {
|
||||
_leave(node);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+19
-19
@@ -1142,7 +1142,7 @@
|
||||
if (charactes.length > 0) {
|
||||
[self reconstructActiveFormattingElements];
|
||||
[self insertCharacters:charactes];
|
||||
if (!charactes.htmlkit_isHTMLWhitespaceString) {
|
||||
if (!charactes.isHTMLWhitespaceString) {
|
||||
_framesetOkFlag = NO;
|
||||
}
|
||||
}
|
||||
@@ -1308,7 +1308,7 @@
|
||||
_framesetOkFlag = NO;
|
||||
} else if ([tagName isEqualToString:@"a"]) {
|
||||
HTMLElement *element = ^ HTMLElement * {
|
||||
for (HTMLElement *element in self->_listOfActiveFormattingElements.reverseObjectEnumerator) {
|
||||
for (HTMLElement *element in _listOfActiveFormattingElements.reverseObjectEnumerator) {
|
||||
if ([element isEqual:[HTMLMarker marker]]) return nil;
|
||||
if ([element.tagName isEqualToString:@"a"]) {
|
||||
return element;
|
||||
@@ -1776,7 +1776,7 @@
|
||||
- (void)HTMLInsertionModeInCaption:(HTMLToken *)token
|
||||
{
|
||||
void (^ common) (BOOL) = ^ (BOOL reprocess) {
|
||||
if (![self->_stackOfOpenElements hasElementInTableScopeWithTagName:@"caption"]) {
|
||||
if (![_stackOfOpenElements hasElementInTableScopeWithTagName:@"caption"]) {
|
||||
[self emitParseError:@"Unexpected end tag </caption> for misnested element in <caption>"];
|
||||
return;
|
||||
}
|
||||
@@ -1784,8 +1784,8 @@
|
||||
if (![self.currentNode.tagName isEqualToString:@"caption"]) {
|
||||
[self emitParseError:@"Misnested <caption> element in <caption>"];
|
||||
}
|
||||
[self->_stackOfOpenElements popElementsUntilElementPoppedWithTagName:@"caption"];
|
||||
[self->_listOfActiveFormattingElements clearUptoLastMarker];
|
||||
[_stackOfOpenElements popElementsUntilElementPoppedWithTagName:@"caption"];
|
||||
[_listOfActiveFormattingElements clearUptoLastMarker];
|
||||
[self switchInsertionMode:HTMLInsertionModeInTable];
|
||||
|
||||
if (reprocess) {
|
||||
@@ -1890,12 +1890,12 @@
|
||||
- (void)HTMLInsertionModeInTableBody:(HTMLToken *)token
|
||||
{
|
||||
void (^ common) (BOOL) = ^ (BOOL reprocess) {
|
||||
if (![self->_stackOfOpenElements hasElementInTableScopeWithAnyOfTagNames:@[@"tbody", @"tfoot", @"thead"]]) {
|
||||
if (![_stackOfOpenElements hasElementInTableScopeWithAnyOfTagNames:@[@"tbody", @"tfoot", @"thead"]]) {
|
||||
[self emitParseError:@"Unexpected tag '%@' for misnested element in <tbody>", token.asTagToken.tagName];
|
||||
return;
|
||||
} else {
|
||||
[self->_stackOfOpenElements clearBackToTableBodyContext];
|
||||
[self->_stackOfOpenElements popCurrentNode];
|
||||
[_stackOfOpenElements clearBackToTableBodyContext];
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
[self switchInsertionMode:HTMLInsertionModeInTable];
|
||||
}
|
||||
|
||||
@@ -1946,12 +1946,12 @@
|
||||
- (void)HTMLInsertionModeInRow:(HTMLToken *)token
|
||||
{
|
||||
void (^ common) (NSString *, BOOL) = ^ (NSString *elementTagName, BOOL reprocess) {
|
||||
if (![self->_stackOfOpenElements hasElementInTableScopeWithTagName:elementTagName]) {
|
||||
if (![_stackOfOpenElements hasElementInTableScopeWithTagName:elementTagName]) {
|
||||
[self emitParseError:@"Unexpected tag '%@' for misnested element <%@> in <tr>", token.asTagToken.tagName, elementTagName];
|
||||
return;
|
||||
} else {
|
||||
[self->_stackOfOpenElements clearBackToTableRowContext];
|
||||
[self->_stackOfOpenElements popCurrentNode];
|
||||
[_stackOfOpenElements clearBackToTableRowContext];
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
[self switchInsertionMode:HTMLInsertionModeInTableBody];
|
||||
}
|
||||
|
||||
@@ -2313,7 +2313,7 @@
|
||||
[characters enumerateSubstringsInRange:NSMakeRange(0, characters.length)
|
||||
options:NSStringEnumerationByComposedCharacterSequences
|
||||
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
|
||||
if (substring.htmlkit_isHTMLWhitespaceString) {
|
||||
if (substring.isHTMLWhitespaceString) {
|
||||
[self insertCharacters:substring];
|
||||
} else {
|
||||
[self emitParseError:@"Unexpected Character (%@) in <frameset>", substring];
|
||||
@@ -2381,7 +2381,7 @@
|
||||
[characters enumerateSubstringsInRange:NSMakeRange(0, characters.length)
|
||||
options:NSStringEnumerationByComposedCharacterSequences
|
||||
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
|
||||
if (substring.htmlkit_isHTMLWhitespaceString) {
|
||||
if (substring.isHTMLWhitespaceString) {
|
||||
[self insertCharacters:substring];
|
||||
} else {
|
||||
[self emitParseError:@"Unexpected Character (%@) after <frameset>", substring];
|
||||
@@ -2515,8 +2515,8 @@
|
||||
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
|
||||
if ([substring isEqualToString:@"\uFFFD"]) {
|
||||
[self emitParseError:@"Unexpected Character (0x0000) in foreign content"];
|
||||
} else if (!substring.htmlkit_isHTMLWhitespaceString) {
|
||||
self->_framesetOkFlag = NO;
|
||||
} else if (!substring.isHTMLWhitespaceString) {
|
||||
_framesetOkFlag = NO;
|
||||
}
|
||||
[self insertCharacters:substring];
|
||||
}];
|
||||
@@ -2541,20 +2541,20 @@
|
||||
}
|
||||
[self insertForeignElementForToken:token.asTagToken inNamespace:self.adjustedCurrentNode.htmlNamespace];
|
||||
if (token.asTagToken.selfClosing) {
|
||||
[self->_stackOfOpenElements popCurrentNode];
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
}
|
||||
};
|
||||
|
||||
void (^ matchedCase)(void) = ^ {
|
||||
[self emitParseError:@"Unexpected start tag <%@> in foreign content", token.asTagToken.tagName];
|
||||
if (self->_fragmentParsingAlgorithm) {
|
||||
if (_fragmentParsingAlgorithm) {
|
||||
anythingElse();
|
||||
} else {
|
||||
[self->_stackOfOpenElements popCurrentNode];
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
while (!IsNodeMathMLTextIntegrationPoint(self.currentNode) &&
|
||||
!IsNodeHTMLIntegrationPoint(self.currentNode) &&
|
||||
self.currentNode.htmlNamespace != HTMLNamespaceHTML) {
|
||||
[self->_stackOfOpenElements popCurrentNode];
|
||||
[_stackOfOpenElements popCurrentNode];
|
||||
}
|
||||
[self reprocessToken:token];
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
//
|
||||
// HTMLQuircksMode.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 26.03.19.
|
||||
// Copyright © 2019 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLQuirksMode.h"
|
||||
#import "NSString+Private.h"
|
||||
|
||||
BOOL QuirksModePrefixMatch(NSString *publicIdentifier)
|
||||
{
|
||||
for (int i = 0; i < sizeof(HTMLQuirksModePrefixes) / sizeof(HTMLQuirksModePrefixes[0]); i++) {
|
||||
if ([publicIdentifier hasPrefixIgnoringCase:HTMLQuirksModePrefixes[i]]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// HTMLSanitizer.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 26.05.18.
|
||||
// Copyright © 2018 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLSanitizingPolicyBuilder.h"
|
||||
#import "HTMLSanitizingPolicy.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HTMLSanitizer : NSObject
|
||||
|
||||
+ (instancetype)sanitizerWithPolicy:(void (^)(HTMLSanitizingPolicyBuilder *))block;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// HTMLSanitizer.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 26.05.18.
|
||||
// Copyright © 2018 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLSanitizer.h"
|
||||
#import "HTMLTokenizer.h"
|
||||
#import "HTMLTokens.h"
|
||||
|
||||
@interface HTMLSanitizer()
|
||||
{
|
||||
HTMLTokenizer *_tokenizer;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation HTMLSanitizer
|
||||
|
||||
+ (instancetype)sanitizerWithPolicy:(void (^)(HTMLSanitizingPolicyBuilder *))block
|
||||
{
|
||||
HTMLSanitizingPolicyBuilder *builder = [HTMLSanitizingPolicyBuilder new];
|
||||
block(builder);
|
||||
return nil; //[[HTMLSanitizingPolicy alloc] initWithBuilder:builder];
|
||||
}
|
||||
|
||||
- (instancetype)initWithString:(NSString *)string
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_tokenizer = [[HTMLTokenizer alloc] initWithString:string ?: @""];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)sanitize
|
||||
{
|
||||
// for (HTMLToken *token in _tokenizer) {
|
||||
//
|
||||
// }
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// HTMLSanitizingPolicy.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 26.05.18.
|
||||
// Copyright © 2018 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HTMLSanitizingPolicy : NSObject
|
||||
|
||||
- (HTMLSanitizingPolicy *)combineWith:(nullable HTMLSanitizingPolicy *)other;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// HTMLSanitizingPolicy.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 26.05.18.
|
||||
// Copyright © 2018 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLSanitizingPolicy.h"
|
||||
|
||||
@interface HTMLSanitizingPolicy()
|
||||
{
|
||||
NSMutableArray *_policies;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLSanitizingPolicy
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_policies = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (HTMLSanitizingPolicy *)combineWith:(HTMLSanitizingPolicy *)other
|
||||
{
|
||||
if (other) {
|
||||
[_policies addObject:other];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// HTMLSanitizingPolicyBuilder.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 26.05.18.
|
||||
// Copyright © 2018 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "HTMLElementPolicy.h"
|
||||
#import "HTMLTokenPolicy.h"
|
||||
#import "HTMLAttributePolicy.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HTMLSanitizingPolicyBuilder : NSObject
|
||||
|
||||
- (HTMLSanitizingPolicyBuilder *)allowElements:(NSArray<NSString *> *)elementNames;
|
||||
- (HTMLSanitizingPolicyBuilder *)disallowElements:(NSArray<NSString *> *)elementNames;
|
||||
- (HTMLSanitizingPolicyBuilder *)allowPolicy:(HTMLElementPolicy *)policy onElements:(NSArray<NSString *> *)elementNames;
|
||||
- (HTMLSanitizingPolicyBuilder *)allowCommonInlineFormattingElements;
|
||||
- (HTMLSanitizingPolicyBuilder *)allowCommonBlockElements;
|
||||
- (HTMLSanitizingPolicyBuilder *)allowTextInElements:(NSArray<NSString *> *)elementNames;
|
||||
- (HTMLSanitizingPolicyBuilder *)disallowTextInElements:(NSArray<NSString *> *)elementNames;
|
||||
|
||||
//- (HTMLSanitizingPolicyBuilder *)allowAttributes:(NSArray<NSString *> *)attributeName
|
||||
// onElements:(NSArray<NSString *> *)elementNames;
|
||||
//- (HTMLSanitizingPolicyBuilder *)disallowAttributes:(NSArray<NSString *> *)attributeName
|
||||
// onElements:(NSArray<NSString *> *)elementNames;
|
||||
//
|
||||
//- (HTMLSanitizingPolicyBuilder *)allowAttributePolicy:(HTMLAttributePolicy *)policy
|
||||
// onElements:(NSArray<NSString *> *)elementNames;
|
||||
//- (HTMLSanitizingPolicyBuilder *)disallowAttributePolicy:(HTMLAttributePolicy *)policy
|
||||
// onElements:(NSArray<NSString *> *)elementNames;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// HTMLSanitizingPolicyBuilder.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 26.05.18.
|
||||
// Copyright © 2018 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLSanitizingPolicyBuilder.h"
|
||||
|
||||
@interface HTMLSanitizingPolicyBuilder()
|
||||
{
|
||||
NSMutableDictionary<NSString *, NSMutableArray<HTMLElementPolicy *> *> * elementPolicies;
|
||||
NSMutableDictionary<NSString *, HTMLAttributePolicy *> * attributePolicies;
|
||||
NSMutableDictionary<NSString *, NSNumber *> * textContainers;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLSanitizingPolicyBuilder
|
||||
|
||||
- (HTMLSanitizingPolicyBuilder *)allowElements:(NSArray<NSString *> *)elementNames
|
||||
{
|
||||
return [self allowPolicy:HTMLElementPolicy.identity onElements:elementNames];
|
||||
}
|
||||
|
||||
- (HTMLSanitizingPolicyBuilder *)disallowElements:(NSArray<NSString *> *)elementNames
|
||||
{
|
||||
return [self allowPolicy:HTMLElementPolicy.rejectAll onElements:elementNames];
|
||||
}
|
||||
|
||||
- (HTMLSanitizingPolicyBuilder *)allowPolicy:(HTMLElementPolicy *)policy onElements:(NSArray<NSString *> *)elementNames
|
||||
{
|
||||
for (NSString *name in elementNames) {
|
||||
NSMutableArray<HTMLElementPolicy *> *list = elementPolicies[name];
|
||||
if (list == nil) {
|
||||
list = [NSMutableArray new];
|
||||
}
|
||||
[list addObject:policy];
|
||||
elementPolicies[name] = list;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (HTMLSanitizingPolicyBuilder *)allowCommonInlineFormattingElements
|
||||
{
|
||||
return [self allowElements:@[@"b", @"i", @"font", @"s", @"u", @"o", @"sup", @"sub", @"ins", @"del",
|
||||
@"strong", @"strike", @"tt", @"code", @"big", @"small", @"br", @"span", @"em"]];
|
||||
}
|
||||
|
||||
- (HTMLSanitizingPolicyBuilder *)allowCommonBlockElements
|
||||
{
|
||||
return [self allowElements:@[@"p", @"div", @"h1", @"h2", @"h3", @"h4", @"h5", @"h6", @"ul", @"ol", @"li",
|
||||
@"blockquote"]];
|
||||
}
|
||||
|
||||
- (HTMLSanitizingPolicyBuilder *)allowTextInElements:(NSArray<NSString *> *)elementNames;
|
||||
{
|
||||
for (NSString *name in elementNames) {
|
||||
textContainers[name] = @YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (HTMLSanitizingPolicyBuilder *)disallowTextInElements:(NSArray<NSString *> *)elementNames
|
||||
{
|
||||
for (NSString *name in elementNames) {
|
||||
textContainers[name] = @NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
//- (HTMLSanitizingPolicyBuilder *)allowAttributes:(NSArray<NSString *> *)attributeNames
|
||||
// onElements:(NSArray<NSString *> *)elementNames
|
||||
//{
|
||||
// for (NSString *attribute in attributeNames) {
|
||||
// [self allowAttributePolicy:HTMLAttributePolicy.identity onElements:elementNames];
|
||||
// }
|
||||
// return self;
|
||||
//}
|
||||
//
|
||||
//- (HTMLSanitizingPolicyBuilder *)disallowAttributes:(NSArray<NSString *> *)attributeName
|
||||
// onElements:(NSArray<NSString *> *)elementNames;
|
||||
//
|
||||
//- (HTMLSanitizingPolicyBuilder *)allowAttributePolicy:(HTMLAttributePolicy *)policy onElements:(NSArray<NSString *> *)elementNames
|
||||
//{
|
||||
// return self;
|
||||
//}
|
||||
//
|
||||
//- (HTMLSanitizingPolicyBuilder *)disallowAttributePolicy:(HTMLAttributePolicy *)policy onElements:(NSArray<NSString *> *)elementNames
|
||||
//{
|
||||
// return self;
|
||||
//}
|
||||
|
||||
@end
|
||||
@@ -1,155 +0,0 @@
|
||||
//
|
||||
// HTMLSerializer.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 28.07.19.
|
||||
// Copyright © 2019 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLSerializer.h"
|
||||
#import "HTMLDOM.h"
|
||||
#import "HTMLNode+Private.h"
|
||||
#import "HTMLTreeVisitor.h"
|
||||
#import "NSString+Private.h"
|
||||
|
||||
#pragma mark - Serializer
|
||||
|
||||
@interface HTMLSerializer ()
|
||||
{
|
||||
HTMLNode *_root;
|
||||
HTMLTreeVisitor *_treeVisitor;
|
||||
NSUInteger _ignore;
|
||||
NSMutableString *_result;
|
||||
}
|
||||
- (instancetype)initWithNode:(HTMLNode *)node;
|
||||
- (NSString *)serializeWithScope:(HTMLSerializationScope)scope;
|
||||
@end
|
||||
|
||||
@implementation HTMLSerializer
|
||||
|
||||
+ (NSString *)serializeNode:(HTMLNode *)node scope:(HTMLSerializationScope)scope
|
||||
{
|
||||
HTMLSerializer *serializer = [[HTMLSerializer alloc] initWithNode:node];
|
||||
return [serializer serializeWithScope:scope];
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)initWithNode:(HTMLNode *)node
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_root = node;
|
||||
_treeVisitor = [[HTMLTreeVisitor alloc] initWithNode:node];
|
||||
_result = [NSMutableString new];
|
||||
_ignore = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Serialization
|
||||
|
||||
- (NSString *)serializeWithScope:(HTMLSerializationScope)scope
|
||||
{
|
||||
[_result setString:@""];
|
||||
|
||||
HTMLNodeVisitorBlock *nodeVisitor = [HTMLNodeVisitorBlock visitorWithEnterBlock:^(HTMLNode * node) {
|
||||
if (scope == HTMLSerializationScopeChildrenOnly && node == self->_root) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->_ignore > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (node.nodeType) {
|
||||
case HTMLNodeElement:
|
||||
[self openElement:node.asElement];
|
||||
break;
|
||||
case HTMLNodeComment:
|
||||
[self serializeComment:node.asComment];
|
||||
break;
|
||||
case HTMLNodeText:
|
||||
[self serializeText:node.asText];
|
||||
break;
|
||||
case HTMLNodeDocumentFragment:
|
||||
[self serializeDocumentType:node.asDocumentType];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} leaveBlock:^(HTMLNode * _Nonnull node) {
|
||||
if (scope == HTMLSerializationScopeChildrenOnly && node == self->_root) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (node.nodeType) {
|
||||
case HTMLNodeElement:
|
||||
if ([node.asElement.tagName isEqualToAny:@"area", @"base", @"basefont", @"bgsound", @"br", @"col", @"embed",
|
||||
@"frame", @"hr", @"img", @"input", @"keygen", @"link", @"menuitem", @"meta", @"param", @"source",
|
||||
@"track", @"wbr", nil]) {
|
||||
self->_ignore--;
|
||||
break;
|
||||
}
|
||||
[self closeElement:node.asElement];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}];
|
||||
|
||||
[_treeVisitor walkWithNodeVisitor:nodeVisitor];
|
||||
return [_result copy];
|
||||
}
|
||||
|
||||
- (void)openElement:(HTMLElement *)element
|
||||
{
|
||||
[_result appendFormat:@"<%@", element.tagName];
|
||||
[element.attributes enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
|
||||
NSMutableString *escaped = [value mutableCopy];
|
||||
[escaped replaceOccurrencesOfString:@"&" withString:@"&" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@"0x00A0" withString:@" " options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@"\"" withString:@""" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
|
||||
[_result appendFormat:@" %@=\"%@\"", key, escaped];
|
||||
}];
|
||||
|
||||
[_result appendString:@">"];
|
||||
|
||||
if ([element.tagName isEqualToAny:@"area", @"base", @"basefont", @"bgsound", @"br", @"col", @"embed",
|
||||
@"frame", @"hr", @"img", @"input", @"keygen", @"link", @"menuitem", @"meta", @"param", @"source",
|
||||
@"track", @"wbr", nil]) {
|
||||
_ignore++;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)closeElement:(HTMLElement *)element
|
||||
{
|
||||
[_result appendFormat:@"</%@>", element.tagName];
|
||||
}
|
||||
|
||||
- (void)serializeText:(HTMLText *)text
|
||||
{
|
||||
if ([text.parentElement.tagName isEqualToAny:@"style", @"script", @"xmp", @"iframe", @"noembed", @"noframes",
|
||||
@"plaintext", @"noscript", nil]) {
|
||||
[_result appendString:text.data];
|
||||
} else {
|
||||
NSMutableString *escaped = [text.data mutableCopy];
|
||||
[escaped replaceOccurrencesOfString:@"&" withString:@"&" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@"\00A0" withString:@" " options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@"<" withString:@"<" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@">" withString:@">" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[_result appendString:escaped];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)serializeComment:(HTMLComment *)comment
|
||||
{
|
||||
[_result appendFormat:@"<!--%@-->", comment.data];
|
||||
}
|
||||
|
||||
- (void)serializeDocumentType:(HTMLDocumentType *)doctype
|
||||
{
|
||||
[_result appendFormat:@"<!DOCTYPE %@>", doctype.name];
|
||||
}
|
||||
|
||||
@end
|
||||
+18
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
#import "HTMLText.h"
|
||||
#import "HTMLElement.h"
|
||||
#import "NSString+Private.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
#import "HTMLCharacterData+Private.h"
|
||||
#import "HTMLKitDOMExceptions.h"
|
||||
#import "HTMLDocument+Private.h"
|
||||
@@ -66,6 +66,23 @@ NS_INLINE void CheckValidOffset(HTMLNode *node, NSUInteger offset, NSString *cmd
|
||||
return newNode;
|
||||
}
|
||||
|
||||
#pragma mark - Serialization
|
||||
|
||||
- (NSString *)outerHTML
|
||||
{
|
||||
if ([self.parentElement.tagName isEqualToAny:@"style", @"script", @"xmp", @"iframe", @"noembed", @"noframes",
|
||||
@"plaintext", @"noscript", nil]) {
|
||||
return self.data;
|
||||
} else {
|
||||
NSMutableString *escaped = [self.data mutableCopy];
|
||||
[escaped replaceOccurrencesOfString:@"&" withString:@"&" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@"\00A0" withString:@" " options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@"<" withString:@"<" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@">" withString:@">" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
return escaped;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Description
|
||||
|
||||
- (NSString *)description
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// HTMLTokenPolicy.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 01.06.18.
|
||||
// Copyright © 2018 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLTokens.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HTMLTokenPolicy : NSObject
|
||||
|
||||
+ (instancetype)policy:(HTMLToken * _Nullable (^)(HTMLToken *))block;
|
||||
|
||||
- (nullable HTMLToken *)apply:(HTMLToken *)token;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// HTMLTokenPolicy.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 01.06.18.
|
||||
// Copyright © 2018 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLTokenPolicy.h"
|
||||
|
||||
@interface HTMLTokenPolicy()
|
||||
{
|
||||
HTMLToken * (^ _policyBlock)(HTMLToken *);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLTokenPolicy
|
||||
|
||||
+ (instancetype)policy:(HTMLToken * _Nullable (^)(HTMLToken * _Nonnull))block
|
||||
{
|
||||
return [[HTMLTokenPolicy alloc] initWithBlock:block];
|
||||
}
|
||||
|
||||
- (instancetype)initWithBlock:(HTMLToken * _Nullable (^)(HTMLToken * _Nonnull))block
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_policyBlock = block;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (HTMLToken *)apply:(HTMLToken *)token
|
||||
{
|
||||
return _policyBlock(token);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,63 +0,0 @@
|
||||
//
|
||||
// HTMLTreeVisitor.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 30.07.19.
|
||||
// Copyright © 2019 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTMLTreeVisitor.h"
|
||||
#import "HTMLNode.h"
|
||||
#import "HTMLTreeWalker.h"
|
||||
|
||||
@interface HTMLTreeVisitor()
|
||||
{
|
||||
HTMLNode *_root;
|
||||
HTMLTreeWalker *_treeWalker;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLTreeVisitor
|
||||
|
||||
- (instancetype)initWithNode:(HTMLNode *)node
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_root = node;
|
||||
_treeWalker = [[HTMLTreeWalker alloc] initWithNode:node];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)walkWithNodeVisitor:(id<HTMLNodeVisitor>)visitor
|
||||
{
|
||||
HTMLNode *currentNode = _treeWalker.currentNode;
|
||||
while (currentNode) {
|
||||
[visitor enter:currentNode];
|
||||
if (currentNode.hasChildNodes) {
|
||||
currentNode = [_treeWalker firstChild];
|
||||
continue;
|
||||
}
|
||||
|
||||
HTMLNode *next = [_treeWalker nextSibling];
|
||||
if (next) {
|
||||
[visitor leave:currentNode];
|
||||
currentNode = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
while (!next && _treeWalker.currentNode != _root) {
|
||||
[visitor leave:_treeWalker.currentNode];
|
||||
currentNode = [_treeWalker parentNode];
|
||||
next = [_treeWalker nextSibling];
|
||||
}
|
||||
[visitor leave:currentNode];
|
||||
currentNode = _treeWalker.currentNode;
|
||||
|
||||
if (currentNode == _root) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
@implementation NSCharacterSet (HTMLKit)
|
||||
|
||||
+ (instancetype)htmlkit_HTMLWhitespaceCharacterSet
|
||||
+ (instancetype)HTMLWhitespaceCharacterSet
|
||||
{
|
||||
static NSCharacterSet *set = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
@@ -20,7 +20,7 @@
|
||||
return set;
|
||||
}
|
||||
|
||||
+ (instancetype)htmlkit_HTMLHexNumberCharacterSet
|
||||
+ (instancetype)HTMLHexNumberCharacterSet
|
||||
{
|
||||
static NSCharacterSet *set = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
@@ -30,7 +30,7 @@
|
||||
return set;
|
||||
}
|
||||
|
||||
+ (instancetype)htmlkit_CSSNthExpressionCharacterSet
|
||||
+ (instancetype)CSSNthExpressionCharacterSet
|
||||
{
|
||||
static NSCharacterSet *set = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
|
||||
@@ -15,12 +15,37 @@ NS_INLINE BOOL isHtmlWhitespaceChar(unichar c)
|
||||
|
||||
@implementation NSString (HTMLKit)
|
||||
|
||||
- (BOOL)htmlkit_isHTMLWhitespaceString
|
||||
- (BOOL)isEqualToStringIgnoringCase:(NSString *)aString
|
||||
{
|
||||
return self.htmlkit_leadingHTMLWhitespaceLength == self.length;
|
||||
return [self caseInsensitiveCompare:aString] == NSOrderedSame;
|
||||
}
|
||||
|
||||
- (NSUInteger)htmlkit_leadingHTMLWhitespaceLength
|
||||
- (BOOL)isEqualToAny:(NSString *)first, ... NS_REQUIRES_NIL_TERMINATION
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, first);
|
||||
for (NSString *next = first; next != nil; next = va_arg(list, NSString *)) {
|
||||
if ([self isEqualToString:next]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
va_end(list);
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)hasPrefixIgnoringCase:(NSString *)aString
|
||||
{
|
||||
NSRange reange = [self rangeOfString:aString
|
||||
options:NSAnchoredSearch|NSCaseInsensitiveSearch];
|
||||
return reange.location != NSNotFound;
|
||||
}
|
||||
|
||||
- (BOOL)isHTMLWhitespaceString
|
||||
{
|
||||
return self.leadingHTMLWhitespaceLength == self.length;
|
||||
}
|
||||
|
||||
- (NSUInteger)leadingHTMLWhitespaceLength
|
||||
{
|
||||
size_t idx = 0;
|
||||
NSUInteger length = self.length;
|
||||
@@ -33,4 +58,15 @@ NS_INLINE BOOL isHtmlWhitespaceChar(unichar c)
|
||||
return idx;
|
||||
}
|
||||
|
||||
- (NSString *)stringByEscapingForHTML
|
||||
{
|
||||
NSMutableString *escaped = [self mutableCopy];
|
||||
[escaped replaceOccurrencesOfString:@"&" withString:@"&" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@"0x00A0" withString:@" " options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@"\"" withString:@""" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@"<" withString:@"<" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
[escaped replaceOccurrencesOfString:@">" withString:@">" options:0 range:NSMakeRange(0, escaped.length)];
|
||||
return escaped;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
//
|
||||
// NSString+Private.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 26.03.19.
|
||||
// Copyright © 2019 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSString+Private.h"
|
||||
|
||||
@implementation NSString (Private)
|
||||
|
||||
- (BOOL)isEqualToStringIgnoringCase:(NSString *)aString
|
||||
{
|
||||
return [self caseInsensitiveCompare:aString] == NSOrderedSame;
|
||||
}
|
||||
|
||||
- (BOOL)isEqualToAny:(NSString *)first, ... NS_REQUIRES_NIL_TERMINATION
|
||||
{
|
||||
va_list list;
|
||||
va_start(list, first);
|
||||
for (NSString *next = first; next != nil; next = va_arg(list, NSString *)) {
|
||||
if ([self isEqualToString:next]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
va_end(list);
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)hasPrefixIgnoringCase:(NSString *)aString
|
||||
{
|
||||
NSRange reange = [self rangeOfString:aString
|
||||
options:NSAnchoredSearch|NSCaseInsensitiveSearch];
|
||||
return reange.location != NSNotFound;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -6,10 +6,6 @@
|
||||
// Copyright (c) 2014 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
///------------------------------------------------------
|
||||
/// HTMLKit private header
|
||||
///------------------------------------------------------
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLToken.h"
|
||||
|
||||
|
||||
@@ -15,11 +15,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@interface HTMLComment : HTMLCharacterData
|
||||
|
||||
/**
|
||||
Decalration override for `NS_UNAVAILABLE` declared in `HTMLNode`
|
||||
*/
|
||||
- (instancetype)init;
|
||||
|
||||
/**
|
||||
Initializes a new HTML comment node.
|
||||
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
// Copyright (c) 2014 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
///------------------------------------------------------
|
||||
/// HTMLKit private header
|
||||
///------------------------------------------------------
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLToken.h"
|
||||
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
// Copyright (c) 2014 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
///------------------------------------------------------
|
||||
/// HTMLKit private header
|
||||
///------------------------------------------------------
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLToken.h"
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#import "HTMLRange.h"
|
||||
#import "HTMLDOMTokenList.h"
|
||||
#import "HTMLNodeIterator.h"
|
||||
#import "HTMLTreeVisitor.h"
|
||||
#import "HTMLTreeWalker.h"
|
||||
#import "HTMLNodeFilter.h"
|
||||
|
||||
|
||||
@@ -78,11 +78,6 @@ typedef NS_ENUM(short, HTMLDocumentReadyState)
|
||||
*/
|
||||
+ (instancetype)documentWithString:(NSString *)string;
|
||||
|
||||
/**
|
||||
Decalration override for `NS_UNAVAILABLE` declared in `HTMLNode`
|
||||
*/
|
||||
- (instancetype)init;
|
||||
|
||||
/**
|
||||
Adopts a given node into this document, i.e. the document becomes the new owner of the node. Raises a HTMLKitNotSupportedError
|
||||
exception if node is an instance of HTMLDocument.
|
||||
|
||||
@@ -18,11 +18,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@interface HTMLDocumentFragment : HTMLNode
|
||||
|
||||
/**
|
||||
Decalration override for `NS_UNAVAILABLE` declared in `HTMLNode`
|
||||
*/
|
||||
- (instancetype)init;
|
||||
|
||||
/**
|
||||
Initializes a new document fragment with the given document as owner.
|
||||
|
||||
|
||||
@@ -31,11 +31,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSString *systemIdentifier;
|
||||
|
||||
/**
|
||||
Decalration override for `NS_UNAVAILABLE` declared in `HTMLNode`
|
||||
*/
|
||||
- (instancetype)init;
|
||||
|
||||
/**
|
||||
Initializes and returns a new isntance of a Document Type node.
|
||||
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
///------------------------------------------------------
|
||||
/// HTMLKit private header
|
||||
///------------------------------------------------------
|
||||
|
||||
#import "HTMLToken.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,10 +10,9 @@
|
||||
/// HTMLKit private header
|
||||
///------------------------------------------------------
|
||||
|
||||
#import "HTMLNode+Private.h"
|
||||
#import "HTMLElement.h"
|
||||
#import "HTMLNamespaces.h"
|
||||
#import "NSString+Private.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
|
||||
NS_INLINE BOOL IsNodeMathMLTextIntegrationPoint(HTMLElement *node)
|
||||
{
|
||||
@@ -53,14 +52,3 @@ NS_INLINE BOOL IsSpecialElement(HTMLElement *element)
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
NS_INLINE BOOL DoesNodeSerializeAsVoid(HTMLNode *node)
|
||||
{
|
||||
if (node.nodeType != HTMLNodeElement) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return [node.asElement.tagName isEqualToAny:@"area", @"base", @"basefont", @"bgsound", @"br", @"col", @"embed",
|
||||
@"frame", @"hr", @"img", @"input", @"keygen", @"link", @"meta", @"param", @"source", @"track", @"wbr", nil];
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,8 @@ extern const unsigned char HTMLKitVersionString[];
|
||||
|
||||
#import "HTMLDOM.h"
|
||||
#import "HTMLParser.h"
|
||||
#import "HTMLSerializer.h"
|
||||
#import "HTMLSanitizer.h"
|
||||
|
||||
#import "HTMLKitErrorDomain.h"
|
||||
#import "HTMLOrderedDictionary.h"
|
||||
|
||||
|
||||
@@ -12,10 +12,6 @@
|
||||
|
||||
#import "HTMLNode.h"
|
||||
|
||||
@class HTMLText;
|
||||
@class HTMLComment;
|
||||
@class HTMLDocumentType;
|
||||
|
||||
/**
|
||||
Private HTML Node methods which are not intended for public API.
|
||||
*/
|
||||
@@ -48,21 +44,6 @@
|
||||
*/
|
||||
- (HTMLElement *)asElement;
|
||||
|
||||
/**
|
||||
Casts this node to a HTML Text. This cast should only be performed after the appropriate check.
|
||||
*/
|
||||
- (HTMLText *)asText;
|
||||
|
||||
/**
|
||||
Casts this node to a HTML Comment. This cast should only be performed after the appropriate check.
|
||||
*/
|
||||
- (HTMLComment *)asComment;
|
||||
|
||||
/**
|
||||
Casts this node to a HTML Document Type. This cast should only be performed after the appropriate check.
|
||||
*/
|
||||
- (HTMLDocumentType *)asDocumentType;
|
||||
|
||||
/**
|
||||
Returns the same string representation of the DOM tree rooted at this node that is used by html5lib-tests.
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLNodeIterator.h"
|
||||
#import "HTMLTreeVisitor.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
//
|
||||
// HTMLNodeVisitor.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 30.07.19.
|
||||
// Copyright © 2019 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class HTMLNode;
|
||||
|
||||
#pragma mark - Node Visitor
|
||||
|
||||
/**
|
||||
A HTML Node Visitor which can be used with a tree visitor.
|
||||
|
||||
@see HTMLTreeVisitor
|
||||
*/
|
||||
@protocol HTMLNodeVisitor <NSObject>
|
||||
@required
|
||||
|
||||
/**
|
||||
Called when visiting the node for the first time
|
||||
|
||||
@param node The node that is beaing visited for the first time.
|
||||
*/
|
||||
- (void)enter:(HTMLNode *)node;
|
||||
|
||||
/**
|
||||
Called when leaving a previously entered node, i.e. when all its child nodes are visited.
|
||||
|
||||
@param node The node that beaing leaved.
|
||||
*/
|
||||
- (void)leave:(HTMLNode *)node;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Block Node Visitor
|
||||
|
||||
/**
|
||||
A concrete block-based HTML Node Visitor implementation.
|
||||
*/
|
||||
@interface HTMLNodeVisitorBlock : NSObject <HTMLNodeVisitor>
|
||||
|
||||
/**
|
||||
Initializes and returns a new instance of this visitor.
|
||||
|
||||
@param enterBlock The block to apply on entering a visited node.
|
||||
@param leaveBlock The block to apply on leaving a visited node.
|
||||
*/
|
||||
+ (instancetype)visitorWithEnterBlock:(void (^)(HTMLNode *node))enterBlock
|
||||
leaveBlock:(void (^)(HTMLNode *node))leaveBlock;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -6,10 +6,6 @@
|
||||
// Copyright (c) 2014 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
///------------------------------------------------------
|
||||
/// HTMLKit private header
|
||||
///------------------------------------------------------
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLToken.h"
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
// Copyright (c) 2015 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSString+HTMLKit.h"
|
||||
|
||||
/**
|
||||
HTML quirks modes
|
||||
https://html.spec.whatwg.org/multipage/infrastructure.html#quirks-mode
|
||||
@@ -80,4 +82,12 @@ static NSString * HTMLQuirksModePrefixes[] = {
|
||||
#undef QUIRKS_ENTRY
|
||||
};
|
||||
|
||||
extern BOOL QuirksModePrefixMatch(NSString *publicIdentifier);
|
||||
NS_INLINE BOOL QuirksModePrefixMatch(NSString *publicIdentifier)
|
||||
{
|
||||
for (int i = 0; i < sizeof(HTMLQuirksModePrefixes) / sizeof(HTMLQuirksModePrefixes[0]); i++) {
|
||||
if ([publicIdentifier hasPrefixIgnoringCase:HTMLQuirksModePrefixes[i]]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
//
|
||||
// HTMLSerializer.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 28.07.19.
|
||||
// Copyright © 2019 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class HTMLNode;
|
||||
|
||||
/**
|
||||
The scope for HTML Serialization.
|
||||
*/
|
||||
typedef NS_ENUM(unsigned short, HTMLSerializationScope)
|
||||
{
|
||||
HTMLSerializationScopeIncludeRoot = 1,
|
||||
HTMLSerializationScopeChildrenOnly = 2
|
||||
};
|
||||
|
||||
/**
|
||||
A HTML DOM Serializer. Used to serialize HTML Tree rooted at a given node with the desired scope:
|
||||
|
||||
- IncludeRoot scope includes the given node into the serialized result, e.g. HTML Node's `outerHTML`
|
||||
- ChildrenOnly scope serializes only the child nodes of the given node, e.g. HTML Node's `innerHTML`
|
||||
|
||||
https://html.spec.whatwg.org/multipage/parsing.html#serialising-html-fragments
|
||||
*/
|
||||
@interface HTMLSerializer : NSObject
|
||||
|
||||
/**
|
||||
Serializes the given node with the given scope.
|
||||
|
||||
@param node The root node of the tree to serialize
|
||||
@param scope The scope for serialization
|
||||
*/
|
||||
+ (NSString *)serializeNode:(HTMLNode *)node scope:(HTMLSerializationScope)scope;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
// Copyright (c) 2014 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
///------------------------------------------------------
|
||||
/// HTMLKit private header
|
||||
///------------------------------------------------------
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLToken.h"
|
||||
#import "HTMLOrderedDictionary.h"
|
||||
|
||||
@@ -18,11 +18,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@interface HTMLTemplate : HTMLElement
|
||||
|
||||
/**
|
||||
Decalration override for `NS_UNAVAILABLE` declared in `HTMLNode`
|
||||
*/
|
||||
- (instancetype)init;
|
||||
|
||||
/**
|
||||
The content of the template.
|
||||
|
||||
|
||||
@@ -15,11 +15,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@interface HTMLText : HTMLCharacterData
|
||||
|
||||
/**
|
||||
Decalration override for `NS_UNAVAILABLE` declared in `HTMLNode`
|
||||
*/
|
||||
- (instancetype)init;
|
||||
|
||||
/**
|
||||
Initializes a new HTML text node.
|
||||
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
// Copyright (c) 2014 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
///------------------------------------------------------
|
||||
/// HTMLKit private header
|
||||
///------------------------------------------------------
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class HTMLDOCTYPEToken;
|
||||
|
||||
@@ -6,10 +6,6 @@
|
||||
// Copyright (c) 2014 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
///------------------------------------------------------
|
||||
/// HTMLKit private header
|
||||
///------------------------------------------------------
|
||||
|
||||
#import "HTMLToken.h"
|
||||
#import "HTMLCharacterToken.h"
|
||||
#import "HTMLCommentToken.h"
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
//
|
||||
// HTMLTreeVisitor.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 30.07.19.
|
||||
// Copyright © 2019 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HTMLNodeVisitor.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class HTMLNode;
|
||||
|
||||
/**
|
||||
A HTML Tree Visitor that walks the DOM in tree order. Nodes are visited exacly once
|
||||
|
||||
The provided node visitor is called for each node twice, once when entering the node,
|
||||
and once again when leaving the node.
|
||||
|
||||
@see HTMLNodeVisitor
|
||||
*/
|
||||
@interface HTMLTreeVisitor : NSObject
|
||||
|
||||
/**
|
||||
Initializes a new tree visitor with.
|
||||
|
||||
@param node The root node.
|
||||
|
||||
@return A new instance of a tree visitor.
|
||||
*/
|
||||
- (instancetype)initWithNode:(HTMLNode *)node;
|
||||
|
||||
/**
|
||||
Walks the DOM tree rooted at the provided node with the given node visitor.
|
||||
|
||||
@param visitor A HTMLNodeVisitor implementation.
|
||||
*/
|
||||
- (void)walkWithNodeVisitor:(id<HTMLNodeVisitor>)visitor;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -19,18 +19,17 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
A character set for HTML whitespace characters: CHARACTER TABULATION U+0009, LINE FEED U+000A, FORM FEED U+000C,
|
||||
CARRIAGE RETURN U+000D, and SPACE U+0020.
|
||||
*/
|
||||
|
||||
+ (instancetype)htmlkit_HTMLWhitespaceCharacterSet;
|
||||
+ (instancetype)HTMLWhitespaceCharacterSet;
|
||||
|
||||
/**
|
||||
A character set for HTML HEX-Number characters: The digits 0-9, latin small letters a-f, and latin capital letters A-F.
|
||||
*/
|
||||
+ (instancetype)htmlkit_HTMLHexNumberCharacterSet;
|
||||
+ (instancetype)HTMLHexNumberCharacterSet;
|
||||
|
||||
/**
|
||||
A character set for CSS Nth-Expression: The digits 0-9, space, latin small n, latin capital N, plus sing and minus sign.
|
||||
*/
|
||||
+ (instancetype)htmlkit_CSSNthExpressionCharacterSet;
|
||||
+ (instancetype)CSSNthExpressionCharacterSet;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -15,17 +15,45 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@interface NSString (HTMLKit)
|
||||
|
||||
/**
|
||||
Checks whether this string is equal to another ignoring the case.
|
||||
|
||||
@return `YES` if the two string are equal ignroing the case, `NO` otherwise.
|
||||
*/
|
||||
- (BOOL)isEqualToStringIgnoringCase:(NSString *)aString;
|
||||
|
||||
/**
|
||||
Checks whether this string is equal to any of the given strings.
|
||||
|
||||
@return `YES` if there is an equal string, `NO` otherwise.
|
||||
*/
|
||||
- (BOOL)isEqualToAny:(NSString *)first, ... NS_REQUIRES_NIL_TERMINATION;
|
||||
|
||||
/**
|
||||
Checks whether this string has a prefix ignoring the case.
|
||||
|
||||
@return `YES` if this string has a given prefix ignroing the case, `NO` otherwise.
|
||||
*/
|
||||
- (BOOL)hasPrefixIgnoringCase:(NSString *)aString;
|
||||
|
||||
/**
|
||||
Checks whether this string is a HTML whitespace string.
|
||||
|
||||
@return `YES` if this string is a HTML whitespace string, `NO` otherwise.
|
||||
*/
|
||||
- (BOOL)htmlkit_isHTMLWhitespaceString;
|
||||
- (BOOL)isHTMLWhitespaceString;
|
||||
|
||||
/**
|
||||
@return The length of the leading HTML whitespace characters in this string.
|
||||
*/
|
||||
- (NSUInteger)htmlkit_leadingHTMLWhitespaceLength;
|
||||
- (NSUInteger)leadingHTMLWhitespaceLength;
|
||||
|
||||
/**
|
||||
Escapes this string as specified in `https://html.spec.whatwg.org/multipage/parsing.html#escapingString`
|
||||
|
||||
@return A copy of this string by HTML-escaping this stirng.
|
||||
*/
|
||||
- (NSString *)stringByEscapingForHTML;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
//
|
||||
// NSString+Private.h
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 26.03.19.
|
||||
// Copyright © 2019 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
///------------------------------------------------------
|
||||
/// HTMLKit private header
|
||||
///------------------------------------------------------
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
NSStirng category for common helper methods.
|
||||
*/
|
||||
@interface NSString (Private)
|
||||
|
||||
/**
|
||||
Checks whether this string is equal to another ignoring the case.
|
||||
|
||||
@return `YES` if the two string are equal ignroing the case, `NO` otherwise.
|
||||
*/
|
||||
- (BOOL)isEqualToStringIgnoringCase:(NSString *)aString;
|
||||
|
||||
/**
|
||||
Checks whether this string is equal to any of the given strings.
|
||||
|
||||
@return `YES` if there is an equal string, `NO` otherwise.
|
||||
*/
|
||||
- (BOOL)isEqualToAny:(NSString *)first, ... NS_REQUIRES_NIL_TERMINATION;
|
||||
|
||||
/**
|
||||
Checks whether this string has a prefix ignoring the case.
|
||||
|
||||
@return `YES` if this string has a given prefix ignroing the case, `NO` otherwise.
|
||||
*/
|
||||
- (BOOL)hasPrefixIgnoringCase:(NSString *)aString;
|
||||
|
||||
@end
|
||||
@@ -34,6 +34,5 @@ module HTMLKit {
|
||||
header "HTMLParser+Private.h"
|
||||
header "HTMLNodeTraversal.h"
|
||||
header "HTMLDOMUtils.h"
|
||||
header "NSString+Private.h"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,43 +0,0 @@
|
||||
//
|
||||
// HTMLKitParserTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 16.07.18.
|
||||
// Copyright © 2018 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "HTMLDOM.h"
|
||||
|
||||
@interface HTMLKitParserIssuesTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation HTMLKitParserIssuesTests
|
||||
|
||||
#pragma mark - Bug Fixes
|
||||
|
||||
- (void)testBugFix_Issue_30 {
|
||||
NSString *html =
|
||||
@"<body>"
|
||||
" <svg id='draw_area' width='600' height='800' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1'>"
|
||||
" <image id='overlay_img' xlink:href='foo.png' width='600' height='800'/>"
|
||||
" </svg>"
|
||||
"</body>";
|
||||
|
||||
HTMLDocument* document = [HTMLDocument documentWithString:html];
|
||||
HTMLElement *svg = [document querySelector:@"#draw_area"];
|
||||
|
||||
XCTAssertNil(svg.attributes[@"xlink"]);
|
||||
XCTAssertEqualObjects(svg.attributes[@"xmlns"], @"http://www.w3.org/2000/svg");
|
||||
XCTAssertEqualObjects(svg.attributes[@"xmlns:xlink"], @"http://www.w3.org/1999/xlink");
|
||||
|
||||
HTMLElement *image = [document querySelector:@"#overlay_img"];
|
||||
|
||||
XCTAssertNil(image.attributes[@"xlink"]);
|
||||
XCTAssertNil(image.attributes[@"href"]);
|
||||
XCTAssertEqualObjects(image.attributes[@"xlink:href"], @"foo.png");
|
||||
XCTAssertEqualObjects(image.outerHTML, @"<image id=\"overlay_img\" xlink:href=\"foo.png\" width=\"600\" height=\"800\"></image>");
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -7,7 +7,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>dev.iabudiab.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<string>com.braincookie.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
@@ -580,20 +580,19 @@ static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node)
|
||||
XCTAssertNotNil(body);
|
||||
|
||||
// iterator should be deallocated and detached at this point
|
||||
XCTAssertEqual(0, nodeIterators.allObjects.count);
|
||||
XCTAssertEqual(0, nodeIterators.count);
|
||||
|
||||
// iterator should be autoreleased, deallocated and detached after autoreleasepool
|
||||
@autoreleasepool {
|
||||
HTMLNodeIterator *iterator = [[HTMLNodeIterator alloc] initWithNode:body];
|
||||
[iterator nextNode];
|
||||
XCTAssertEqual(1, nodeIterators.allObjects.count);
|
||||
XCTAssertEqual(1, nodeIterators.count);
|
||||
}
|
||||
|
||||
XCTAssertEqual(0, nodeIterators.allObjects.count);
|
||||
XCTAssertEqual(0, nodeIterators.count);
|
||||
}
|
||||
|
||||
- (void)testBugFix_Issue_22
|
||||
{
|
||||
- (void)testBugFix_Issue_22 {
|
||||
// The issue is applicable only for devices. On simulator the test is passed.
|
||||
HTMLDocument *document = [HTMLDocument documentWithString:@"<div id=\"id\"></div>"];
|
||||
|
||||
@@ -609,8 +608,7 @@ static HTMLNode * (^ LastDescendant)(HTMLNode *) = ^ HTMLNode * (HTMLNode *node)
|
||||
XCTAssertTrue([element.elementId isEqualToString:divId]);
|
||||
}
|
||||
|
||||
- (void)testBugFix_Issue_28
|
||||
{
|
||||
- (void)testBugFix_Issue_28 {
|
||||
HTMLDocument *document = self.document;
|
||||
HTMLNodeIterator *iterator = document.body.nodeIterator;
|
||||
|
||||
|
||||
@@ -495,7 +495,9 @@
|
||||
XCTAssertTrue([paragraph compareDocumentPositionWithNode:paragraph] == HTMLDocumentPositionEquivalent);
|
||||
|
||||
HTMLElement *element = [HTMLElement new];
|
||||
XCTAssertTrue([paragraph compareDocumentPositionWithNode:element] == HTMLDocumentPositionPreceding);
|
||||
XCTAssertTrue([paragraph compareDocumentPositionWithNode:element] ==
|
||||
(HTMLDocumentPositionDisconnected | HTMLDocumentPositionImplementationSpecific |
|
||||
paragraph.hash < element.hash ? HTMLDocumentPositionPreceding: HTMLDocumentPositionFollowing));
|
||||
|
||||
XCTAssertTrue([paragraph compareDocumentPositionWithNode:image] == HTMLDocumentPositionPreceding);
|
||||
XCTAssertTrue([anchor compareDocumentPositionWithNode:image] == HTMLDocumentPositionPreceding);
|
||||
|
||||
@@ -2112,10 +2112,10 @@
|
||||
@autoreleasepool {
|
||||
HTMLRange *range = [[HTMLRange alloc] initWithDocument:document];
|
||||
[range cloneContents];
|
||||
XCTAssertEqual(1, ranges.allObjects.count);
|
||||
XCTAssertEqual(1, ranges.count);
|
||||
}
|
||||
|
||||
XCTAssertEqual(0, ranges.allObjects.count);
|
||||
XCTAssertEqual(0, ranges.count);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,19 +8,6 @@
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "HTMLDOM.h"
|
||||
#import "HTMLKitTestUtil.h"
|
||||
|
||||
#define Assert(input, expected) \
|
||||
do { \
|
||||
HTMLDocument *document = [HTMLDocument documentWithString:input]; \
|
||||
XCTAssertEqualObjects(document.body.innerHTML, expected); \
|
||||
} while(0)
|
||||
|
||||
#define AssertH(input, expected) \
|
||||
do { \
|
||||
HTMLDocument *document = [HTMLDocument documentWithString:input]; \
|
||||
XCTAssertEqualObjects(document.head.innerHTML, expected); \
|
||||
} while(0)
|
||||
|
||||
@interface HTMLSerializationTests : XCTestCase
|
||||
|
||||
@@ -28,47 +15,12 @@
|
||||
|
||||
@implementation HTMLSerializationTests
|
||||
|
||||
- (void)testSerializer
|
||||
{
|
||||
Assert(@"", @"");
|
||||
Assert(@"<a a=\r\n", @"");
|
||||
Assert(@"<p><i>Hello!</p>, World!</i>", @"<p><i>Hello!</i></p><i>, World!</i>");
|
||||
Assert(@"<p><i>Hello</i>, World!</p>", @"<p><i>Hello</i>, World!</p>");
|
||||
AssertH(@"<base foo=\"<'>\">", @"<base foo=\"<'>\">");
|
||||
AssertH(@"<base foo=\"&\">", @"<base foo=\"&\">");
|
||||
AssertH(@"<base foo=&>", @"<base foo=\"&\">");
|
||||
AssertH(@"<base foo=x0x00A0y>", @"<base foo=\"x y\">");
|
||||
AssertH(@"<base foo='\"'>", @"<base foo=\""\">");
|
||||
Assert(@"<span foo=3 title='test \"with\" &quot;'>", @"<span foo=\"3\" title=\"test "with" &quot;\"></span>");
|
||||
Assert(@"<p>\"'\"</p>", @"<p>\"'\"</p>");
|
||||
Assert(@"<p>&</p>", @"<p>&</p>");
|
||||
Assert(@"<p>&</p>", @"<p>&</p>");
|
||||
Assert(@"<p><</p>", @"<p><</p>");
|
||||
Assert(@"<p>></p>", @"<p>></p>");
|
||||
Assert(@"<p>></p>", @"<p>></p>");
|
||||
AssertH(@"<script>(x & 1) < 2; y > \"foo\" + 'bar'</script>", @"<script>(x & 1) < 2; y > \"foo\" + 'bar'</script>");
|
||||
AssertH(@"<style>(x & 1) < 2; y > \"foo\" + 'bar'</style>", @"<style>(x & 1) < 2; y > \"foo\" + 'bar'</style>");
|
||||
Assert(@"<xmp>(x & 1) < 2; y > \"foo\" + 'bar'</xmp>", @"<xmp>(x & 1) < 2; y > \"foo\" + 'bar'</xmp>");
|
||||
Assert(@"<iframe>(x & 1) < 2; y > \"foo\" + 'bar'</iframe>", @"<iframe>(x & 1) < 2; y > \"foo\" + 'bar'</iframe>");
|
||||
Assert(@"<noembed>(x & 1) < 2; y > \"foo\" + 'bar'</noembed>", @"<noembed>(x & 1) < 2; y > \"foo\" + 'bar'</noembed>");
|
||||
AssertH(@"<noframes>(x & 1) < 2; y > \"foo\" + 'bar'</noframes>", @"<noframes>(x & 1) < 2; y > \"foo\" + 'bar'</noframes>");
|
||||
Assert(@"<pre>foo bar</pre>", @"<pre>foo bar</pre>");
|
||||
Assert(@"<pre>\nfoo bar</pre>", @"<pre>foo bar</pre>");
|
||||
Assert(@"<pre>\n\nfoo bar</pre>", @"<pre>\nfoo bar</pre>");
|
||||
Assert(@"<textarea>foo bar</textarea>", @"<textarea>foo bar</textarea>");
|
||||
Assert(@"<textarea>\nfoo bar</textarea>", @"<textarea>foo bar</textarea>");
|
||||
Assert(@"<textarea>\n\nfoo bar</textarea>", @"<textarea>\nfoo bar</textarea>");
|
||||
Assert(@"<listing>foo bar</listing>", @"<listing>foo bar</listing>");
|
||||
Assert(@"<listing>\nfoo bar</listing>", @"<listing>foo bar</listing>");
|
||||
Assert(@"<listing>\n\nfoo bar</listing>", @"<listing>\nfoo bar</listing>");
|
||||
Assert(@"<p>hi <!--world--></p>", @"<p>hi <!--world--></p>");
|
||||
Assert(@"<p>hi <!-- world--></p>", @"<p>hi <!-- world--></p>");
|
||||
Assert(@"<p>hi <!--world --></p>", @"<p>hi <!--world --></p>");
|
||||
Assert(@"<p>hi <!-- world --></p>", @"<p>hi <!-- world --></p>");
|
||||
Assert(@"<svg xmlns=\"bleh\"></svg>", @"<svg xmlns=\"bleh\"></svg>");
|
||||
Assert(@"<svg xmlns:foo=\"bleh\"></svg>", @"<svg xmlns:foo=\"bleh\"></svg>");
|
||||
Assert(@"<svg xmlns:xlink=\"bleh\"></svg>", @"<svg xmlns:xlink=\"bleh\"></svg>");
|
||||
Assert(@"<svg xlink:href=\"bleh\"></svg>", @"<svg xlink:href=\"bleh\"></svg>");
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
#pragma mark - Bug Fixes
|
||||
@@ -89,19 +41,4 @@
|
||||
XCTAssertEqualObjects(document.body.outerHTML, @"<body key=\"& testing \"></body>");
|
||||
}
|
||||
|
||||
- (void)testBugFix_Issue_33
|
||||
{
|
||||
NSString *path = [HTMLKitTestUtil pathForFixture:@"bug33" ofType:@"html" inDirectory:@"Fixtures"];
|
||||
NSString *html = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
|
||||
HTMLDocument *document = [HTMLDocument documentWithString:html];
|
||||
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"HTML serializes despite limited recursion depth"];
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||
[document.rootElement outerHTML];
|
||||
[expectation fulfill];
|
||||
});
|
||||
|
||||
[self waitForExpectationsWithTimeout:500 handler:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "NSString+Private.h"
|
||||
#import "NSString+HTMLKit.h"
|
||||
#import "HTMLDOM.h"
|
||||
|
||||
@interface HTMLKitStringCategoryTests : XCTestCase
|
||||
|
||||
@@ -51,33 +51,49 @@
|
||||
|
||||
- (void)testIsHTMLWhitespaceString
|
||||
{
|
||||
XCTAssertTrue([@" " htmlkit_isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@"\t" htmlkit_isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@"\n" htmlkit_isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@"\f" htmlkit_isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@"\r" htmlkit_isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@" \t\n\f\r" htmlkit_isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@"\t\n\f\r " htmlkit_isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@" \t \n \f \r" htmlkit_isHTMLWhitespaceString]);
|
||||
XCTAssertFalse([@"html kit" htmlkit_isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@" " isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@"\t" isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@"\n" isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@"\f" isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@"\r" isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@" \t\n\f\r" isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@"\t\n\f\r " isHTMLWhitespaceString]);
|
||||
XCTAssertTrue([@" \t \n \f \r" isHTMLWhitespaceString]);
|
||||
XCTAssertFalse([@"html kit" isHTMLWhitespaceString]);
|
||||
}
|
||||
|
||||
- (void)testLeadingWhitespaceLength
|
||||
{
|
||||
XCTAssertEqual([@"" htmlkit_leadingHTMLWhitespaceLength], 0);
|
||||
XCTAssertEqual([@"\0" htmlkit_leadingHTMLWhitespaceLength], 0);
|
||||
XCTAssertEqual([@"" leadingHTMLWhitespaceLength], 0);
|
||||
XCTAssertEqual([@"\0" leadingHTMLWhitespaceLength], 0);
|
||||
|
||||
XCTAssertEqual([@" " htmlkit_leadingHTMLWhitespaceLength], 1);
|
||||
XCTAssertEqual([@"\0 " htmlkit_leadingHTMLWhitespaceLength], 0);
|
||||
XCTAssertEqual([@" " leadingHTMLWhitespaceLength], 1);
|
||||
XCTAssertEqual([@"\0 " leadingHTMLWhitespaceLength], 0);
|
||||
|
||||
XCTAssertEqual([@" " htmlkit_leadingHTMLWhitespaceLength], 2);
|
||||
XCTAssertEqual([@" \0 " htmlkit_leadingHTMLWhitespaceLength], 1);
|
||||
XCTAssertEqual([@" " leadingHTMLWhitespaceLength], 2);
|
||||
XCTAssertEqual([@" \0 " leadingHTMLWhitespaceLength], 1);
|
||||
|
||||
XCTAssertEqual([@"\t\r\n\f" htmlkit_leadingHTMLWhitespaceLength], 4);
|
||||
XCTAssertEqual([@"\t\r\n\0\f" htmlkit_leadingHTMLWhitespaceLength], 3);
|
||||
XCTAssertEqual([@"\t\r\n\f" leadingHTMLWhitespaceLength], 4);
|
||||
XCTAssertEqual([@"\t\r\n\0\f" leadingHTMLWhitespaceLength], 3);
|
||||
|
||||
XCTAssertEqual([@"\t\r\n\f " htmlkit_leadingHTMLWhitespaceLength], 5);
|
||||
XCTAssertEqual([@"\t\r\n\f\0 " htmlkit_leadingHTMLWhitespaceLength], 4);
|
||||
XCTAssertEqual([@"\t\r\n\f " leadingHTMLWhitespaceLength], 5);
|
||||
XCTAssertEqual([@"\t\r\n\f\0 " leadingHTMLWhitespaceLength], 4);
|
||||
}
|
||||
|
||||
- (void)testStringByEscapingForHTML
|
||||
{
|
||||
XCTAssertEqualObjects(@"".stringByEscapingForHTML, @"");
|
||||
XCTAssertEqualObjects(@"&".stringByEscapingForHTML, @"&");
|
||||
XCTAssertEqualObjects(@"0x00A0".stringByEscapingForHTML, @" ");
|
||||
XCTAssertEqualObjects(@"\"".stringByEscapingForHTML, @""");
|
||||
XCTAssertEqualObjects(@"<".stringByEscapingForHTML, @"<");
|
||||
XCTAssertEqualObjects(@">".stringByEscapingForHTML, @">");
|
||||
XCTAssertEqualObjects(@"&0x00A0\"<>".stringByEscapingForHTML, @"& "<>");
|
||||
|
||||
NSString *input = @"This is an <b>email</b>: John Do <john@do.com>";
|
||||
NSString *escaped = input.stringByEscapingForHTML;
|
||||
XCTAssertNotEqual(input, escaped);
|
||||
XCTAssertEqualObjects(escaped, @"This is an <b>email</b>: John Do <john@do.com>");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
//
|
||||
// HTMLTreeVisitorTests.m
|
||||
// HTMLKit
|
||||
//
|
||||
// Created by Iska on 30.07.19.
|
||||
// Copyright © 2019 BrainCookie. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "HTMLDOM.h"
|
||||
#import "HTMLElement.h"
|
||||
#import "HTMLNode+Private.h"
|
||||
|
||||
@interface HTMLTreeVisitorTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation HTMLTreeVisitorTests
|
||||
|
||||
#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 - Basic Walking
|
||||
|
||||
- (HTMLNode *)testDOM
|
||||
{
|
||||
// Tree structure:
|
||||
// #a
|
||||
// |
|
||||
// +----+----+
|
||||
// | |
|
||||
// #b #c
|
||||
// |
|
||||
// +----+----+
|
||||
// | |
|
||||
// #d #j
|
||||
// |
|
||||
// +----+----+
|
||||
// | | |
|
||||
// #e #f #i
|
||||
// |
|
||||
// +--+--+
|
||||
// | |
|
||||
// #g #h
|
||||
|
||||
HTMLElement *div = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"a"}];
|
||||
|
||||
[div appendNode:[[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"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:[[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"j"}]];
|
||||
|
||||
[d appendNode:[[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"e"}]];
|
||||
|
||||
HTMLElement *f = [[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"f"}];
|
||||
[d appendNode:f];
|
||||
[d appendNode:[[HTMLElement alloc] initWithTagName:@"div" attributes:@{@"id": @"i"}]];
|
||||
|
||||
[f appendNode:[[HTMLElement alloc] initWithTagName:@"g" attributes:@{@"id": @"g"}]];
|
||||
[f appendNode:[[HTMLElement alloc] initWithTagName:@"h" attributes:@{@"id": @"h"}]];
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
- (void)testTreeVisitor
|
||||
{
|
||||
HTMLNode *root = self.testDOM;
|
||||
HTMLTreeVisitor *visitor = [[HTMLTreeVisitor alloc] initWithNode:root];
|
||||
|
||||
NSMutableArray *visited = [NSMutableArray array];
|
||||
|
||||
[visitor walkWithNodeVisitor:[HTMLNodeVisitorBlock visitorWithEnterBlock:^(HTMLNode *node) {
|
||||
[visited addObject:[NSString stringWithFormat:@"E %@", node.asElement.elementId]];
|
||||
} leaveBlock:^(HTMLNode *node) {
|
||||
[visited addObject:[NSString stringWithFormat:@"L %@", node.asElement.elementId]];
|
||||
}]];
|
||||
|
||||
NSArray *expected = @[@"E a", @"E b", @"L b", @"E c", @"E d", @"E e", @"L e", @"E f", @"E g", @"L g", @"E h", @"L h",
|
||||
@"L f", @"E i", @"L i", @"L d", @"E j", @"L j", @"L c", @"L a"];
|
||||
|
||||
XCTAssertEqualObjects(visited, expected);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "HTMLTreeWalker.h"
|
||||
#import "HTMLDOM.h"
|
||||
#import "HTMLNode+Private.h"
|
||||
|
||||
|
||||
+1
-1
Submodule Tests/html5lib-tests updated: e52ff68cc7...515dc09aaa
Reference in New Issue
Block a user