Skip to content

Commit

Permalink
Merge pull request wikimedia#4711 from wikimedia/native-editor-links-…
Browse files Browse the repository at this point in the history
…images

Native Editor - Add link and image support
  • Loading branch information
mazevedofs authored Jan 11, 2024
2 parents 32b31ed + 118b0d5 commit 261a1fd
Show file tree
Hide file tree
Showing 22 changed files with 811 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class WKEditorToolbarButton: WKComponentView {
set {
button.isSelected = newValue
updateColors()
accessibilityTraits = newValue ? [.button, .selected] : [.button]
accessibilityTraits = button.accessibilityTraits
}
}

Expand All @@ -75,7 +75,7 @@ class WKEditorToolbarButton: WKComponentView {
set {
button.isEnabled = newValue
updateColors()
accessibilityTraits = newValue ? [.button, .selected] : [.button, .notEnabled]
accessibilityTraits = button.accessibilityTraits
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ protocol WKEditorToolbarExpandingViewDelegate: AnyObject {
func toolbarExpandingViewDidTapFind(toolbarView: WKEditorToolbarExpandingView)
func toolbarExpandingViewDidTapFormatText(toolbarView: WKEditorToolbarExpandingView)
func toolbarExpandingViewDidTapTemplate(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool)
func toolbarExpandingViewDidTapLink(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool)
func toolbarExpandingViewDidTapImage(toolbarView: WKEditorToolbarExpandingView)
func toolbarExpandingViewDidTapUnorderedList(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool)
func toolbarExpandingViewDidTapOrderedList(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool)
func toolbarExpandingViewDidTapIncreaseIndent(toolbarView: WKEditorToolbarExpandingView)
Expand Down Expand Up @@ -46,7 +48,7 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView {
@IBOutlet private weak var citationButton: WKEditorToolbarButton!
@IBOutlet private weak var linkButton: WKEditorToolbarButton!
@IBOutlet private weak var templateButton: WKEditorToolbarButton!
@IBOutlet private weak var mediaButton: WKEditorToolbarButton!
@IBOutlet private weak var imageButton: WKEditorToolbarButton!
@IBOutlet private weak var findInPageButton: WKEditorToolbarButton!

@IBOutlet private weak var unorderedListButton: WKEditorToolbarButton!
Expand Down Expand Up @@ -96,9 +98,9 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView {
templateButton.addTarget(self, action: #selector(tappedTemplate), for: .touchUpInside)
templateButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current.accessibilityLabelButtonTemplate

mediaButton.setImage(WKSFSymbolIcon.for(symbol: .photo), for: .normal)
mediaButton.addTarget(self, action: #selector(tappedMedia), for: .touchUpInside)
mediaButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current.accessibilityLabelButtonMedia
imageButton.setImage(WKSFSymbolIcon.for(symbol: .photo), for: .normal)
imageButton.addTarget(self, action: #selector(tappedMedia), for: .touchUpInside)
imageButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current.accessibilityLabelButtonMedia

findInPageButton.setImage(WKSFSymbolIcon.for(symbol: .docTextMagnifyingGlass), for: .normal)
findInPageButton.addTarget(self, action: #selector(tappedFindInPage), for: .touchUpInside)
Expand Down Expand Up @@ -137,6 +139,7 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView {

cursorRightButton.setImage(WKIcon.chevronRight, for: .normal)
cursorRightButton.addTarget(self, action: #selector(tappedCursorRight), for: .touchUpInside)
cursorRightButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current.accessibilityLabelButtonCursorRight

NotificationCenter.default.addObserver(self, selector: #selector(updateButtonSelectionState(_:)), name: Notification.WKSourceEditorSelectionState, object: nil)
}
Expand All @@ -149,6 +152,8 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView {
}

templateButton.isSelected = selectionState.isHorizontalTemplate
linkButton.isSelected = selectionState.isSimpleLink
imageButton.isEnabled = !selectionState.isBold && !selectionState.isItalics && !selectionState.isSimpleLink

unorderedListButton.isSelected = selectionState.isBulletSingleList || selectionState.isBulletMultipleList
unorderedListButton.isEnabled = !selectionState.isNumberSingleList && !selectionState.isNumberMultipleList
Expand Down Expand Up @@ -223,6 +228,7 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView {
}

@objc private func tappedLink() {
delegate?.toolbarExpandingViewDidTapLink(toolbarView: self, isSelected: linkButton.isSelected)
}

@objc private func tappedUnorderedList() {
Expand Down Expand Up @@ -262,6 +268,7 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView {
}

@objc private func tappedMedia() {
delegate?.toolbarExpandingViewDidTapImage(toolbarView: self)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,9 @@
<outlet property="expandButton" destination="jLt-zh-HFv" id="LkK-4N-EDh"/>
<outlet property="findInPageButton" destination="ysd-bl-nOt" id="YnS-6B-WJp"/>
<outlet property="formatTextButton" destination="q5y-cw-4pq" id="EVV-8g-wME"/>
<outlet property="imageButton" destination="Oyz-BA-g0g" id="Gxu-b5-3Sp"/>
<outlet property="increaseIndentionButton" destination="YcQ-k6-ZuB" id="phQ-vm-eKH"/>
<outlet property="linkButton" destination="lOp-Bv-UED" id="I7F-zV-jom"/>
<outlet property="mediaButton" destination="Oyz-BA-g0g" id="Gxu-b5-3Sp"/>
<outlet property="orderedListButton" destination="Usg-R3-2O9" id="8Qf-xg-gjD"/>
<outlet property="primaryContainerView" destination="BWO-2h-I64" id="8BW-Xe-ftH"/>
<outlet property="scrollView" destination="ZnR-ux-s6T" id="cvF-Ya-s9R"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ protocol WKEditorToolbarHighlightViewDelegate: AnyObject {
func toolbarHighlightViewDidTapBold(toolbarView: WKEditorToolbarHighlightView, isSelected: Bool)
func toolbarHighlightViewDidTapItalics(toolbarView: WKEditorToolbarHighlightView, isSelected: Bool)
func toolbarHighlightViewDidTapTemplate(toolbarView: WKEditorToolbarHighlightView, isSelected: Bool)
func toolbarHighlightViewDidTapLink(toolbarView: WKEditorToolbarHighlightView, isSelected: Bool)
func toolbarHighlightViewDidTapShowMore(toolbarView: WKEditorToolbarHighlightView)
}

Expand Down Expand Up @@ -67,6 +68,7 @@ class WKEditorToolbarHighlightView: WKEditorToolbarView {
boldButton.isSelected = selectionState.isBold
italicsButton.isSelected = selectionState.isItalics
templateButton.isSelected = selectionState.isHorizontalTemplate
linkButton.isSelected = selectionState.isSimpleLink
}

// MARK: - Button Actions
Expand All @@ -86,6 +88,7 @@ class WKEditorToolbarHighlightView: WKEditorToolbarView {
}

@objc private func tappedLink() {
delegate?.toolbarHighlightViewDidTapLink(toolbarView: self, isSelected: linkButton.isSelected)
}

@objc private func tappedTemplate() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ protocol WKEditorInputViewDelegate: AnyObject {
func didTapDecreaseIndent()
func didTapHeading(type: WKEditorInputView.HeadingButtonType)
func didTapStrikethrough(isSelected: Bool)
func didTapLink(isSelected: Bool)
}

class WKEditorInputView: WKComponentView {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class WKEditorToolbarPlainView: WKEditorToolbarView {
boldButton.isSelected = selectionState.isBold
italicsButton.isSelected = selectionState.isItalics
templateButton.isSelected = selectionState.isHorizontalTemplate
linkButton.isSelected = selectionState.isSimpleLink
}

// MARK: Button Actions
Expand All @@ -78,5 +79,6 @@ class WKEditorToolbarPlainView: WKEditorToolbarView {
}

@objc private func tappedLink() {
delegate?.didTapLink(isSelected: linkButton.isSelected)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
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) {
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)
}
}
}

func insertImage(wikitext: String, in textView: UITextView) {

guard let selectedTextRange = textView.selectedTextRange else {
return
}

textView.replace(selectedTextRange, withText: wikitext)
}
}
Loading

0 comments on commit 261a1fd

Please sign in to comment.