Rationalize the ArticleRenderer API.
This commit is contained in:
parent
9d9afea52a
commit
8de4ff4ee3
|
@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue