Skip to content

Commit b80781a

Browse files
authored
Fix injecting the dir attribute when already present (#312)
1 parent e94b8f7 commit b80781a

File tree

4 files changed

+46
-1
lines changed

4 files changed

+46
-1
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ All notable changes to this project will be documented in this file. Take a look
2525
* The `WKWebView` is now inspectable again with Safari starting from iOS 16.4.
2626
* Fixed crash in the `PublicationSpeechSynthesizer` when closing the navigator without stopping it first.
2727
* Fixed the audio session kept opened while the app is in the background and paused.
28+
* Fixed the **Attribute dir redefined** error when the EPUB resource already has a `dir` attribute.
2829

2930
## [2.5.0]
3031

Sources/Navigator/EPUB/CSS/ReadiumCSS.swift

+11
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ extension ReadiumCSS {
8888
}
8989

9090
extension ReadiumCSS: HTMLInjectable {
91+
func willInject(in html: String) -> String {
92+
// Removes any dir attributes in html/body.
93+
let range = NSRange(html.startIndex..., in: html)
94+
return dirRegex.stringByReplacingMatches(in: html, options: [], range: range, withTemplate: "$1")
95+
}
96+
9197
/// https://github.com/readium/readium-css/blob/develop/docs/CSS06-stylesheets_order.md
9298
func injections(for html: String) throws -> [HTMLInjection] {
9399
let document = try parse(html)
@@ -200,3 +206,8 @@ private extension Element {
200206
return code.map { Language(code: .bcp47($0)) }
201207
}
202208
}
209+
210+
private let dirRegex = try! NSRegularExpression(
211+
pattern: "(<(?:html|body)[^>]*)\\s+dir=[\"']\\w*[\"']",
212+
options: [.caseInsensitive, .anchorsMatchLines]
213+
)

Sources/Navigator/Toolkit/HTMLInjection.swift

+6-1
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,18 @@ import ReadiumInternal
1010

1111
/// An object that can be injected into an HTML document.
1212
protocol HTMLInjectable {
13+
/// Extension point to do treatment on the HTML document before injection.
14+
func willInject(in html: String) -> String
15+
1316
func injections(for html: String) throws -> [HTMLInjection]
1417
}
1518

1619
extension HTMLInjectable {
20+
func willInject(in html: String) -> String { html }
21+
1722
/// Injects the receiver in the given `html` document.
1823
func inject(in html: String) throws -> String {
19-
var result = html
24+
var result = willInject(in: html)
2025
for injection in try injections(for: html) {
2126
result = try injection.inject(in: result)
2227
}

Tests/NavigatorTests/EPUB/CSS/ReadiumCSSTests.swift

+28
Original file line numberDiff line numberDiff line change
@@ -302,4 +302,32 @@ class ReadiumCSSTests: XCTestCase {
302302
]
303303
)
304304
}
305+
306+
func testInjectDirAttributeWhenAlreadyPresent() {
307+
let css = ReadiumCSS(
308+
layout: CSSLayout(language: Language(code: .bcp47("en"))),
309+
baseURL: baseURL
310+
)
311+
312+
XCTAssertEqual(
313+
try css.inject(in: """
314+
<?xml version="1.0" encoding="utf-8"?>
315+
<html xmlns="http://www.w3.org/1999/xhtml">
316+
<head>
317+
<title>Publication</title>
318+
</head>
319+
<body dir="rtl" lang="fr"></body>
320+
</html>
321+
"""),
322+
"""
323+
<?xml version="1.0" encoding="utf-8"?>
324+
<html xml:lang="fr" dir="ltr" style="" xmlns="http://www.w3.org/1999/xhtml">
325+
<head><link rel="stylesheet" href="https://readium/assets/ReadiumCSS-before.css" type="text/css"/>
326+
<title>Publication</title>
327+
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0"/><link rel="stylesheet" href="https://readium/assets/ReadiumCSS-default.css" type="text/css"/><link rel="stylesheet" href="https://readium/assets/ReadiumCSS-after.css" type="text/css"/><style type="text/css">audio[controls] { width: revert; height: revert; }</style></head>
328+
<body dir="ltr" lang="fr"></body>
329+
</html>
330+
"""
331+
)
332+
}
305333
}

0 commit comments

Comments
 (0)