Skip to content

Commit e1ad2bc

Browse files
authored
Merge pull request #56 from GeekTree0101/bug/VEditorKit-Support-HTML-Entitles-Handler
[BUG] Support HTML Entitles
2 parents 7d95004 + f7e8827 commit e1ad2bc

4 files changed

Lines changed: 85 additions & 6 deletions

File tree

Example/Tests/VEditorParserSpec.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,21 @@ class VEditorParserSpec: QuickSpec {
7272
.to(beTrue())
7373
}
7474
}
75+
76+
context("HTML Entities handling test") {
77+
78+
it("should be success to parse with HTML entities") {
79+
80+
expect(parser.parseXMLToAttributedString("<p>hello &amp; world</p>").string == "hello & world")
81+
.to(beTrue())
82+
}
83+
84+
it("should be fail to parse with HTML entities") {
85+
86+
expect(parser.parseXMLToAttributedString("<p>hello & world</p>").string == "hello & world")
87+
.to(beFalse())
88+
}
89+
}
7590
}
7691
}
7792
}

Example/Tests/VEditorXMLBuilderSpec.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,50 @@ class VEditorXMLBuilderSpec: QuickSpec {
9292
.to(equal("<content><p>hello<b>world</b>!</p><h2>headingTest</h2><p><b><i>boldItalicTest</i></b></p></content>"))
9393
}
9494
}
95+
96+
context("HTML Entities handling test") {
97+
98+
var testContents: [VEditorContent]!
99+
100+
beforeEach {
101+
var pTagStyle = EditorRule.init().paragraphStyle("p", attributes: [:])
102+
pTagStyle?.add(extraAttributes: [VEditorAttributeKey: ["p"]])
103+
let textNode = NSMutableAttributedString.init()
104+
textNode.append("hello & world".styled(with: pTagStyle!))
105+
testContents = [textNode]
106+
VEditorXMLBuilder.shared.encodingHTMLEntitiesExternalHandler = nil
107+
}
108+
109+
it("should be success to build with default HTML entities") {
110+
expect(VEditorXMLBuilder.shared.encodingHTMLEntitiesExternalHandler)
111+
.to(beNil())
112+
expect(VEditorXMLBuilder.shared.buildXML(testContents, rule: rule, packageTag: "content"))
113+
.to(equal("<content><p>hello &amp; world</p></content>"))
114+
}
115+
116+
it("should be success to build with custom HTML entities") {
117+
VEditorXMLBuilder.shared.encodingHTMLEntitiesExternalHandler = { text -> String in
118+
return text.replacingOccurrences(of: "&", with: "&amp;")
119+
}
120+
121+
expect(VEditorXMLBuilder.shared.encodingHTMLEntitiesExternalHandler)
122+
.toNot(beNil())
123+
expect(VEditorXMLBuilder.shared.buildXML(testContents, rule: rule, packageTag: "content"))
124+
.to(equal("<content><p>hello &amp; world</p></content>"))
125+
}
126+
127+
it("should be fail to build with custom HTML entities") {
128+
129+
VEditorXMLBuilder.shared.encodingHTMLEntitiesExternalHandler = { text -> String in
130+
return text
131+
}
132+
133+
expect(VEditorXMLBuilder.shared.encodingHTMLEntitiesExternalHandler)
134+
.toNot(beNil())
135+
expect(VEditorXMLBuilder.shared.buildXML(testContents, rule: rule, packageTag: "content"))
136+
.toNot(equal("<content><p>hello &amp; world</p></content>"))
137+
}
138+
}
95139
}
96140

97141
}

VEditorKit/Classes/VEditorParser.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,7 @@ public final class VEditorParser: NSObject, XMLStyler {
3838
public func parseXML(_ xmlString: String,
3939
onSuccess: (([VEditorContent]) -> Void)? = nil,
4040
onError: ((Error?) -> Void)? = nil) {
41-
var xmlString = xmlString
42-
.replacingOccurrences(of: "\\n", with: "\n")
43-
.replacingOccurrences(of: "\\", with: "")
41+
var xmlString = xmlString.convertDuplicatedBackSlashToValidParserXML()
4442

4543
// make newlink before block heading if needs
4644
for blockXML in parserRule.blockStyleXMLTags {
@@ -193,7 +191,7 @@ internal class VEditorContentParser: NSObject, XMLParserDelegate {
193191

194192
func parser(_ parser: XMLParser, foundCharacters string: String) {
195193
if self.contents.last is String {
196-
self.contents.append(string)
194+
self.contents.append(string.encodingHTMLEntities())
197195
}
198196
}
199197

VEditorKit/Classes/VEditorXMLBuilder.swift

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import BonMot
1212
public final class VEditorXMLBuilder {
1313

1414
public static let shared: VEditorXMLBuilder = .init()
15+
public var encodingHTMLEntitiesExternalHandler: ((String) -> String)?
1516

1617
public func buildXML(_ contents: [VEditorContent],
1718
rule: VEditorRule,
@@ -73,8 +74,7 @@ public final class VEditorXMLBuilder {
7374
using: { attributes, subRange, _ in
7475

7576
var content = attrText.attributedSubstring(from: subRange).string
76-
content = content
77-
.replacingOccurrences(of: "\"", with: "\\")
77+
content = content.encodingHTMLEntities()
7878

7979
guard !content.isEmpty else { return }
8080

@@ -148,4 +148,26 @@ extension String {
148148
}
149149
return xmlString
150150
}
151+
152+
internal func encodingHTMLEntities() -> String {
153+
guard let handler = VEditorXMLBuilder.shared.encodingHTMLEntitiesExternalHandler else {
154+
// NOTE: default encoding HTML Entities for VEditor
155+
// ref: https://dev.w3.org/html5/html-author/charref
156+
return self.replacingOccurrences(of: "&", with: "&amp;")
157+
.replacingOccurrences(of: "<", with: "&lt;")
158+
.replacingOccurrences(of: ">", with: "&gt;")
159+
.replacingOccurrences(of: "\"", with: "&quot;")
160+
.replacingOccurrences(of: "'", with: "&#x27;")
161+
.replacingOccurrences(of: "'", with: "&#x39;")
162+
.replacingOccurrences(of: "'", with: "&#x92;")
163+
.replacingOccurrences(of: "'", with: "&#x96;")
164+
}
165+
166+
return handler(self)
167+
}
168+
169+
internal func convertDuplicatedBackSlashToValidParserXML() -> String {
170+
return self.replacingOccurrences(of: "\\n", with: "\n")
171+
.replacingOccurrences(of: "\\", with: "")
172+
}
151173
}

0 commit comments

Comments
 (0)