diff --git a/ios/Platform/Platform/Features/Reader/Views/ArticleView.swift b/ios/Platform/Platform/Features/Reader/Views/ArticleView.swift index 000b320..e41a61a 100644 --- a/ios/Platform/Platform/Features/Reader/Views/ArticleView.swift +++ b/ios/Platform/Platform/Features/Reader/Views/ArticleView.swift @@ -244,7 +244,7 @@ enum ArticleHTMLBuilder {

\(safeTitle)

\(meta)
- \(body) +
\(body)
""" diff --git a/ios/Platform/Platform/Features/Reader/Views/ArticleWebView.swift b/ios/Platform/Platform/Features/Reader/Views/ArticleWebView.swift index dc12939..f2d10ca 100644 --- a/ios/Platform/Platform/Features/Reader/Views/ArticleWebView.swift +++ b/ios/Platform/Platform/Features/Reader/Views/ArticleWebView.swift @@ -62,21 +62,23 @@ struct ArticleWebView: UIViewRepresentable { context.coordinator.lastHTML = newHTML if isUpgrade { - // Content upgrade (partial → full): capture scroll, replace body, restore scroll. - // Uses JavaScript DOM replacement instead of full page reload to avoid flash. - let escapedBody = extractBody(from: newHTML) + // Content upgrade (partial → full): swap only #article-body contents. + // Header + outer document structure stay intact. Scroll preserved. + let escapedContent = escapeForJS(extractArticleBody(from: newHTML)) let js = """ (function() { + var el = document.getElementById('article-body'); + if (!el) return 'no-container'; var scrollY = window.scrollY; - var header = document.querySelector('.article-header'); - var headerHTML = header ? header.outerHTML : ''; - document.body.innerHTML = headerHTML + \(escapedBody); + el.innerHTML = \(escapedContent); window.scrollTo(0, scrollY); + return 'ok'; })(); """ - webView.evaluateJavaScript(js) { _, error in - // If JS replacement fails (e.g. different page structure), fall back to full reload - if error != nil { + webView.evaluateJavaScript(js) { result, error in + // Fall back to full reload if container missing or JS error + let status = result as? String + if error != nil || status != "ok" { webView.loadHTMLString(newHTML, baseURL: nil) } } @@ -90,22 +92,32 @@ struct ArticleWebView: UIViewRepresentable { Coordinator() } - /// Extract the content after ... as a JS string literal - private func extractBody(from html: String) -> String { - // Find body content between and - if let bodyStart = html.range(of: ""), - let bodyEnd = html.range(of: "") { - let bodyContent = String(html[bodyStart.upperBound..... + private func extractArticleBody(from html: String) -> String { + let marker = "
" + guard let start = html.range(of: marker) else { return "" } + let afterMarker = html[start.upperBound...] + // Find the matching
before + guard let bodyEnd = afterMarker.range(of: "\n ") + ?? afterMarker.range(of: "") + ?? afterMarker.range(of: "\n") else { + // Fallback: take everything up to + if let end = afterMarker.range(of: "") { + return String(afterMarker[.. String { + let escaped = str + .replacingOccurrences(of: "\\", with: "\\\\") + .replacingOccurrences(of: "'", with: "\\'") + .replacingOccurrences(of: "\n", with: "\\n") + .replacingOccurrences(of: "\r", with: "") + return "'\(escaped)'" } class Coordinator: NSObject, WKNavigationDelegate {