Merge branch 'Ranchero-Software:main' into improve-markdown
This commit is contained in:
commit
9789545624
|
@ -10,18 +10,18 @@ import Foundation
|
||||||
|
|
||||||
struct TwitterSymbol: Codable, TwitterEntity {
|
struct TwitterSymbol: Codable, TwitterEntity {
|
||||||
|
|
||||||
let name: String?
|
let text: String?
|
||||||
let indices: [Int]?
|
let indices: [Int]?
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case name = "name"
|
case text = "text"
|
||||||
case indices = "indices"
|
case indices = "indices"
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderAsHTML() -> String {
|
func renderAsHTML() -> String {
|
||||||
var html = String()
|
var html = String()
|
||||||
if let name = name {
|
if let text = text {
|
||||||
html += "<a href=\"https://twitter.com/search?q=%24\(name)\">$\(name)</a>"
|
html += "<a href=\"https://twitter.com/search?q=%24\(text)\">$\(text)</a>"
|
||||||
}
|
}
|
||||||
return html
|
return html
|
||||||
}
|
}
|
||||||
|
|
|
@ -1259,7 +1259,7 @@ private extension FeedbinAccountDelegate {
|
||||||
|
|
||||||
let parsedItems: [ParsedItem] = entries.map { entry in
|
let parsedItems: [ParsedItem] = entries.map { entry in
|
||||||
let authors = Set([ParsedAuthor(name: entry.authorName, url: entry.jsonFeed?.jsonFeedAuthor?.url, avatarURL: entry.jsonFeed?.jsonFeedAuthor?.avatarURL, emailAddress: nil)])
|
let authors = Set([ParsedAuthor(name: entry.authorName, url: entry.jsonFeed?.jsonFeedAuthor?.url, avatarURL: entry.jsonFeed?.jsonFeedAuthor?.avatarURL, emailAddress: nil)])
|
||||||
return ParsedItem(syncServiceID: String(entry.articleID), uniqueID: String(entry.articleID), feedURL: String(entry.feedID), url: entry.url, externalURL: nil, title: entry.title, language: nil, contentHTML: entry.contentHTML, contentText: nil, summary: entry.summary, imageURL: nil, bannerImageURL: nil, datePublished: entry.parsedDatePublished, dateModified: nil, authors: authors, tags: nil, attachments: nil)
|
return ParsedItem(syncServiceID: String(entry.articleID), uniqueID: String(entry.articleID), feedURL: String(entry.feedID), url: entry.url, externalURL: entry.jsonFeed?.jsonFeedExternalURL, title: entry.title, language: nil, contentHTML: entry.contentHTML, contentText: nil, summary: entry.summary, imageURL: nil, bannerImageURL: nil, datePublished: entry.parsedDatePublished, dateModified: nil, authors: authors, tags: nil, attachments: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Set(parsedItems)
|
return Set(parsedItems)
|
||||||
|
|
|
@ -52,9 +52,11 @@ final class FeedbinEntry: Decodable {
|
||||||
|
|
||||||
struct FeedbinEntryJSONFeed: Decodable {
|
struct FeedbinEntryJSONFeed: Decodable {
|
||||||
let jsonFeedAuthor: FeedbinEntryJSONFeedAuthor?
|
let jsonFeedAuthor: FeedbinEntryJSONFeedAuthor?
|
||||||
|
let jsonFeedExternalURL: String?
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case jsonFeedAuthor = "author"
|
case jsonFeedAuthor = "author"
|
||||||
|
case jsonFeedExternalURL = "external_url"
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(from decoder: Decoder) throws {
|
public init(from decoder: Decoder) throws {
|
||||||
|
@ -64,6 +66,11 @@ struct FeedbinEntryJSONFeed: Decodable {
|
||||||
} catch {
|
} catch {
|
||||||
jsonFeedAuthor = nil
|
jsonFeedAuthor = nil
|
||||||
}
|
}
|
||||||
|
do {
|
||||||
|
jsonFeedExternalURL = try container.decode(String.self, forKey: .jsonFeedExternalURL)
|
||||||
|
} catch {
|
||||||
|
jsonFeedExternalURL = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ protocol DetailWebViewControllerDelegate: AnyObject {
|
||||||
func mouseDidExit(_: DetailWebViewController)
|
func mouseDidExit(_: DetailWebViewController)
|
||||||
}
|
}
|
||||||
|
|
||||||
final class DetailWebViewController: NSViewController, WKUIDelegate {
|
final class DetailWebViewController: NSViewController {
|
||||||
|
|
||||||
weak var delegate: DetailWebViewControllerDelegate?
|
weak var delegate: DetailWebViewControllerDelegate?
|
||||||
var webView: DetailWebView!
|
var webView: DetailWebView!
|
||||||
|
@ -184,16 +184,22 @@ extension DetailWebViewController: WKScriptMessageHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - WKNavigationDelegate
|
// MARK: - WKNavigationDelegate & WKUIDelegate
|
||||||
|
|
||||||
extension DetailWebViewController: WKNavigationDelegate {
|
extension DetailWebViewController: WKNavigationDelegate, WKUIDelegate {
|
||||||
|
|
||||||
|
// Bottleneck through which WebView-based URL opens go
|
||||||
|
func openInBrowser(_ url: URL, flags: NSEvent.ModifierFlags) {
|
||||||
|
let invert = flags.contains(.shift) || flags.contains(.command)
|
||||||
|
Browser.open(url.absoluteString, invertPreference: invert)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WKNavigationDelegate
|
||||||
|
|
||||||
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
||||||
if navigationAction.navigationType == .linkActivated {
|
if navigationAction.navigationType == .linkActivated {
|
||||||
if let url = navigationAction.request.url {
|
if let url = navigationAction.request.url {
|
||||||
let flags = navigationAction.modifierFlags
|
self.openInBrowser(url, flags: navigationAction.modifierFlags)
|
||||||
let invert = flags.contains(.shift) || flags.contains(.command)
|
|
||||||
Browser.open(url.absoluteString, invertPreference: invert)
|
|
||||||
}
|
}
|
||||||
decisionHandler(.cancel)
|
decisionHandler(.cancel)
|
||||||
return
|
return
|
||||||
|
@ -216,6 +222,20 @@ extension DetailWebViewController: WKNavigationDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WKUIDelegate
|
||||||
|
|
||||||
|
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
|
||||||
|
// This method is reached when WebKit handles a JavaScript based window.open() invocation, for example. One
|
||||||
|
// example where this is used is in YouTube's embedded video player when a user clicks on the video's title
|
||||||
|
// or on the "Watch in YouTube" button. For our purposes we'll handle such window.open calls the same way we
|
||||||
|
// handle clicks on a URL.
|
||||||
|
if let url = navigationAction.request.url {
|
||||||
|
self.openInBrowser(url, flags: navigationAction.modifierFlags)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
|
@ -272,7 +272,14 @@ blockquote {
|
||||||
border-top: 1px solid var(--header-table-border-color);
|
border-top: 1px solid var(--header-table-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hide the external link at the bottom of Daring Fireball posts */
|
||||||
|
|
||||||
|
.x-netnewswire-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* see removeWpSmiley; this rule is kept in case a wp-smiley is encountered without alt text */
|
/* see removeWpSmiley; this rule is kept in case a wp-smiley is encountered without alt text */
|
||||||
|
|
||||||
.wp-smiley {
|
.wp-smiley {
|
||||||
height: 1em;
|
height: 1em;
|
||||||
max-height: 1em;
|
max-height: 1em;
|
||||||
|
|
|
@ -344,16 +344,7 @@ extension WebViewController: WKNavigationDelegate {
|
||||||
let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
|
let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
|
||||||
if components?.scheme == "http" || components?.scheme == "https" {
|
if components?.scheme == "http" || components?.scheme == "https" {
|
||||||
decisionHandler(.cancel)
|
decisionHandler(.cancel)
|
||||||
|
openURL(url)
|
||||||
// If the resource cannot be opened with an installed app, present the web view.
|
|
||||||
UIApplication.shared.open(url, options: [.universalLinksOnly: true]) { didOpen in
|
|
||||||
assert(Thread.isMainThread)
|
|
||||||
guard didOpen == false else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let vc = SFSafariViewController(url: url)
|
|
||||||
self.present(vc, animated: true)
|
|
||||||
}
|
|
||||||
} else if components?.scheme == "mailto" {
|
} else if components?.scheme == "mailto" {
|
||||||
decisionHandler(.cancel)
|
decisionHandler(.cancel)
|
||||||
|
|
||||||
|
@ -392,12 +383,23 @@ extension WebViewController: WKNavigationDelegate {
|
||||||
// MARK: WKUIDelegate
|
// MARK: WKUIDelegate
|
||||||
|
|
||||||
extension WebViewController: WKUIDelegate {
|
extension WebViewController: WKUIDelegate {
|
||||||
|
|
||||||
func webView(_ webView: WKWebView, contextMenuForElement elementInfo: WKContextMenuElementInfo, willCommitWithAnimator animator: UIContextMenuInteractionCommitAnimating) {
|
func webView(_ webView: WKWebView, contextMenuForElement elementInfo: WKContextMenuElementInfo, willCommitWithAnimator animator: UIContextMenuInteractionCommitAnimating) {
|
||||||
// We need to have at least an unimplemented WKUIDelegate assigned to the WKWebView. This makes the
|
// We need to have at least an unimplemented WKUIDelegate assigned to the WKWebView. This makes the
|
||||||
// link preview launch Safari when the link preview is tapped. In theory, you shoud be able to get
|
// link preview launch Safari when the link preview is tapped. In theory, you shoud be able to get
|
||||||
// the link from the elementInfo above and transition to SFSafariViewController instead of launching
|
// the link from the elementInfo above and transition to SFSafariViewController instead of launching
|
||||||
// Safari. As the time of this writing, the link in elementInfo is always nil. ¯\_(ツ)_/¯
|
// Safari. As the time of this writing, the link in elementInfo is always nil. ¯\_(ツ)_/¯
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
|
||||||
|
guard let url = navigationAction.request.url else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
openURL(url)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: WKScriptMessageHandler
|
// MARK: WKScriptMessageHandler
|
||||||
|
@ -745,7 +747,19 @@ private extension WebViewController {
|
||||||
self?.showActivityDialog()
|
self?.showActivityDialog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the resource cannot be opened with an installed app, present the web view.
|
||||||
|
func openURL(_ url: URL) {
|
||||||
|
UIApplication.shared.open(url, options: [.universalLinksOnly: true]) { didOpen in
|
||||||
|
assert(Thread.isMainThread)
|
||||||
|
guard didOpen == false else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let vc = SFSafariViewController(url: url)
|
||||||
|
self.present(vc, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Find in Article
|
// MARK: Find in Article
|
||||||
|
|
Loading…
Reference in New Issue