diff --git a/NetNewsWire/Base.lproj/MainWindow.storyboard b/NetNewsWire/Base.lproj/MainWindow.storyboard
index b44312305..aad2d223f 100644
--- a/NetNewsWire/Base.lproj/MainWindow.storyboard
+++ b/NetNewsWire/Base.lproj/MainWindow.storyboard
@@ -624,59 +624,9 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/NetNewsWire/MainWindow/Detail/ArticleRenderer.swift b/NetNewsWire/MainWindow/Detail/ArticleRenderer.swift
index 13b50167b..2d26b5d0c 100644
--- a/NetNewsWire/MainWindow/Detail/ArticleRenderer.swift
+++ b/NetNewsWire/MainWindow/Detail/ArticleRenderer.swift
@@ -18,7 +18,7 @@ var cachedTemplate = ""
class ArticleRenderer {
- let article: Article
+ let article: Article?
let articleStyle: ArticleStyle
let appearance: NSAppearance?
@@ -47,7 +47,7 @@ class ArticleRenderer {
}()
lazy var title: String = {
- if let articleTitle = self.article.title {
+ if let articleTitle = self.article?.title {
return articleTitle
}
@@ -56,12 +56,12 @@ class ArticleRenderer {
lazy var baseURL: URL? = {
- var s = self.article.url
+ var s = self.article?.url
if s == nil {
- s = self.article.feed?.homePageURL
+ s = self.article?.feed?.homePageURL
}
if s == nil {
- s = self.article.feed?.url
+ s = self.article?.feed?.url
}
if s == nil {
return nil
@@ -84,17 +84,25 @@ class ArticleRenderer {
return nil
}()
- var html: String {
-
- return renderedHTML()
+ var articleHTML: String {
+ let body = RSMacroProcessor.renderedText(withTemplate: template(), substitutions: substitutions(), macroStart: "[[", macroEnd: "]]")
+ return renderHTML(withBody: body)
}
- init(article: Article, style: ArticleStyle, appearance: NSAppearance? = nil) {
-
+ var multipleSelectionHTML: String {
+ let body = "
Multiple selection
"
+ return renderHTML(withBody: body)
+ }
+
+ var noSelectionHTML: String {
+ let body = "No selection
"
+ return renderHTML(withBody: body)
+ }
+
+ init(article: Article?, style: ArticleStyle, appearance: NSAppearance? = nil) {
self.article = article
self.articleStyle = style
self.appearance = appearance
-
}
// MARK: Private
@@ -157,7 +165,7 @@ class ArticleRenderer {
private func titleOrTitleLink() -> String {
- if let link = article.preferredLink {
+ if let link = article?.preferredLink {
return linkWithText(title, link)
}
return title
@@ -167,6 +175,11 @@ class ArticleRenderer {
var d = [String: String]()
+ guard let article = article else {
+ assertionFailure("Article should have been set before calling this function.")
+ return d
+ }
+
let title = titleOrTitleLink()
d["title"] = title
@@ -220,10 +233,10 @@ class ArticleRenderer {
}
private func dateShouldBeLink() -> Bool {
- guard let permalink = article.url else {
+ guard let permalink = article?.url else {
return false
}
- guard let preferredLink = article.preferredLink else { // Title uses preferredLink
+ guard let preferredLink = article?.preferredLink else { // Title uses preferredLink
return false
}
return permalink != preferredLink // Make date a link if it’s a different link from the title’s link
@@ -301,7 +314,7 @@ class ArticleRenderer {
// The author of this article, if just one.
- if let authors = article.authors, authors.count == 1 {
+ if let authors = article?.authors, authors.count == 1 {
return authors.first!
}
return nil
@@ -309,7 +322,7 @@ class ArticleRenderer {
private func singleFeedSpecifiedAuthor() -> Author? {
- if let authors = article.feed?.authors, authors.count == 1 {
+ if let authors = article?.feed?.authors, authors.count == 1 {
return authors.first!
}
return nil
@@ -317,10 +330,10 @@ class ArticleRenderer {
private func feedAvatar() -> Avatar? {
- guard let feedIconURL = article.feed?.iconURL else {
+ guard let feedIconURL = article?.feed?.iconURL else {
return nil
}
- return Avatar(imageURL: feedIconURL, url: article.feed?.homePageURL ?? article.feed?.url)
+ return Avatar(imageURL: feedIconURL, url: article?.feed?.homePageURL ?? article?.feed?.url)
}
private func authorAvatar() -> Avatar? {
@@ -354,8 +367,8 @@ class ArticleRenderer {
if let author = singleArticleSpecifiedAuthor(), let imageURL = author.avatarURL {
return Avatar(imageURL: imageURL, url: author.url)
}
- if let feedIconURL = article.feed?.iconURL {
- return Avatar(imageURL: feedIconURL, url: article.feed?.homePageURL ?? article.feed?.url)
+ if let feedIconURL = article?.feed?.iconURL {
+ return Avatar(imageURL: feedIconURL, url: article?.feed?.homePageURL ?? article?.feed?.url)
}
if let author = singleFeedSpecifiedAuthor(), let imageURL = author.avatarURL {
return Avatar(imageURL: imageURL, url: author.url)
@@ -370,11 +383,11 @@ class ArticleRenderer {
if let author = singleArticleSpecifiedAuthor(), let imageURL = author.avatarURL {
return Avatar(imageURL: imageURL, url: author.url).html(dimension: avatarDimension)
}
- if let feed = article.feed, let imgTag = feedIconImgTag(forFeed: feed) {
+ if let feed = article?.feed, let imgTag = feedIconImgTag(forFeed: feed) {
return imgTag
}
- if let feedIconURL = article.feed?.iconURL {
- return Avatar(imageURL: feedIconURL, url: article.feed?.homePageURL ?? article.feed?.url).html(dimension: avatarDimension)
+ if let feedIconURL = article?.feed?.iconURL {
+ return Avatar(imageURL: feedIconURL, url: article?.feed?.homePageURL ?? article?.feed?.url).html(dimension: avatarDimension)
}
if let author = singleFeedSpecifiedAuthor(), let imageURL = author.avatarURL {
return Avatar(imageURL: imageURL, url: author.url).html(dimension: avatarDimension)
@@ -400,7 +413,7 @@ class ArticleRenderer {
private func byline() -> String {
- guard let authors = article.authors ?? article.feed?.authors, !authors.isEmpty else {
+ guard let authors = article?.authors ?? article?.feed?.authors, !authors.isEmpty else {
return ""
}
@@ -408,7 +421,7 @@ class ArticleRenderer {
// This code assumes that multiple authors would never match the feed name so that
// if there feed owner has an article co-author all authors are given the byline.
if authors.count == 1, let author = authors.first {
- if author.name == article.feed?.nameForDisplay {
+ if author.name == article?.feed?.nameForDisplay {
return ""
}
}
@@ -447,7 +460,7 @@ class ArticleRenderer {
}
- private func renderedHTML() -> String {
+ private func renderHTML(withBody body: String) -> String {
var s = "\n\n"
s += textInsideTag(title, "title")
@@ -480,7 +493,7 @@ class ArticleRenderer {
let appearanceClass = appearance?.isDarkMode ?? false ? "dark" : "light"
s += "\n\n\n\n"
- s += RSMacroProcessor.renderedText(withTemplate: template(), substitutions: substitutions(), macroStart: "[[", macroEnd: "]]")
+ s += body
s += "\n\n"
diff --git a/NetNewsWire/MainWindow/Detail/DetailViewController.swift b/NetNewsWire/MainWindow/Detail/DetailViewController.swift
index 0013c6ff0..17f71dec2 100644
--- a/NetNewsWire/MainWindow/Detail/DetailViewController.swift
+++ b/NetNewsWire/MainWindow/Detail/DetailViewController.swift
@@ -15,7 +15,6 @@ import RSWeb
final class DetailViewController: NSViewController, WKUIDelegate {
@IBOutlet var containerView: DetailContainerView!
- @IBOutlet var noSelectionView: NoSelectionView!
var webview: DetailWebView!
@@ -26,19 +25,13 @@ final class DetailViewController: NSViewController, WKUIDelegate {
return
}
article = nil
- if let _ = articles {
- noSelectionView.showMultipleSelection()
- }
- else {
- noSelectionView.showNoSelection()
- }
+ reloadHTML()
}
}
private var article: Article? {
didSet {
reloadHTML()
- showOrHideWebView()
}
}
@@ -78,9 +71,10 @@ final class DetailViewController: NSViewController, WKUIDelegate {
webview.customUserAgent = userAgent
}
+ reloadHTML()
+ containerView.contentView = webview
containerView.viewController = self
- showOrHideWebView()
}
// MARK: - Scrolling
@@ -194,35 +188,21 @@ private extension DetailViewController {
func reloadHTML() {
- if let article = article {
- let articleRenderer = ArticleRenderer(article: article,
- style: ArticleStylesManager.shared.currentStyle,
- appearance: self.view.effectiveAppearance)
- webview.loadHTMLString(articleRenderer.html, baseURL: articleRenderer.baseURL)
+ let articleRenderer = ArticleRenderer(article: article,
+ style: ArticleStylesManager.shared.currentStyle,
+ appearance: self.view.effectiveAppearance)
+
+ if article != nil {
+ webview.loadHTMLString(articleRenderer.articleHTML, baseURL: articleRenderer.baseURL)
+ }
+ else if articles != nil {
+ webview.loadHTMLString(articleRenderer.multipleSelectionHTML, baseURL: nil)
}
else {
- webview.loadHTMLString("", baseURL: nil)
+ webview.loadHTMLString(articleRenderer.noSelectionHTML, baseURL: nil)
}
}
- func showOrHideWebView() {
-
- if let _ = article {
- switchToView(webview)
- }
- else {
- switchToView(noSelectionView)
- }
- }
-
- func switchToView(_ view: NSView) {
-
- if containerView.contentView == view {
- return
- }
- containerView.contentView = view
- }
-
func fetchScrollInfo(_ callback: @escaping (ScrollInfo?) -> Void) {
let javascriptString = "var x = {contentHeight: document.body.scrollHeight, offsetY: document.body.scrollTop}; x"
@@ -251,12 +231,6 @@ final class DetailContainerView: NSView {
weak var viewController: DetailViewController? = nil
-// private var didConfigureLayer = false
-//
-// override var wantsUpdateLayer: Bool {
-// return true
-// }
-
var contentView: NSView? {
didSet {
if let oldContentView = oldValue {
@@ -284,37 +258,8 @@ final class DetailContainerView: NSView {
NSColor.textBackgroundColor.setFill()
dirtyRect.fill()
}
-// override func updateLayer() {
-//
-// guard !didConfigureLayer else {
-// return
-// }
-// if let layer = layer {
-// let color = appDelegate.currentTheme.color(forKey: "MainWindow.Detail.backgroundColor")
-// layer.backgroundColor = color.cgColor
-// didConfigureLayer = true
-// }
-// }
-}
-// MARK: -
-
-final class NoSelectionView: NSView {
-
- @IBOutlet var noSelectionLabel: NSTextField!
- @IBOutlet var multipleSelectionLabel: NSTextField!
-
- func showMultipleSelection() {
-
- noSelectionLabel.isHidden = true
- multipleSelectionLabel.isHidden = false
- }
-
- func showNoSelection() {
-
- noSelectionLabel.isHidden = false
- multipleSelectionLabel.isHidden = true
- }
+
}
// MARK: -
diff --git a/NetNewsWire/MainWindow/Detail/styleSheet.css b/NetNewsWire/MainWindow/Detail/styleSheet.css
index 09d1141fb..509b015c5 100644
--- a/NetNewsWire/MainWindow/Detail/styleSheet.css
+++ b/NetNewsWire/MainWindow/Detail/styleSheet.css
@@ -21,6 +21,13 @@ a:hover {
height: 68px;
}
+.systemMessage {
+ position: absolute;
+ top: 45%;
+ left: 50%;
+ transform: translateX(-55%) translateY(-50%);
+}
+
/* Light mode */
body.light {
@@ -44,6 +51,10 @@ body.light .articleDateline, body.light .articleDateLine.a:link, body.light .art
color: rgba(0, 0, 0, 0.3);
}
+.light > .systemMessage {
+ color: #cbcbcb;
+}
+
/* Dark mode */
body.dark {
@@ -70,6 +81,10 @@ body.dark .articleDateline, body.dark .articleDateLine.a:link, body.dark .articl
color: #d2d2d2;
}
+.dark > .systemMessage {
+ color: #5f5f5f;
+}
+
.feedlink a:link, .feedlink a:visited {
color: rgba(0, 0, 0, 0.6);
}
diff --git a/NetNewsWire/MainWindow/Timeline/ArticlePasteboardWriter.swift b/NetNewsWire/MainWindow/Timeline/ArticlePasteboardWriter.swift
index 502e7b5fa..93b9735d3 100644
--- a/NetNewsWire/MainWindow/Timeline/ArticlePasteboardWriter.swift
+++ b/NetNewsWire/MainWindow/Timeline/ArticlePasteboardWriter.swift
@@ -27,7 +27,7 @@ extension Article: PasteboardWriterOwner {
private lazy var renderedHTML: String = {
let articleRenderer = ArticleRenderer(article: article, style: ArticleStylesManager.shared.currentStyle)
- return articleRenderer.html
+ return articleRenderer.articleHTML
}()
init(article: Article) {
diff --git a/NetNewsWire/Resources/DB5.plist b/NetNewsWire/Resources/DB5.plist
index 6b7b51c17..dd95ce9df 100644
--- a/NetNewsWire/Resources/DB5.plist
+++ b/NetNewsWire/Resources/DB5.plist
@@ -127,11 +127,6 @@
Detail
- noSelectionView
-
- backgroundColor
- FFFFFF
-
statusBar
backgroundColor