Merge pull request #3626 from danielpunkass/inline-find

Add support for in-article find
This commit is contained in:
Maurice Parker
2022-07-26 17:31:46 -05:00
committed by GitHub
6 changed files with 117 additions and 3 deletions

View File

@@ -364,14 +364,25 @@
<outlet property="urlLabel" destination="Dim-ed-Dcz" id="8fY-oo-cGT"/>
</connections>
</customView>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="lMN-Bl-G9Q" userLabel="Find Bar Container View">
<rect key="frame" x="0.0" y="300" width="730" height="0.0"/>
<constraints>
<constraint firstAttribute="height" id="C1e-J5-baX"/>
</constraints>
</customView>
</subviews>
<constraints>
<constraint firstItem="xI5-lx-RD8" firstAttribute="leading" secondItem="cJ9-6s-66u" secondAttribute="leading" constant="6" id="5vz-ys-CAo"/>
<constraint firstItem="lMN-Bl-G9Q" firstAttribute="top" secondItem="cJ9-6s-66u" secondAttribute="top" placeholder="YES" id="Qyj-r4-LOb"/>
<constraint firstItem="lMN-Bl-G9Q" firstAttribute="leading" secondItem="cJ9-6s-66u" secondAttribute="leading" id="fjq-7Z-e0q"/>
<constraint firstAttribute="trailing" secondItem="lMN-Bl-G9Q" secondAttribute="trailing" id="oth-5X-F9R"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="xI5-lx-RD8" secondAttribute="trailing" constant="6" id="pbD-LN-Gk1"/>
<constraint firstAttribute="bottom" secondItem="xI5-lx-RD8" secondAttribute="bottom" constant="2" id="zsv-B0-ChW"/>
</constraints>
<connections>
<outlet property="detailStatusBarView" destination="xI5-lx-RD8" id="yIZ-aP-fKF"/>
<outlet property="findBarContainerView" destination="lMN-Bl-G9Q" id="zMP-iV-uSN"/>
<outlet property="findBarHeightConstraint" destination="C1e-J5-baX" id="Q4g-LU-JWK"/>
</connections>
</customView>
<connections>

View File

@@ -29,10 +29,61 @@ final class DetailContainerView: NSView {
if let contentView = contentView {
contentView.translatesAutoresizingMaskIntoConstraints = false
addSubview(contentView, positioned: .below, relativeTo: detailStatusBarView)
let constraints = constraintsToMakeSubViewFullSize(contentView)
// Constrain the content view to fill the available space on all sides except the top, which we'll constrain to the find bar
var constraints = constraintsToMakeSubViewFullSize(contentView).filter { $0.firstAttribute != .top }
constraints.append(findBarContainerView.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor))
constraints.append(findBarContainerView.bottomAnchor.constraint(equalTo: contentView.topAnchor))
NSLayoutConstraint.activate(constraints)
contentViewConstraints = constraints
}
}
}
// MARK: NSTextFinderBarContainer
@IBOutlet var findBarContainerView: NSView!
@IBOutlet var findBarHeightConstraint: NSLayoutConstraint!
public var findBarView: NSView? = nil {
didSet {
oldValue?.removeFromSuperview()
}
}
public var isFindBarVisible = false {
didSet {
// It seems AppKit assumes the findBarView will be removed from its superview when it's
// not being shown, so we have to fulfill that expectation in addition to hiding the stack view
// container we embed it in.
if
self.isFindBarVisible,
let view = findBarView
{
view.layoutSubtreeIfNeeded()
view.frame.origin = NSZeroPoint
view.frame.size.width = self.findBarContainerView.bounds.width
findBarContainerView.frame = view.bounds
findBarHeightConstraint.constant = view.frame.size.height + 1.0
findBarContainerView.addSubview(view)
}
else {
if let view = findBarView {
view.removeFromSuperview()
findBarHeightConstraint.constant = 0
}
}
}
}
func findBarViewDidChangeHeight() {
if let height = findBarView?.frame.size.height {
findBarHeightConstraint.constant = height + 1.0
findBarContainerView.layoutSubtreeIfNeeded()
findBarView?.setFrameOrigin(NSPoint.zero)
}
}
}

View File

@@ -41,6 +41,7 @@ final class DetailViewController: NSViewController, WKUIDelegate {
}
statusBarView.mouseoverLink = nil
containerView.contentView = webview
resetTextFinder()
}
}
@@ -52,6 +53,7 @@ final class DetailViewController: NSViewController, WKUIDelegate {
func setState(_ state: DetailState, mode: TimelineSourceMode) {
webViewController(for: mode).state = state
resetTextFinder()
}
func showDetail(for mode: TimelineSourceMode) {
@@ -92,7 +94,33 @@ final class DetailViewController: NSViewController, WKUIDelegate {
func saveState(to state: inout [AnyHashable : Any]) {
currentWebViewController.saveState(to: &state)
}
// MARK: Find in Article
private var didLoadTextFinder = false
lazy private var textFinder: NSTextFinder = {
let finder = NSTextFinder()
finder.isIncrementalSearchingEnabled = true
finder.incrementalSearchingShouldDimContentView = false
finder.client = self.currentWebViewController.webView
finder.findBarContainer = self.containerView
didLoadTextFinder = true
return finder
}()
private func resetTextFinder() {
if didLoadTextFinder {
self.textFinder.performAction(.hideFindInterface)
self.textFinder.client = currentWebViewController.webView
}
}
@IBAction func performFindPanelAction(_ sender: Any?) {
if let menuItem = sender as? NSMenuItem, let findAction = NSTextFinder.Action(rawValue: menuItem.tag) {
self.textFinder.performAction(findAction)
}
}
}
// MARK: - DetailWebViewControllerDelegate

View File

@@ -99,6 +99,12 @@ final class DetailWebView: WKWebView {
window!.setFrame(frame, display: false)
}
}
// MARK: NSTextFinderClient
// Returning false here prevents the "Replace" checkbox from appearing in the find bar
override var isEditable: Bool { return false }
}
// MARK: - Private

View File

@@ -186,7 +186,18 @@ final class DetailWebViewController: NSViewController {
state[UserInfoKey.isShowingExtractedArticle] = isShowingExtractedArticle
state[UserInfoKey.articleWindowScrollY] = windowScrollY
}
// MARK: Find in Article
var canFindInArticle: Bool {
switch state {
case .article(_, _), .extracted(_, _, _):
return true
default:
return false
}
}
}
// MARK: - WKScriptMessageHandler

View File

@@ -276,6 +276,9 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations {
return true
}
if item.action == #selector(performFindPanelAction(_:)) {
return self.detailViewController?.currentWebViewController.canFindInArticle ?? false
}
return true
}
@@ -536,6 +539,10 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations {
@IBAction func toggleReadArticlesFilter(_ sender: Any?) {
timelineContainerViewController?.toggleReadFilter()
}
@IBAction func performFindPanelAction(_ sender: Any?) {
self.detailViewController?.performFindPanelAction(sender)
}
@objc func selectArticleTheme(_ menuItem: NSMenuItem) {
ArticleThemesManager.shared.currentThemeName = menuItem.title