Rationalize the ArticleRenderer API.

This commit is contained in:
Brent Simmons 2019-02-10 22:06:03 -08:00
parent 9d9afea52a
commit 8de4ff4ee3
3 changed files with 58 additions and 41 deletions

View File

@ -11,31 +11,20 @@ import RSCore
import Articles import Articles
import Account import Account
class ArticleRenderer { struct ArticleRendererResult {
let html: String
let baseURL: URL? let baseURL: URL?
}
var articleHTML: String { struct ArticleRenderer {
let body = RSMacroProcessor.renderedText(withTemplate: template(), substitutions: substitutions(), macroStart: "[[", macroEnd: "]]")
return renderHTML(withBody: body)
}
var multipleSelectionHTML: String {
let body = "<h3 class='systemMessage'>Multiple selection</h3>"
return renderHTML(withBody: body)
}
var noSelectionHTML: String {
let body = "<h3 class='systemMessage'>No selection</h3>"
return renderHTML(withBody: body)
}
private let baseURL: URL?
private let article: Article? private let article: Article?
private let articleStyle: ArticleStyle private let articleStyle: ArticleStyle
private let appearance: NSAppearance? private let appearance: NSAppearance?
private let title: String private let title: String
init(article: Article?, style: ArticleStyle, appearance: NSAppearance? = nil) { private init(article: Article?, style: ArticleStyle, appearance: NSAppearance?) {
self.article = article self.article = article
self.articleStyle = style self.articleStyle = style
self.appearance = appearance self.appearance = appearance
@ -47,12 +36,44 @@ class ArticleRenderer {
self.baseURL = nil self.baseURL = nil
} }
} }
// MARK: - API
static func articleHTML(article: Article, style: ArticleStyle, appearance: NSAppearance?) -> ArticleRendererResult {
let renderer = ArticleRenderer(article: article, style: style, appearance: appearance)
return ArticleRendererResult(html: renderer.articleHTML, baseURL: renderer.baseURL)
}
static func multipleSelectionHTML(style: ArticleStyle, appearance: NSAppearance?) -> ArticleRendererResult {
let renderer = ArticleRenderer(article: nil, style: style, appearance: appearance)
return ArticleRendererResult(html: renderer.multipleSelectionHTML, baseURL: nil)
}
static func noSelectionHTML(style: ArticleStyle, appearance: NSAppearance?) -> ArticleRendererResult {
let renderer = ArticleRenderer(article: nil, style: style, appearance: appearance)
return ArticleRendererResult(html: renderer.noSelectionHTML, baseURL: nil)
}
} }
// MARK: Private // MARK: - Private
private extension ArticleRenderer { private extension ArticleRenderer {
private var articleHTML: String {
let body = RSMacroProcessor.renderedText(withTemplate: template(), substitutions: substitutions(), macroStart: "[[", macroEnd: "]]")
return renderHTML(withBody: body)
}
private var multipleSelectionHTML: String {
let body = "<h3 class='systemMessage'>Multiple selection</h3>"
return renderHTML(withBody: body)
}
private var noSelectionHTML: String {
let body = "<h3 class='systemMessage'>No selection</h3>"
return renderHTML(withBody: body)
}
static var faviconImgTagCache = [Feed: String]() static var faviconImgTagCache = [Feed: String]()
static var feedIconImgTagCache = [Feed: String]() static var feedIconImgTagCache = [Feed: String]()
@ -362,6 +383,5 @@ private extension ArticleRenderer {
//print(s) //print(s)
return s return s
} }
} }

View File

