Skip to content

Commit

Permalink
Add link button action support
Browse files Browse the repository at this point in the history
  • Loading branch information
tonisevener committed Jan 6, 2024
1 parent 45856ea commit a2d80e7
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extension WKSourceEditorFormatter {

// MARK: - Expanding selected range methods

private func expandSelectedRangeUpToNearestFormattingStrings(startingFormattingString: String, endingFormattingString: String, in textView: UITextView) {
func expandSelectedRangeUpToNearestFormattingStrings(startingFormattingString: String, endingFormattingString: String, in textView: UITextView) {
if let textPositions = textPositionsCloserToNearestFormattingStrings(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView) {
textView.selectedTextRange = textView.textRange(from: textPositions.startPosition, to: textPositions.endPosition)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import Foundation
import ComponentsObjC

enum WKSourceEditorFormatterLinkButtonAction {
case edit
case insert
}

public struct WKSourceEditorFormatterLinkWizardParameters {
public let editPageTitle: String?
public let editPageLabel: String?
public let insertSearchTerm: String?
let preselectedTextRange: UITextRange
}

extension WKSourceEditorFormatterLink {

func linkWizardParameters(action: WKSourceEditorFormatterLinkButtonAction, in textView: UITextView) -> WKSourceEditorFormatterLinkWizardParameters? {

switch action {
case .edit:
expandSelectedRangeUpToNearestFormattingStrings(startingFormattingString: "[[", endingFormattingString: "]]", in: textView)

guard let selectedTextRange = textView.selectedTextRange,
let selectedText = textView.text(in: selectedTextRange) else {
return nil
}

let splitText = selectedText.split(separator: "|").map {String($0)}

switch splitText.count {
case 1:
return WKSourceEditorFormatterLinkWizardParameters(editPageTitle: splitText[0], editPageLabel: nil, insertSearchTerm: nil, preselectedTextRange: selectedTextRange)
case 2:
return WKSourceEditorFormatterLinkWizardParameters(editPageTitle: splitText[0], editPageLabel: splitText[1], insertSearchTerm: nil, preselectedTextRange: selectedTextRange)
default:
return nil
}

case .insert:

guard let selectedTextRange = textView.selectedTextRange,
let selectedText = textView.text(in: selectedTextRange) else {
return nil
}

return WKSourceEditorFormatterLinkWizardParameters(editPageTitle: nil, editPageLabel: nil, insertSearchTerm: selectedText, preselectedTextRange: selectedTextRange)
}


}

func insertLink(in textView: UITextView, pageTitle: String, preselectedTextRange: UITextRange) {
var content = "[[\(pageTitle)]]"

guard let selectedText = textView.text(in: preselectedTextRange) else {
return
}

if pageTitle != selectedText {
content = "[[\(pageTitle)|\(selectedText)]]"
}

textView.replace(preselectedTextRange, withText: content)

if let newStartPosition = textView.position(from: preselectedTextRange.start, offset: 2),
let newEndPosition = textView.position(from: preselectedTextRange.start, offset: content.count-2) {
textView.selectedTextRange = textView.textRange(from: newStartPosition, to: newEndPosition)
}

}

func editLink(in textView: UITextView, newPageTitle: String, newPageLabel: String?, preselectedTextRange: UITextRange) {

expandSelectedRangeUpToNearestFormattingStrings(startingFormattingString: "[[", endingFormattingString: "]]", in: textView)

if let newPageLabel, !newPageLabel.isEmpty {
textView.replace(preselectedTextRange, withText: "\(newPageTitle)|\(newPageLabel)")
} else {
textView.replace(preselectedTextRange, withText: "\(newPageTitle)")
}
}

func removeLink(in textView: UITextView, preselectedTextRange: UITextRange) {

guard let selectedText = textView.text(in: preselectedTextRange) else {
return
}

if let markupStartPosition = textView.position(from: preselectedTextRange.start, offset: -2),
let markupEndPosition = textView.position(from: preselectedTextRange.end, offset: 2),
let newSelectedRange = textView.textRange(from: markupStartPosition, to: markupEndPosition) {
textView.replace(newSelectedRange, withText: selectedText)

if let newStartPosition = textView.position(from: preselectedTextRange.start, offset: -2),
let newEndPosition = textView.position(from: preselectedTextRange.end, offset: -2) {
textView.selectedTextRange = textView.textRange(from: newStartPosition, to: newEndPosition)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import UIKit
public protocol WKSourceEditorViewControllerDelegate: AnyObject {
func sourceEditorViewControllerDidTapFind(sourceEditorViewController: WKSourceEditorViewController)
func sourceEditorViewControllerDidRemoveFindInputAccessoryView(sourceEditorViewController: WKSourceEditorViewController)
func sourceEditorViewControllerDidTapLink(parameters: WKSourceEditorFormatterLinkWizardParameters)
}

// MARK: NSNotification Names
Expand Down Expand Up @@ -37,6 +38,7 @@ public class WKSourceEditorViewController: WKComponentViewController {
private let viewModel: WKSourceEditorViewModel
private weak var delegate: WKSourceEditorViewControllerDelegate?
private let textFrameworkMediator: WKSourceEditorTextFrameworkMediator
private var preselectedTextRange: UITextRange?

var textView: UITextView {
return textFrameworkMediator.textView
Expand Down Expand Up @@ -231,6 +233,39 @@ public class WKSourceEditorViewController: WKComponentViewController {
viewModel.isSyntaxHighlightingEnabled.toggle()
update(viewModel: viewModel)
}

public func insertLink(pageTitle: String) {

guard let preselectedTextRange else {
return
}

textFrameworkMediator.linkFormatter?.insertLink(in: textView, pageTitle: pageTitle, preselectedTextRange: preselectedTextRange)

self.preselectedTextRange = nil
}

public func editLink(newPageTitle: String, newPageLabel: String?) {

guard let preselectedTextRange else {
return
}

textFrameworkMediator.linkFormatter?.editLink(in: textView, newPageTitle: newPageTitle, newPageLabel: newPageLabel, preselectedTextRange: preselectedTextRange)

self.preselectedTextRange = nil
}

public func removeLink() {

guard let preselectedTextRange else {
return
}

textFrameworkMediator.linkFormatter?.removeLink(in: textView, preselectedTextRange: preselectedTextRange)

self.preselectedTextRange = nil
}
}

// MARK: - Private
Expand Down Expand Up @@ -272,6 +307,19 @@ private extension WKSourceEditorViewController {
NotificationCenter.default.post(name: Notification.WKSourceEditorSelectionState, object: nil, userInfo: [Notification.WKSourceEditorSelectionStateKey: selectionState])
}
}

func presentLinkWizard(linkButtonIsSelected: Bool) {

let action: WKSourceEditorFormatterLinkButtonAction = linkButtonIsSelected ? .edit : .insert

guard let parameters = textFrameworkMediator.linkFormatter?.linkWizardParameters(action: action, in: textView) else {
return
}

// For some reason the editor text view can lose its selectedTextRange when presenting the link wizard, which we need in the formatter button action extension to determine how to change the text after wizard dismissal. We keep track of it here and send it back into the formatter later.
self.preselectedTextRange = parameters.preselectedTextRange
delegate?.sourceEditorViewControllerDidTapLink(parameters: parameters)
}
}

// MARK: - UITextViewDelegate
Expand Down Expand Up @@ -312,7 +360,7 @@ extension WKSourceEditorViewController: WKEditorToolbarExpandingViewDelegate {
}

func toolbarExpandingViewDidTapLink(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool) {

presentLinkWizard(linkButtonIsSelected: isSelected)
}

func toolbarExpandingViewDidTapImage(toolbarView: WKEditorToolbarExpandingView) {
Expand Down Expand Up @@ -340,7 +388,7 @@ extension WKSourceEditorViewController: WKEditorToolbarHighlightViewDelegate {
}

func toolbarHighlightViewDidTapLink(toolbarView: WKEditorToolbarHighlightView, isSelected: Bool) {

presentLinkWizard(linkButtonIsSelected: isSelected)
}

func toolbarHighlightViewDidTapShowMore(toolbarView: WKEditorToolbarHighlightView) {
Expand Down Expand Up @@ -378,7 +426,7 @@ extension WKSourceEditorViewController: WKEditorInputViewDelegate {
}

func didTapLink(isSelected: Bool) {

presentLinkWizard(linkButtonIsSelected: isSelected)
}

func didTapClose() {
Expand Down
70 changes: 70 additions & 0 deletions Wikipedia/Code/PageEditorViewController.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import UIKit
import Components
import WMF
import CocoaLumberjackSwift

protocol PageEditorViewControllerDelegate: AnyObject {
func pageEditorDidCancelEditing(_ pageEditor: PageEditorViewController, navigateToURL: URL?)
Expand Down Expand Up @@ -239,6 +240,39 @@ extension PageEditorViewController: WKSourceEditorViewControllerDelegate {
func sourceEditorViewControllerDidRemoveFindInputAccessoryView(sourceEditorViewController: Components.WKSourceEditorViewController) {
hideFocusNavigationView()
}


func sourceEditorViewControllerDidTapLink(parameters: WKSourceEditorFormatterLinkWizardParameters) {
guard let siteURL = pageURL.wmf_site else {
return
}

if let editPageTitle = parameters.editPageTitle {
guard let link = Link(page: editPageTitle, label: parameters.editPageLabel, exists: true) else {
return
}

guard let editLinkViewController = EditLinkViewController(link: link, siteURL: pageURL.wmf_site, dataStore: dataStore) else {
return
}

editLinkViewController.delegate = self
let navigationController = WMFThemeableNavigationController(rootViewController: editLinkViewController, theme: self.theme)
navigationController.isNavigationBarHidden = true
present(navigationController, animated: true)
}

if let insertSearchTerm = parameters.insertSearchTerm {
guard let link = Link(page: insertSearchTerm, label: nil, exists: false) else {
return
}

let insertLinkViewController = InsertLinkViewController(link: link, siteURL: siteURL, dataStore: dataStore)
insertLinkViewController.delegate = self
let navigationController = WMFThemeableNavigationController(rootViewController: insertLinkViewController, theme: self.theme)
present(navigationController, animated: true)
}
}
}

// MARK: - PageEditorNavigationItemControllerDelegate
Expand Down Expand Up @@ -314,6 +348,42 @@ extension PageEditorViewController: ReadingThemesControlsPresenting {
}
}

// MARK: - EditLinkViewControllerDelegate

extension PageEditorViewController: EditLinkViewControllerDelegate {
func editLinkViewController(_ editLinkViewController: EditLinkViewController, didTapCloseButton button: UIBarButtonItem) {
dismiss(animated: true)
}

func editLinkViewController(_ editLinkViewController: EditLinkViewController, didFinishEditingLink displayText: String?, linkTarget: String) {
dismiss(animated: true)
sourceEditor.editLink(newPageTitle: linkTarget, newPageLabel: displayText)
}

func editLinkViewController(_ editLinkViewController: EditLinkViewController, didFailToExtractArticleTitleFromArticleURL articleURL: URL) {
DDLogError("Failed to extract article title from \(pageURL)")
dismiss(animated: true)
}

func editLinkViewControllerDidRemoveLink(_ editLinkViewController: EditLinkViewController) {
dismiss(animated: true)
sourceEditor.removeLink()
}
}

// MARK: - InsertLinkViewControllerDelegate

extension PageEditorViewController: InsertLinkViewControllerDelegate {
func insertLinkViewController(_ insertLinkViewController: InsertLinkViewController, didTapCloseButton button: UIBarButtonItem) {
dismiss(animated: true)
}

func insertLinkViewController(_ insertLinkViewController: InsertLinkViewController, didInsertLinkFor page: String, withLabel label: String?) {
sourceEditor.insertLink(pageTitle: page)
dismiss(animated: true)
}
}

enum SourceEditorAccessibilityIdentifiers: String {
case entryButton = "Source Editor Entry Button"
case textView = "Source Editor TextView"
Expand Down
4 changes: 4 additions & 0 deletions WikipediaUITests/UITestHelperViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ public class UITestHelperViewController: WKCanvasViewController {


extension UITestHelperViewController: WKSourceEditorViewControllerDelegate {
public func sourceEditorViewControllerDidTapLink(parameters: Components.WKSourceEditorFormatterLinkWizardParameters) {

}

public func sourceEditorViewControllerDidRemoveFindInputAccessoryView(sourceEditorViewController: Components.WKSourceEditorViewController) {

}
Expand Down

0 comments on commit a2d80e7

Please sign in to comment.