@ -21,7 +21,7 @@ final class DetailViewController: NSViewController, WKUIDelegate {
var articles: [Article]? { var articles: [Article]? {
didSet { didSet {
if articles == articles { if articles == oldValue {
return return
} }
statusBarView.mouseoverLink = nil statusBarView.mouseoverLink = nil
@ -43,7 +43,6 @@ final class DetailViewController: NSViewController, WKUIDelegate {
} }
override func viewDidLoad() { override func viewDidLoad() {
NotificationCenter.default.addObserver(self, selector: #selector(timelineSelectionDidChange(_:)), name: .TimelineSelectionDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(timelineSelectionDidChange(_:)), name: .TimelineSelectionDidChange, object: nil)
let preferences = WKPreferences() let preferences = WKPreferences()
@ -74,10 +73,9 @@ final class DetailViewController: NSViewController, WKUIDelegate {
containerView.viewController = self containerView.viewController = self
} }
// MARK: - Scrolling // MARK: Scrolling
func canScrollDown(_ callback: @escaping (Bool) -> Void) { func canScrollDown(_ callback: @escaping (Bool) -> Void) {
if webviewIsHidden { if webviewIsHidden {
callback(false) callback(false)
return return
@ -96,7 +94,7 @@ final class DetailViewController: NSViewController, WKUIDelegate {
webview.scrollPageDown(sender) webview.scrollPageDown(sender)
} }
// MARK: - Notifications // MARK: Notifications
@objc func timelineSelectionDidChange(_ notification: Notification) { @objc func timelineSelectionDidChange(_ notification: Notification) {
@ -122,7 +120,7 @@ final class DetailViewController: NSViewController, WKUIDelegate {
} }
} }
// MARK: - WKNavigationDelegate // MARK: WKNavigationDelegate
extension DetailViewController: WKNavigationDelegate { extension DetailViewController: WKNavigationDelegate {
@ -142,7 +140,7 @@ extension DetailViewController: WKNavigationDelegate {
} }
} }
// MARK: - WKScriptMessageHandler // MARK: WKScriptMessageHandler
extension DetailViewController: WKScriptMessageHandler { extension DetailViewController: WKScriptMessageHandler {
@ -168,29 +166,29 @@ extension DetailViewController: WKScriptMessageHandler {
} }
} }
// MARK: - Private // MARK: Private
private extension DetailViewController { private extension DetailViewController {
func reloadHTML() { func reloadHTML() {
let articleRendererResult: ArticleRendererResult
let style = ArticleStylesManager.shared.currentStyle
let appearance = self.view.effectiveAppearance
let articleRenderer = ArticleRenderer(article: article, if let articles = articles, articles.count > 1 {
style: ArticleStylesManager.shared.currentStyle, articleRendererResult = ArticleRenderer.multipleSelectionHTML(style: style, appearance: appearance)
appearance: self.view.effectiveAppearance)
if article != nil {
webview.loadHTMLString(articleRenderer.articleHTML, baseURL: articleRenderer.baseURL)
} }
else if articles != nil { else if let article = article {
webview.loadHTMLString(articleRenderer.multipleSelectionHTML, baseURL: nil) articleRendererResult = ArticleRenderer.articleHTML(article: article, style: style, appearance: appearance)
} }
else { else {
webview.loadHTMLString(articleRenderer.noSelectionHTML, baseURL: nil) articleRendererResult = ArticleRenderer.noSelectionHTML(style: style, appearance: appearance)
} }
webview.loadHTMLString(articleRendererResult.html, baseURL: articleRendererResult.baseURL)
} }
func fetchScrollInfo(_ callback: @escaping (ScrollInfo?) -> Void) { func fetchScrollInfo(_ callback: @escaping (ScrollInfo?) -> Void) {
let javascriptString = "var x = {contentHeight: document.body.scrollHeight, offsetY: document.body.scrollTop}; x" let javascriptString = "var x = {contentHeight: document.body.scrollHeight, offsetY: document.body.scrollTop}; x"
webview.evaluateJavaScript(javascriptString) { (info, error) in webview.evaluateJavaScript(javascriptString) { (info, error) in
@ -245,7 +243,7 @@ final class DetailContainerView: NSView {
} }
} }
// MARK: - // MARK: - ScrollInfo
private struct ScrollInfo { private struct ScrollInfo {
@ -256,7 +254,6 @@ private struct ScrollInfo {
let canScrollUp: Bool let canScrollUp: Bool
init(contentHeight: CGFloat, viewHeight: CGFloat, offsetY: CGFloat) { init(contentHeight: CGFloat, viewHeight: CGFloat, offsetY: CGFloat) {
self.contentHeight = contentHeight self.contentHeight = contentHeight
self.viewHeight = viewHeight self.viewHeight = viewHeight
self.offsetY = offsetY self.offsetY = offsetY

View File

@ -20,8 +20,8 @@ import RSCore
static let articleUTIInternalType = NSPasteboard.PasteboardType(rawValue: articleUTIInternal) static let articleUTIInternalType = NSPasteboard.PasteboardType(rawValue: articleUTIInternal)
private lazy var renderedHTML: String = { private lazy var renderedHTML: String = {
let articleRenderer = ArticleRenderer(article: article, style: ArticleStylesManager.shared.currentStyle) let articleRendererResult = ArticleRenderer.articleHTML(article: article, style: ArticleStylesManager.shared.currentStyle, appearance: nil)
return articleRenderer.articleHTML return articleRendererResult.html
}() }()
init(article: Article) { init(article: Article) {