diff --git a/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Expanding/WKEditorToolbarExpandingView.swift b/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Expanding/WKEditorToolbarExpandingView.swift
index 5dc203a4944..20448b349b0 100644
--- a/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Expanding/WKEditorToolbarExpandingView.swift
+++ b/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Expanding/WKEditorToolbarExpandingView.swift
@@ -4,6 +4,7 @@ protocol WKEditorToolbarExpandingViewDelegate: AnyObject {
func toolbarExpandingViewDidTapFind(toolbarView: WKEditorToolbarExpandingView)
func toolbarExpandingViewDidTapFormatText(toolbarView: WKEditorToolbarExpandingView)
func toolbarExpandingViewDidTapTemplate(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool)
+ func toolbarExpandingViewDidTapReference(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool)
func toolbarExpandingViewDidTapLink(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool)
func toolbarExpandingViewDidTapImage(toolbarView: WKEditorToolbarExpandingView)
func toolbarExpandingViewDidTapUnorderedList(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool)
@@ -45,7 +46,7 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView {
@IBOutlet weak var secondaryContainerView: UIView!
@IBOutlet private weak var formatTextButton: WKEditorToolbarButton!
- @IBOutlet private weak var citationButton: WKEditorToolbarButton!
+ @IBOutlet private weak var referenceButton: WKEditorToolbarButton!
@IBOutlet private weak var linkButton: WKEditorToolbarButton!
@IBOutlet private weak var templateButton: WKEditorToolbarButton!
@IBOutlet private weak var imageButton: WKEditorToolbarButton!
@@ -86,9 +87,9 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView {
formatTextButton.accessibilityIdentifier = WKSourceEditorAccessibilityIdentifiers.current?.formatTextButton
formatTextButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current.accessibilityLabelButtonFormatText
- citationButton.setImage(WKSFSymbolIcon.for(symbol: .quoteOpening), for: .normal)
- citationButton.addTarget(self, action: #selector(tappedCitation), for: .touchUpInside)
- citationButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current.accessibilityLabelButtonCitation
+ referenceButton.setImage(WKSFSymbolIcon.for(symbol: .quoteOpening), for: .normal)
+ referenceButton.addTarget(self, action: #selector(tappedReference), for: .touchUpInside)
+ referenceButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current.accessibilityLabelButtonCitation
linkButton.setImage(WKSFSymbolIcon.for(symbol: .link), for: .normal)
linkButton.addTarget(self, action: #selector(tappedLink), for: .touchUpInside)
@@ -152,6 +153,7 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView {
}
templateButton.isSelected = selectionState.isHorizontalTemplate
+ referenceButton.isSelected = selectionState.isHorizontalReference
linkButton.isSelected = selectionState.isSimpleLink
imageButton.isEnabled = !selectionState.isBold && !selectionState.isItalics && !selectionState.isSimpleLink
@@ -224,7 +226,8 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView {
@objc private func tappedFormatHeading() {
}
- @objc private func tappedCitation() {
+ @objc private func tappedReference() {
+ delegate?.toolbarExpandingViewDidTapReference(toolbarView: self, isSelected: referenceButton.isSelected)
}
@objc private func tappedLink() {
diff --git a/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Expanding/WKEditorToolbarExpandingView.xib b/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Expanding/WKEditorToolbarExpandingView.xib
index cf669071ea9..4b9c61e75cc 100644
--- a/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Expanding/WKEditorToolbarExpandingView.xib
+++ b/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Expanding/WKEditorToolbarExpandingView.xib
@@ -267,7 +267,6 @@
-
@@ -281,6 +280,7 @@
+
diff --git a/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Highlight/WKEditorToolbarHighlightView.swift b/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Highlight/WKEditorToolbarHighlightView.swift
index ecf0c1b4b27..33238ec9cd9 100644
--- a/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Highlight/WKEditorToolbarHighlightView.swift
+++ b/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Highlight/WKEditorToolbarHighlightView.swift
@@ -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 toolbarHighlightViewDidTapReference(toolbarView: WKEditorToolbarHighlightView, isSelected: Bool)
func toolbarHighlightViewDidTapLink(toolbarView: WKEditorToolbarHighlightView, isSelected: Bool)
func toolbarHighlightViewDidTapShowMore(toolbarView: WKEditorToolbarHighlightView)
}
@@ -16,7 +17,7 @@ class WKEditorToolbarHighlightView: WKEditorToolbarView {
@IBOutlet private weak var boldButton: WKEditorToolbarButton!
@IBOutlet private weak var italicsButton: WKEditorToolbarButton!
- @IBOutlet private weak var citationButton: WKEditorToolbarButton!
+ @IBOutlet private weak var referenceButton: WKEditorToolbarButton!
@IBOutlet private weak var linkButton: WKEditorToolbarButton!
@IBOutlet private weak var templateButton: WKEditorToolbarButton!
@IBOutlet private weak var showMoreButton: WKEditorToolbarNavigatorButton!
@@ -39,9 +40,9 @@ class WKEditorToolbarHighlightView: WKEditorToolbarView {
italicsButton.addTarget(self, action: #selector(tappedItalics), for: .touchUpInside)
italicsButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current?.accessibilityLabelButtonItalics
- citationButton.setImage(WKSFSymbolIcon.for(symbol: .quoteOpening), for: .normal)
- citationButton.addTarget(self, action: #selector(tappedCitation), for: .touchUpInside)
- citationButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current?.accessibilityLabelButtonCitation
+ referenceButton.setImage(WKSFSymbolIcon.for(symbol: .quoteOpening), for: .normal)
+ referenceButton.addTarget(self, action: #selector(tappedReference), for: .touchUpInside)
+ referenceButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current?.accessibilityLabelButtonCitation
linkButton.setImage(WKSFSymbolIcon.for(symbol: .link), for: .normal)
linkButton.addTarget(self, action: #selector(tappedLink), for: .touchUpInside)
@@ -68,6 +69,7 @@ class WKEditorToolbarHighlightView: WKEditorToolbarView {
boldButton.isSelected = selectionState.isBold
italicsButton.isSelected = selectionState.isItalics
templateButton.isSelected = selectionState.isHorizontalTemplate
+ referenceButton.isSelected = selectionState.isHorizontalReference
linkButton.isSelected = selectionState.isSimpleLink
}
@@ -84,7 +86,8 @@ class WKEditorToolbarHighlightView: WKEditorToolbarView {
@objc private func tappedFormatHeading() {
}
- @objc private func tappedCitation() {
+ @objc private func tappedReference() {
+ delegate?.toolbarHighlightViewDidTapReference(toolbarView: self, isSelected: referenceButton.isSelected)
}
@objc private func tappedLink() {
diff --git a/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Highlight/WKEditorToolbarHighlightView.xib b/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Highlight/WKEditorToolbarHighlightView.xib
index 78e7480b361..37ecb6e927b 100644
--- a/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Highlight/WKEditorToolbarHighlightView.xib
+++ b/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Highlight/WKEditorToolbarHighlightView.xib
@@ -90,9 +90,9 @@
-
+
diff --git a/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorInputView.swift b/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorInputView.swift
index bcb20840fb6..7aa62ae047f 100644
--- a/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorInputView.swift
+++ b/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorInputView.swift
@@ -6,6 +6,7 @@ protocol WKEditorInputViewDelegate: AnyObject {
func didTapBold(isSelected: Bool)
func didTapItalics(isSelected: Bool)
func didTapTemplate(isSelected: Bool)
+ func didTapReference(isSelected: Bool)
func didTapBulletList(isSelected: Bool)
func didTapNumberList(isSelected: Bool)
func didTapIncreaseIndent()
diff --git a/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorToolbarPlainView.swift b/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorToolbarPlainView.swift
index b39cd5a7cbd..57468fe1075 100644
--- a/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorToolbarPlainView.swift
+++ b/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorToolbarPlainView.swift
@@ -6,7 +6,7 @@ class WKEditorToolbarPlainView: WKEditorToolbarView {
@IBOutlet private weak var boldButton: WKEditorToolbarButton!
@IBOutlet private weak var italicsButton: WKEditorToolbarButton!
- @IBOutlet private weak var citationButton: WKEditorToolbarButton!
+ @IBOutlet private weak var referenceButton: WKEditorToolbarButton!
@IBOutlet private weak var linkButton: WKEditorToolbarButton!
@IBOutlet private weak var templateButton: WKEditorToolbarButton!
@IBOutlet private weak var commentButton: WKEditorToolbarButton!
@@ -26,9 +26,9 @@ class WKEditorToolbarPlainView: WKEditorToolbarView {
italicsButton.addTarget(self, action: #selector(tappedItalics), for: .touchUpInside)
italicsButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current?.accessibilityLabelButtonItalics
- citationButton.setImage(WKSFSymbolIcon.for(symbol: .quoteOpening), for: .normal)
- citationButton.addTarget(self, action: #selector(tappedCitation), for: .touchUpInside)
- citationButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current?.accessibilityLabelButtonCitation
+ referenceButton.setImage(WKSFSymbolIcon.for(symbol: .quoteOpening), for: .normal)
+ referenceButton.addTarget(self, action: #selector(tappedReference), for: .touchUpInside)
+ referenceButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current?.accessibilityLabelButtonCitation
linkButton.setImage(WKIcon.link, for: .normal)
linkButton.addTarget(self, action: #selector(tappedLink), for: .touchUpInside)
@@ -55,6 +55,7 @@ class WKEditorToolbarPlainView: WKEditorToolbarView {
boldButton.isSelected = selectionState.isBold
italicsButton.isSelected = selectionState.isItalics
templateButton.isSelected = selectionState.isHorizontalTemplate
+ referenceButton.isSelected = selectionState.isHorizontalReference
linkButton.isSelected = selectionState.isSimpleLink
}
@@ -68,7 +69,8 @@ class WKEditorToolbarPlainView: WKEditorToolbarView {
delegate?.didTapItalics(isSelected: italicsButton.isSelected)
}
- @objc private func tappedCitation() {
+ @objc private func tappedReference() {
+ delegate?.didTapReference(isSelected: referenceButton.isSelected)
}
@objc private func tappedTemplate() {
diff --git a/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorToolbarPlainView.xib b/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorToolbarPlainView.xib
index 0e700570dac..61d1e9b3fb0 100644
--- a/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorToolbarPlainView.xib
+++ b/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorToolbarPlainView.xib
@@ -1,9 +1,8 @@
-
+
-
-
+
@@ -54,10 +53,10 @@
-
+
diff --git a/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorFormatter+ButtonActions.swift b/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorFormatter+ButtonActions.swift
index ce9f1869e4e..7364b92825b 100644
--- a/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorFormatter+ButtonActions.swift
+++ b/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorFormatter+ButtonActions.swift
@@ -14,19 +14,26 @@ extension WKSourceEditorFormatter {
toggleFormatting(startingFormattingString: formattingString, endingFormattingString: formattingString, action: action, in: textView)
}
- func toggleFormatting(startingFormattingString: String, endingFormattingString: String, action: WKSourceEditorFormatterButtonAction, in textView: UITextView) {
-
+ func toggleFormatting(startingFormattingString: String, wildcardStartingFormattingString: String? = nil, endingFormattingString: String, action: WKSourceEditorFormatterButtonAction, in textView: UITextView) {
+
+ var resolvedStartingFormattingString = startingFormattingString
+ if let wildcardStartingFormattingString {
+ resolvedStartingFormattingString = getModifiedStartingFormattingStringForSingleWildcard(startingFormattingString: wildcardStartingFormattingString, textView: textView)
+ }
+
if textView.selectedRange.length == 0 {
+
switch action {
case .remove:
- expandSelectedRangeUpToNearestFormattingStrings(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView)
+
+ expandSelectedRangeUpToNearestFormattingStrings(startingFormattingString: resolvedStartingFormattingString, endingFormattingString: endingFormattingString, in: textView)
- if selectedRangeIsSurroundedByFormattingStrings(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView) {
- removeSurroundingFormattingStringsFromSelectedRange(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView)
+ if selectedRangeIsSurroundedByFormattingStrings(startingFormattingString: resolvedStartingFormattingString, endingFormattingString: endingFormattingString, in: textView) {
+ removeSurroundingFormattingStringsFromSelectedRange(startingFormattingString: resolvedStartingFormattingString, endingFormattingString: endingFormattingString, in: textView)
}
case .add:
- if selectedRangeIsSurroundedByFormattingStrings(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView) {
- removeSurroundingFormattingStringsFromSelectedRange(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView)
+ if selectedRangeIsSurroundedByFormattingStrings(startingFormattingString: resolvedStartingFormattingString, endingFormattingString: endingFormattingString, in: textView) {
+ removeSurroundingFormattingStringsFromSelectedRange(startingFormattingString: resolvedStartingFormattingString, endingFormattingString: endingFormattingString, in: textView)
} else {
addStringFormattingCharacters(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView)
}
@@ -36,8 +43,8 @@ extension WKSourceEditorFormatter {
switch action {
case .remove:
- if selectedRangeIsSurroundedByFormattingStrings(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView) {
- removeSurroundingFormattingStringsFromSelectedRange(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView)
+ if selectedRangeIsSurroundedByFormattingStrings(startingFormattingString: resolvedStartingFormattingString, endingFormattingString: endingFormattingString, in: textView) {
+ removeSurroundingFormattingStringsFromSelectedRange(startingFormattingString: resolvedStartingFormattingString, endingFormattingString: endingFormattingString, in: textView)
} else {
// Note the flipped formatting string params.
@@ -77,6 +84,64 @@ extension WKSourceEditorFormatter {
}
}
+
+ /// Takes a starting formatting string with a wildcard. Searches backwards from the selection point and seeks out a match (up until the first line break) and sends back a resolved starting formatting string
+ /// For example:
+ /// If you send in "[", it can match and send back "]["
+ /// - Parameters:
+ /// - originalStartingFormattingString: Starting formatting string with a single wildcard character (*)
+ /// - textView: UITextView to search
+ /// - Returns: A new resolved starting formatting string with no wildcard.
+ func getModifiedStartingFormattingStringForSingleWildcard(startingFormattingString originalStartingFormattingString: String, textView: UITextView) -> String {
+ guard originalStartingFormattingString.contains("*") else {
+ return originalStartingFormattingString
+ }
+
+ let splitStrings = originalStartingFormattingString.split(separator: "*").map { String($0) }
+ guard splitStrings.count == 2 else {
+ return originalStartingFormattingString
+ }
+
+ guard let originalSelectedRange = textView.selectedTextRange else {
+ return originalStartingFormattingString
+ }
+
+ // Loop backwards and find
+ var i = 0
+ var closingPosition: UITextPosition?
+ var startingPosition: UITextPosition?
+ while let loopPosition = textView.position(from: originalSelectedRange.start, offset: i) {
+ let newRange = textView.textRange(from: loopPosition, to: originalSelectedRange.start)
+
+ if closingPosition == nil && rangeIsPrecededByFormattingString(range: newRange, formattingString: splitStrings[1], in: textView) {
+
+ closingPosition = loopPosition
+ continue
+ }
+
+ if closingPosition != nil && rangeIsPrecededByFormattingString(range: newRange, formattingString: splitStrings[0], in: textView) {
+ startingPosition = textView.position(from: loopPosition, offset: -splitStrings[0].count)
+ break
+ }
+
+ // Stop searching if you encounter a line break
+ if rangeIsPrecededByFormattingString(range: newRange, formattingString: "\n", in: textView) {
+ break
+ }
+
+ i = i - 1
+ }
+
+ guard let startingPosition,
+ let closingPosition,
+ let newTextRange = textView.textRange(from: startingPosition, to: closingPosition),
+ let modifiedStartingFormattingString = textView.text(in: newTextRange) else {
+ return originalStartingFormattingString
+ }
+
+ return modifiedStartingFormattingString
+ }
+
// MARK: - Expanding selected range methods
func expandSelectedRangeUpToNearestFormattingStrings(startingFormattingString: String, endingFormattingString: String, in textView: UITextView) {
diff --git a/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorReference+ButtonActions.swift b/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorReference+ButtonActions.swift
new file mode 100644
index 00000000000..baf19113136
--- /dev/null
+++ b/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorReference+ButtonActions.swift
@@ -0,0 +1,8 @@
+import Foundation
+import ComponentsObjC
+
+extension WKSourceEditorFormatterReference {
+ func toggleReferenceFormatting(action: WKSourceEditorFormatterButtonAction, in textView: UITextView) {
+ toggleFormatting(startingFormattingString: "][", wildcardStartingFormattingString: "][", endingFormattingString: "]", action: action, in: textView)
+ }
+}
diff --git a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift
index 11f3897ed6d..9859fff34ec 100644
--- a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift
+++ b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift
@@ -17,6 +17,7 @@ fileprivate var needsTextKit2: Bool {
let isBold: Bool
let isItalics: Bool
let isHorizontalTemplate: Bool
+ let isHorizontalReference: Bool
let isBulletSingleList: Bool
let isBulletMultipleList: Bool
let isNumberSingleList: Bool
@@ -29,11 +30,11 @@ fileprivate var needsTextKit2: Bool {
let isStrikethrough: Bool
let isSimpleLink: Bool
let isLinkWithNestedLink: Bool
-
- init(isBold: Bool, isItalics: Bool, isHorizontalTemplate: Bool, isBulletSingleList: Bool, isBulletMultipleList: Bool, isNumberSingleList: Bool, isNumberMultipleList: Bool, isHeading: Bool, isSubheading1: Bool, isSubheading2: Bool, isSubheading3: Bool, isSubheading4: Bool, isStrikethrough: Bool, isSimpleLink: Bool, isLinkWithNestedLink: Bool) {
+ init(isBold: Bool, isItalics: Bool, isHorizontalTemplate: Bool, isHorizontalReference: Bool, isBulletSingleList: Bool, isBulletMultipleList: Bool, isNumberSingleList: Bool, isNumberMultipleList: Bool, isHeading: Bool, isSubheading1: Bool, isSubheading2: Bool, isSubheading3: Bool, isSubheading4: Bool, isStrikethrough: Bool, isSimpleLink: Bool, isLinkWithNestedLink: Bool) {
self.isBold = isBold
self.isItalics = isItalics
self.isHorizontalTemplate = isHorizontalTemplate
+ self.isHorizontalReference = isHorizontalReference
self.isBulletSingleList = isBulletSingleList
self.isBulletMultipleList = isBulletMultipleList
self.isNumberSingleList = isNumberSingleList
@@ -47,6 +48,7 @@ fileprivate var needsTextKit2: Bool {
self.isSimpleLink = isSimpleLink
self.isLinkWithNestedLink = isLinkWithNestedLink
}
+
}
final class WKSourceEditorTextFrameworkMediator: NSObject {
@@ -59,6 +61,7 @@ final class WKSourceEditorTextFrameworkMediator: NSObject {
private(set) var formatters: [WKSourceEditorFormatter] = []
private(set) var boldItalicsFormatter: WKSourceEditorFormatterBoldItalics?
private(set) var templateFormatter: WKSourceEditorFormatterTemplate?
+ private(set) var referenceFormatter: WKSourceEditorFormatterReference?
private(set) var listFormatter: WKSourceEditorFormatterList?
private(set) var headingFormatter: WKSourceEditorFormatterHeading?
private(set) var strikethroughFormatter: WKSourceEditorFormatterStrikethrough?
@@ -130,6 +133,7 @@ final class WKSourceEditorTextFrameworkMediator: NSObject {
let fonts = self.fonts
let templateFormatter = WKSourceEditorFormatterTemplate(colors: colors, fonts: fonts)
+ let referenceFormatter = WKSourceEditorFormatterReference(colors: colors, fonts: fonts)
let boldItalicsFormatter = WKSourceEditorFormatterBoldItalics(colors: colors, fonts: fonts)
let listFormatter = WKSourceEditorFormatterList(colors: colors, fonts: fonts)
let headingFormatter = WKSourceEditorFormatterHeading(colors: colors, fonts: fonts)
@@ -138,16 +142,18 @@ final class WKSourceEditorTextFrameworkMediator: NSObject {
self.formatters = [WKSourceEditorFormatterBase(colors: colors, fonts: fonts, textAlignment: viewModel.textAlignment),
templateFormatter,
boldItalicsFormatter,
+ referenceFormatter,
listFormatter,
headingFormatter,
strikethroughFormatter, linkFormatter]
self.boldItalicsFormatter = boldItalicsFormatter
self.templateFormatter = templateFormatter
+ self.referenceFormatter = referenceFormatter
self.listFormatter = listFormatter
self.headingFormatter = headingFormatter
self.strikethroughFormatter = strikethroughFormatter
self.linkFormatter = linkFormatter
-
+
if needsTextKit2 {
if #available(iOS 16.0, *) {
let textContentManager = textView.textLayoutManager?.textContentManager
@@ -186,12 +192,14 @@ final class WKSourceEditorTextFrameworkMediator: NSObject {
if needsTextKit2 {
guard let textKit2Data = textkit2SelectionData(selectedDocumentRange: selectedDocumentRange) else {
- return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isBulletSingleList: false, isBulletMultipleList: false, isNumberSingleList: false, isNumberMultipleList: false, isHeading: false, isSubheading1: false, isSubheading2: false, isSubheading3: false, isSubheading4: false, isStrikethrough: false, isSimpleLink: false, isLinkWithNestedLink: false)
+ return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isHorizontalReference: false, isBulletSingleList: false, isBulletMultipleList: false, isNumberSingleList: false, isNumberMultipleList: false, isHeading: false, isSubheading1: false, isSubheading2: false, isSubheading3: false, isSubheading4: false, isStrikethrough: false, isSimpleLink: false, isLinkWithNestedLink: false)
+
}
let isBold = boldItalicsFormatter?.attributedString(textKit2Data.paragraphAttributedString, isBoldIn: textKit2Data.paragraphSelectedRange) ?? false
let isItalics = boldItalicsFormatter?.attributedString(textKit2Data.paragraphAttributedString, isItalicsIn: textKit2Data.paragraphSelectedRange) ?? false
let isHorizontalTemplate = templateFormatter?.attributedString(textKit2Data.paragraphAttributedString, isHorizontalTemplateIn: textKit2Data.paragraphSelectedRange) ?? false
+ let isHorizontalReference = referenceFormatter?.attributedString(textKit2Data.paragraphAttributedString, isHorizontalReferenceIn: textKit2Data.paragraphSelectedRange) ?? false
let isBulletSingleList = listFormatter?.attributedString(textKit2Data.paragraphAttributedString, isBulletSingleIn: textKit2Data.paragraphSelectedRange) ?? false
let isBulletMultipleList = listFormatter?.attributedString(textKit2Data.paragraphAttributedString, isBulletMultipleIn: textKit2Data.paragraphSelectedRange) ?? false
let isNumberSingleList = listFormatter?.attributedString(textKit2Data.paragraphAttributedString, isNumberSingleIn: textKit2Data.paragraphSelectedRange) ?? false
@@ -205,15 +213,16 @@ final class WKSourceEditorTextFrameworkMediator: NSObject {
let isSimpleLink = linkFormatter?.attributedString(textKit2Data.paragraphAttributedString, isSimpleLinkIn: textKit2Data.paragraphSelectedRange) ?? false
let isLinkWithNestedLink = linkFormatter?.attributedString(textKit2Data.paragraphAttributedString, isLinkWithNestedLinkIn: textKit2Data.paragraphSelectedRange) ?? false
- return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isBulletSingleList: isBulletSingleList, isBulletMultipleList: isBulletMultipleList, isNumberSingleList: isNumberSingleList, isNumberMultipleList: isNumberMultipleList, isHeading: isHeading, isSubheading1: isSubheading1, isSubheading2: isSubheading2, isSubheading3: isSubheading3, isSubheading4: isSubheading4, isStrikethrough: isStrikethrough, isSimpleLink: isSimpleLink, isLinkWithNestedLink: isLinkWithNestedLink)
+ return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isHorizontalReference: isHorizontalReference, isBulletSingleList: isBulletSingleList, isBulletMultipleList: isBulletMultipleList, isNumberSingleList: isNumberSingleList, isNumberMultipleList: isNumberMultipleList, isHeading: isHeading, isSubheading1: isSubheading1, isSubheading2: isSubheading2, isSubheading3: isSubheading3, isSubheading4: isSubheading4, isStrikethrough: isStrikethrough, isSimpleLink: isSimpleLink, isLinkWithNestedLink: isLinkWithNestedLink)
} else {
guard let textKit1Storage else {
- return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isBulletSingleList: false, isBulletMultipleList: false, isNumberSingleList: false, isNumberMultipleList: false, isHeading: false, isSubheading1: false, isSubheading2: false, isSubheading3: false, isSubheading4: false, isStrikethrough: false, isSimpleLink: false, isLinkWithNestedLink: false)
+ return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isHorizontalReference: false, isBulletSingleList: false, isBulletMultipleList: false, isNumberSingleList: false, isNumberMultipleList: false, isHeading: false, isSubheading1: false, isSubheading2: false, isSubheading3: false, isSubheading4: false, isStrikethrough: false, isSimpleLink: false, isLinkWithNestedLink: false)
}
-
+
let isBold = boldItalicsFormatter?.attributedString(textKit1Storage, isBoldIn: selectedDocumentRange) ?? false
let isItalics = boldItalicsFormatter?.attributedString(textKit1Storage, isItalicsIn: selectedDocumentRange) ?? false
let isHorizontalTemplate = templateFormatter?.attributedString(textKit1Storage, isHorizontalTemplateIn: selectedDocumentRange) ?? false
+ let isHorizontalReference = referenceFormatter?.attributedString(textKit1Storage, isHorizontalReferenceIn: selectedDocumentRange) ?? false
let isBulletSingleList = listFormatter?.attributedString(textKit1Storage, isBulletSingleIn: selectedDocumentRange) ?? false
let isBulletMultipleList = listFormatter?.attributedString(textKit1Storage, isBulletMultipleIn: selectedDocumentRange) ?? false
let isNumberSingleList = listFormatter?.attributedString(textKit1Storage, isNumberSingleIn: selectedDocumentRange) ?? false
@@ -227,7 +236,7 @@ final class WKSourceEditorTextFrameworkMediator: NSObject {
let isSimpleLink = linkFormatter?.attributedString(textKit1Storage, isSimpleLinkIn: selectedDocumentRange) ?? false
let isLinkWithNestedLink = linkFormatter?.attributedString(textKit1Storage, isLinkWithNestedLinkIn: selectedDocumentRange) ?? false
- return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isBulletSingleList: isBulletSingleList, isBulletMultipleList: isBulletMultipleList, isNumberSingleList: isNumberSingleList, isNumberMultipleList: isNumberMultipleList, isHeading: isHeading, isSubheading1: isSubheading1, isSubheading2: isSubheading2, isSubheading3: isSubheading3, isSubheading4: isSubheading4, isStrikethrough: isStrikethrough, isSimpleLink: isSimpleLink, isLinkWithNestedLink: isLinkWithNestedLink)
+ return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isHorizontalReference: isHorizontalReference, isBulletSingleList: isBulletSingleList, isBulletMultipleList: isBulletMultipleList, isNumberSingleList: isNumberSingleList, isNumberMultipleList: isNumberMultipleList, isHeading: isHeading, isSubheading1: isSubheading1, isSubheading2: isSubheading2, isSubheading3: isSubheading3, isSubheading4: isSubheading4, isStrikethrough: isStrikethrough, isSimpleLink: isSimpleLink, isLinkWithNestedLink: isLinkWithNestedLink)
}
}
diff --git a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorViewController.swift b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorViewController.swift
index 9e874c794bd..95555725aa5 100644
--- a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorViewController.swift
+++ b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorViewController.swift
@@ -314,7 +314,12 @@ extension WKSourceEditorViewController: WKEditorToolbarExpandingViewDelegate {
let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add
textFrameworkMediator.templateFormatter?.toggleTemplateFormatting(action: action, in: textView)
}
-
+
+ func toolbarExpandingViewDidTapReference(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool) {
+ let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add
+ textFrameworkMediator.referenceFormatter?.toggleReferenceFormatting(action: action, in: textView)
+ }
+
func toolbarExpandingViewDidTapLink(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool) {
presentLinkWizard(linkButtonIsSelected: isSelected)
}
@@ -360,9 +365,15 @@ extension WKSourceEditorViewController: WKEditorToolbarHighlightViewDelegate {
let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add
textFrameworkMediator.templateFormatter?.toggleTemplateFormatting(action: action, in: textView)
}
-
+
+ func toolbarHighlightViewDidTapReference(toolbarView: WKEditorToolbarHighlightView, isSelected: Bool) {
+ let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add
+ textFrameworkMediator.referenceFormatter?.toggleReferenceFormatting(action: action, in: textView)
+ }
+
func toolbarHighlightViewDidTapLink(toolbarView: WKEditorToolbarHighlightView, isSelected: Bool) {
presentLinkWizard(linkButtonIsSelected: isSelected)
+
}
func toolbarHighlightViewDidTapShowMore(toolbarView: WKEditorToolbarHighlightView) {
@@ -392,6 +403,11 @@ extension WKSourceEditorViewController: WKEditorInputViewDelegate {
let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add
textFrameworkMediator.templateFormatter?.toggleTemplateFormatting(action: action, in: textView)
}
+
+ func didTapReference(isSelected: Bool) {
+ let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add
+ textFrameworkMediator.referenceFormatter?.toggleReferenceFormatting(action: action, in: textView)
+ }
func didTapBulletList(isSelected: Bool) {
let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add
diff --git a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h
new file mode 100644
index 00000000000..a3296aedfe2
--- /dev/null
+++ b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h
@@ -0,0 +1,9 @@
+#import "WKSourceEditorFormatter.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface WKSourceEditorFormatterReference : WKSourceEditorFormatter
+- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isHorizontalReferenceInRange:(NSRange)range;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m
new file mode 100644
index 00000000000..f427197c3b4
--- /dev/null
+++ b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m
@@ -0,0 +1,179 @@
+#import "WKSourceEditorFormatterReference.h"
+#import "WKSourceEditorColors.h"
+
+@interface WKSourceEditorFormatterReference ()
+@property (nonatomic, strong) NSDictionary *refAttributes;
+@property (nonatomic, strong) NSDictionary *refEmptyAttributes;
+@property (nonatomic, strong) NSDictionary *refContentAttributes;
+
+@property (nonatomic, strong) NSRegularExpression *refHorizontalRegex;
+@property (nonatomic, strong) NSRegularExpression *refOpenRegex;
+@property (nonatomic, strong) NSRegularExpression *refCloseRegex;
+@property (nonatomic, strong) NSRegularExpression *refEmptyRegex;
+@end
+
+@implementation WKSourceEditorFormatterReference
+
+#pragma mark - Custom Attributed String Keys
+
+NSString * const WKSourceEditorCustomKeyContentReference = @"WKSourceEditorCustomKeyContentReference";
+
+#pragma mark - Overrides
+
+- (instancetype)initWithColors:(WKSourceEditorColors *)colors fonts:(WKSourceEditorFonts *)fonts {
+ self = [super initWithColors:colors fonts:fonts];
+ if (self) {
+ _refAttributes = @{
+ NSForegroundColorAttributeName: colors.greenForegroundColor,
+ WKSourceEditorCustomKeyColorGreen: [NSNumber numberWithBool:YES]
+ };
+
+ _refEmptyAttributes = @{
+ NSForegroundColorAttributeName: colors.greenForegroundColor,
+ WKSourceEditorCustomKeyColorGreen: [NSNumber numberWithBool:YES]
+ };
+
+ _refContentAttributes = @{
+ WKSourceEditorCustomKeyContentReference: [NSNumber numberWithBool:YES]
+ };
+
+ _refHorizontalRegex = [[NSRegularExpression alloc] initWithPattern:@"(]+?)?>)(.*?)(<\\/ref>)" options:0 error:nil];
+ _refOpenRegex = [[NSRegularExpression alloc] initWithPattern:@"]+?)?>" options:0 error:nil];
+ _refCloseRegex = [[NSRegularExpression alloc] initWithPattern:@"<\\/ref>" options:0 error:nil];
+ _refEmptyRegex = [[NSRegularExpression alloc] initWithPattern:@"[]+?\\/>" options:0 error:nil];
+ }
+
+ return self;
+}
+
+- (void)addSyntaxHighlightingToAttributedString:(nonnull NSMutableAttributedString *)attributedString inRange:(NSRange)range {
+
+ // Reset
+ [attributedString removeAttribute:WKSourceEditorCustomKeyContentReference range:range];
+
+ [self.refHorizontalRegex enumerateMatchesInString:attributedString.string
+ options:0
+ range:range
+ usingBlock:^(NSTextCheckingResult *_Nullable result, NSMatchingFlags flags, BOOL *_Nonnull stop) {
+ NSRange fullMatch = [result rangeAtIndex:0];
+ NSRange openingRange = [result rangeAtIndex:1];
+ NSRange contentRange = [result rangeAtIndex:2];
+ NSRange closingRange = [result rangeAtIndex:3];
+
+ if (openingRange.location != NSNotFound) {
+ [attributedString addAttributes:self.refAttributes range:openingRange];
+ }
+
+ if (contentRange.location != NSNotFound) {
+ [attributedString addAttributes:self.refContentAttributes range:contentRange];
+ }
+
+ if (closingRange.location != NSNotFound) {
+ [attributedString addAttributes:self.refAttributes range:closingRange];
+ }
+ }];
+
+ [self.refEmptyRegex enumerateMatchesInString:attributedString.string
+ options:0
+ range:range
+ usingBlock:^(NSTextCheckingResult *_Nullable result, NSMatchingFlags flags, BOOL *_Nonnull stop) {
+ NSRange fullMatch = [result rangeAtIndex:0];
+
+ if (fullMatch.location != NSNotFound) {
+ [attributedString addAttributes:self.refAttributes range:fullMatch];
+ }
+ }];
+
+ // refOpenAndClose regex doesn't match everything. This scoops up extra open and closing ref tags that do not have a matching tag on the same line
+
+ [self.refOpenRegex enumerateMatchesInString:attributedString.string
+ options:0
+ range:range
+ usingBlock:^(NSTextCheckingResult *_Nullable result, NSMatchingFlags flags, BOOL *_Nonnull stop) {
+ NSRange fullMatch = [result rangeAtIndex:0];
+
+ if (fullMatch.location != NSNotFound) {
+ [attributedString addAttributes:self.refAttributes range:fullMatch];
+ }
+ }];
+
+ [self.refCloseRegex enumerateMatchesInString:attributedString.string
+ options:0
+ range:range
+ usingBlock:^(NSTextCheckingResult *_Nullable result, NSMatchingFlags flags, BOOL *_Nonnull stop) {
+ NSRange fullMatch = [result rangeAtIndex:0];
+
+ if (fullMatch.location != NSNotFound) {
+ [attributedString addAttributes:self.refAttributes range:fullMatch];
+ }
+ }];
+}
+
+- (void)updateColors:(WKSourceEditorColors *)colors inAttributedString:(NSMutableAttributedString *)attributedString inRange:(NSRange)range {
+
+ NSMutableDictionary *mutAttributes = [[NSMutableDictionary alloc] initWithDictionary:self.refAttributes];
+ [mutAttributes setObject:colors.greenForegroundColor forKey:NSForegroundColorAttributeName];
+ self.refAttributes = [[NSDictionary alloc] initWithDictionary:mutAttributes];
+
+ [attributedString enumerateAttribute:WKSourceEditorCustomKeyColorGreen
+ inRange:range
+ options:nil
+ usingBlock:^(id value, NSRange localRange, BOOL *stop) {
+ if ([value isKindOfClass: [NSNumber class]]) {
+ NSNumber *numValue = (NSNumber *)value;
+ if ([numValue boolValue] == YES) {
+ [attributedString addAttributes:self.refAttributes range:localRange];
+ }
+ }
+ }];
+}
+
+- (void)updateFonts:(WKSourceEditorFonts *)fonts inAttributedString:(NSMutableAttributedString *)attributedString inRange:(NSRange)range {
+ // No special font handling needed for references
+}
+
+#pragma mark - Public
+
+- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isHorizontalReferenceInRange:(NSRange)range {
+ __block BOOL isContentKey = NO;
+
+ if (range.length == 0) {
+
+ if (attributedString.length > range.location) {
+ NSDictionary *attrs = [attributedString attributesAtIndex:range.location effectiveRange:nil];
+
+ if (attrs[WKSourceEditorCustomKeyContentReference] != nil) {
+ isContentKey = YES;
+ } else {
+ // Edge case, check previous character if we are up against closing string
+ if (attrs[WKSourceEditorCustomKeyColorGreen]) {
+ attrs = [attributedString attributesAtIndex:range.location - 1 effectiveRange:nil];
+ if (attrs[WKSourceEditorCustomKeyContentReference] != nil) {
+ isContentKey = YES;
+ }
+ }
+ }
+ }
+
+ } else {
+ __block NSRange unionRange = NSMakeRange(NSNotFound, 0);
+ [attributedString enumerateAttributesInRange:range options:nil usingBlock:^(NSDictionary * _Nonnull attrs, NSRange loopRange, BOOL * _Nonnull stop) {
+ if (attrs[WKSourceEditorCustomKeyContentReference] != nil) {
+ if (unionRange.location == NSNotFound) {
+ unionRange = loopRange;
+ } else {
+ unionRange = NSUnionRange(unionRange, loopRange);
+ }
+ stop = YES;
+ }
+ }];
+
+ if (NSEqualRanges(unionRange, range)) {
+ isContentKey = YES;
+ }
+ }
+
+ return isContentKey;
+}
+
+@end
diff --git a/Components/Sources/ComponentsObjC/include/ComponentsObjC.h b/Components/Sources/ComponentsObjC/include/ComponentsObjC.h
index 13a96ff2f1b..c7ef8ee727c 100644
--- a/Components/Sources/ComponentsObjC/include/ComponentsObjC.h
+++ b/Components/Sources/ComponentsObjC/include/ComponentsObjC.h
@@ -8,6 +8,7 @@
#import "WKSourceEditorFormatterBase.h"
#import "WKSourceEditorFormatterBoldItalics.h"
#import "WKSourceEditorFormatterTemplate.h"
+#import "WKSourceEditorFormatterReference.h"
#import "WKSourceEditorFormatterList.h"
#import "WKSourceEditorFormatterHeading.h"
#import "WKSourceEditorFormatterStrikethrough.h"
diff --git a/Components/Sources/ComponentsObjC/include/WKSourceEditorFormatterReference.h b/Components/Sources/ComponentsObjC/include/WKSourceEditorFormatterReference.h
new file mode 120000
index 00000000000..5443694ba1a
--- /dev/null
+++ b/Components/Sources/ComponentsObjC/include/WKSourceEditorFormatterReference.h
@@ -0,0 +1 @@
+../WKSourceEditorFormatterReference.h
\ No newline at end of file
diff --git a/Components/Tests/ComponentsTests/WKSourceEditorFormatterButtonActionTests.swift b/Components/Tests/ComponentsTests/WKSourceEditorFormatterButtonActionTests.swift
index cc97bb19df2..94f3420f164 100644
--- a/Components/Tests/ComponentsTests/WKSourceEditorFormatterButtonActionTests.swift
+++ b/Components/Tests/ComponentsTests/WKSourceEditorFormatterButtonActionTests.swift
@@ -163,6 +163,46 @@ final class WKSourceEditorFormatterButtonActionTests: XCTestCase {
XCTAssertEqual(mediator.textView.attributedText.string, "One Two Three Four")
}
+ func testReferenceInsertAndRemove() throws {
+ let text = "One Two Three Four"
+ mediator.textView.attributedText = NSAttributedString(string: text)
+ mediator.textView.selectedRange = NSRange(location: 4, length: 3)
+ mediator.referenceFormatter?.toggleReferenceFormatting(action: .add, in: mediator.textView)
+ XCTAssertEqual(mediator.textView.attributedText.string, "One ][Two] Three Four")
+ mediator.referenceFormatter?.toggleReferenceFormatting(action: .remove, in: mediator.textView)
+ XCTAssertEqual(mediator.textView.attributedText.string, "One Two Three Four")
+ }
+
+ func testReferenceInsertAndRemoveCursor() throws {
+ let text = "One Two Three Four"
+ mediator.textView.attributedText = NSAttributedString(string: text)
+ mediator.textView.selectedRange = NSRange(location: 4, length: 0)
+ mediator.referenceFormatter?.toggleReferenceFormatting(action: .add, in: mediator.textView)
+ XCTAssertEqual(mediator.textView.attributedText.string, "One [ ]Two Three Four")
+ mediator.referenceFormatter?.toggleReferenceFormatting(action: .remove, in: mediator.textView)
+ XCTAssertEqual(mediator.textView.attributedText.string, "One Two Three Four")
+ }
+
+ func testReferenceNamedRemoveAndInsert() throws {
+ let text = "One [Two] Three Four"
+ mediator.textView.attributedText = NSAttributedString(string: text)
+ mediator.textView.selectedRange = NSRange(location: 24, length: 3)
+ mediator.referenceFormatter?.toggleReferenceFormatting(action: .remove, in: mediator.textView)
+ XCTAssertEqual(mediator.textView.attributedText.string, "One Two Three Four")
+ mediator.referenceFormatter?.toggleReferenceFormatting(action: .add, in: mediator.textView)
+ XCTAssertEqual(mediator.textView.attributedText.string, "One [Two] Three Four")
+ }
+
+ func testReferenceNamedRemoveAndInsertCursor() throws {
+ let text = "One [Two] Three Four"
+ mediator.textView.attributedText = NSAttributedString(string: text)
+ mediator.textView.selectedRange = NSRange(location: 25, length: 0)
+ mediator.referenceFormatter?.toggleReferenceFormatting(action: .remove, in: mediator.textView)
+ XCTAssertEqual(mediator.textView.attributedText.string, "One Two Three Four")
+ mediator.referenceFormatter?.toggleReferenceFormatting(action: .add, in: mediator.textView)
+ XCTAssertEqual(mediator.textView.attributedText.string, "One [Two] Three Four")
+ }
+
func testListBulletInsertAndRemove() throws {
let text = "Test"
mediator.textView.attributedText = NSAttributedString(string: text)
diff --git a/Components/Tests/ComponentsTests/WKSourceEditorFormatterTests.swift b/Components/Tests/ComponentsTests/WKSourceEditorFormatterTests.swift
index 4664ceadaeb..5f694f68043 100644
--- a/Components/Tests/ComponentsTests/WKSourceEditorFormatterTests.swift
+++ b/Components/Tests/ComponentsTests/WKSourceEditorFormatterTests.swift
@@ -10,12 +10,13 @@ final class WKSourceEditorFormatterTests: XCTestCase {
var baseFormatter: WKSourceEditorFormatterBase!
var boldItalicsFormatter: WKSourceEditorFormatterBoldItalics!
var templateFormatter: WKSourceEditorFormatterTemplate!
+ var referenceFormatter: WKSourceEditorFormatterReference!
var listFormatter: WKSourceEditorFormatterList!
var headingFormatter: WKSourceEditorFormatterHeading!
var strikethroughFormatter: WKSourceEditorFormatterStrikethrough!
var linkFormatter: WKSourceEditorFormatterLink!
var formatters: [WKSourceEditorFormatter] {
- return [baseFormatter, templateFormatter, boldItalicsFormatter, listFormatter, headingFormatter, strikethroughFormatter, linkFormatter]
+ return [baseFormatter, templateFormatter, boldItalicsFormatter, referenceFormatter, listFormatter, headingFormatter, strikethroughFormatter, linkFormatter]
}
override func setUpWithError() throws {
@@ -42,6 +43,7 @@ final class WKSourceEditorFormatterTests: XCTestCase {
self.baseFormatter = WKSourceEditorFormatterBase(colors: colors, fonts: fonts, textAlignment: .left)
self.boldItalicsFormatter = WKSourceEditorFormatterBoldItalics(colors: colors, fonts: fonts)
self.templateFormatter = WKSourceEditorFormatterTemplate(colors: colors, fonts: fonts)
+ self.referenceFormatter = WKSourceEditorFormatterReference(colors: colors, fonts: fonts)
self.listFormatter = WKSourceEditorFormatterList(colors: colors, fonts: fonts)
self.headingFormatter = WKSourceEditorFormatterHeading(colors: colors, fonts: fonts)
self.strikethroughFormatter = WKSourceEditorFormatterStrikethrough(colors: colors, fonts: fonts)
@@ -630,7 +632,7 @@ final class WKSourceEditorFormatterTests: XCTestCase {
XCTAssertEqual(refOpeningRange.location, 0, "Incorrect ref formatting")
XCTAssertEqual(refOpeningRange.length, 5, "Incorrect ref formatting")
XCTAssertEqual(refOpeningAttributes[.font] as! UIFont, fonts.baseFont, "Incorrect ref formatting")
- XCTAssertEqual(refOpeningAttributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "Incorrect ref formatting")
+ XCTAssertEqual(refOpeningAttributes[.foregroundColor] as! UIColor, colors.greenForegroundColor, "Incorrect ref formatting")
// "{{cite web |url=https://en.wikipedia.org |title=English Wikipedia}}"
XCTAssertEqual(templateRange.location, 5, "Incorrect template formatting")
@@ -642,7 +644,7 @@ final class WKSourceEditorFormatterTests: XCTestCase {
XCTAssertEqual(refClosingRange.location, 72, "Incorrect ref formatting")
XCTAssertEqual(refClosingRange.length, 6, "Incorrect ref formatting")
XCTAssertEqual(refClosingAttributes[.font] as! UIFont, fonts.baseFont, "Incorrect ref formatting")
- XCTAssertEqual(refClosingAttributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "Incorrect ref formatting")
+ XCTAssertEqual(refClosingAttributes[.foregroundColor] as! UIColor, colors.greenForegroundColor, "Incorrect ref formatting")
}
func testHorizontalNestedTemplate() {
@@ -785,7 +787,223 @@ final class WKSourceEditorFormatterTests: XCTestCase {
XCTAssertEqual(refRange.location, 2, "Incorrect ref formatting")
XCTAssertEqual(refRange.length, 6, "Incorrect ref formatting")
XCTAssertEqual(refAttributes[.font] as! UIFont, fonts.baseFont, "Incorrect ref formatting")
- XCTAssertEqual(refAttributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "Incorrect ref formatting")
+ XCTAssertEqual(refAttributes[.foregroundColor] as! UIColor, colors.greenForegroundColor, "Incorrect ref formatting")
+ }
+
+ func testOpenAndClosingReference() {
+ let string = "Testing.[{{cite web | url=https://en.wikipedia.org}}] Testing"
+ let mutAttributedString = NSMutableAttributedString(string: string)
+
+ for formatter in formatters {
+ formatter.addSyntaxHighlighting(to: mutAttributedString, in: NSRange(location: 0, length: string.count))
+ }
+
+ var base1Range = NSRange(location: 0, length: 0)
+ let base1Attributes = mutAttributedString.attributes(at: 0, effectiveRange: &base1Range)
+
+ var refOpenRange = NSRange(location: 0, length: 0)
+ let refOpenAttributes = mutAttributedString.attributes(at: 8, effectiveRange: &refOpenRange)
+
+ var templateRange = NSRange(location: 0, length: 0)
+ let templateAttributes = mutAttributedString.attributes(at: 13, effectiveRange: &templateRange)
+
+ var refCloseRange = NSRange(location: 0, length: 0)
+ let refCloseAttributes = mutAttributedString.attributes(at: 56, effectiveRange: &refCloseRange)
+
+ var base2Range = NSRange(location: 0, length: 0)
+ let base2Attributes = mutAttributedString.attributes(at: 62, effectiveRange: &base2Range)
+
+ // "Testing."
+ XCTAssertEqual(base1Range.location, 0, "Incorrect base formatting")
+ XCTAssertEqual(base1Range.length, 8, "Incorrect base formatting")
+ XCTAssertEqual(base1Attributes[.font] as! UIFont, fonts.baseFont, "Incorrect base formatting")
+ XCTAssertEqual(base1Attributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "Incorrect base formatting")
+
+ // "["
+ XCTAssertEqual(refOpenRange.location, 8, "Incorrect template formatting")
+ XCTAssertEqual(refOpenRange.length, 5, "Incorrect template formatting")
+ XCTAssertEqual(refOpenAttributes[.font] as! UIFont, fonts.baseFont, "Incorrect template formatting")
+ XCTAssertEqual(refOpenAttributes[.foregroundColor] as! UIColor, colors.greenForegroundColor, "Incorrect template formatting")
+
+ // "{{cite web | url=https://en.wikipedia.org}}"
+ XCTAssertEqual(templateRange.location, 13, "Incorrect base formatting")
+ XCTAssertEqual(templateRange.length, 43, "Incorrect base formatting")
+ XCTAssertEqual(templateAttributes[.font] as! UIFont, fonts.baseFont, "Incorrect base formatting")
+ XCTAssertEqual(templateAttributes[.foregroundColor] as! UIColor, colors.purpleForegroundColor, "Incorrect base formatting")
+
+ // "]"
+ XCTAssertEqual(refCloseRange.location, 56, "Incorrect base formatting")
+ XCTAssertEqual(refCloseRange.length, 6, "Incorrect base formatting")
+ XCTAssertEqual(refCloseAttributes[.font] as! UIFont, fonts.baseFont, "Incorrect base formatting")
+ XCTAssertEqual(refCloseAttributes[.foregroundColor] as! UIColor, colors.greenForegroundColor, "Incorrect base formatting")
+
+ // " Testing"
+ XCTAssertEqual(base2Range.location, 62, "Incorrect base formatting")
+ XCTAssertEqual(base2Range.length, 8, "Incorrect base formatting")
+ XCTAssertEqual(base2Attributes[.font] as! UIFont, fonts.baseFont, "Incorrect base formatting")
+ XCTAssertEqual(base2Attributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "Incorrect base formatting")
+ }
+
+ func testOpenAndClosingReferenceWithName() {
+ let string = "Testing.[{{cite web | url=https://en.wikipedia.org}}] Testing"
+ let mutAttributedString = NSMutableAttributedString(string: string)
+
+ for formatter in formatters {
+ formatter.addSyntaxHighlighting(to: mutAttributedString, in: NSRange(location: 0, length: string.count))
+ }
+
+ var base1Range = NSRange(location: 0, length: 0)
+ let base1Attributes = mutAttributedString.attributes(at: 0, effectiveRange: &base1Range)
+
+ var refOpenRange = NSRange(location: 0, length: 0)
+ let refOpenAttributes = mutAttributedString.attributes(at: 8, effectiveRange: &refOpenRange)
+
+ var templateRange = NSRange(location: 0, length: 0)
+ let templateAttributes = mutAttributedString.attributes(at: 25, effectiveRange: &templateRange)
+
+ var refCloseRange = NSRange(location: 0, length: 0)
+ let refCloseAttributes = mutAttributedString.attributes(at: 68, effectiveRange: &refCloseRange)
+
+ var base2Range = NSRange(location: 0, length: 0)
+ let base2Attributes = mutAttributedString.attributes(at: 74, effectiveRange: &base2Range)
+
+ // "Testing."
+ XCTAssertEqual(base1Range.location, 0, "Incorrect base formatting")
+ XCTAssertEqual(base1Range.length, 8, "Incorrect base formatting")
+ XCTAssertEqual(base1Attributes[.font] as! UIFont, fonts.baseFont, "Incorrect base formatting")
+ XCTAssertEqual(base1Attributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "Incorrect base formatting")
+
+ // "["
+ XCTAssertEqual(refOpenRange.location, 8, "Incorrect reference formatting")
+ XCTAssertEqual(refOpenRange.length, 17, "Incorrect reference formatting")
+ XCTAssertEqual(refOpenAttributes[.font] as! UIFont, fonts.baseFont, "Incorrect reference formatting")
+ XCTAssertEqual(refOpenAttributes[.foregroundColor] as! UIColor, colors.greenForegroundColor, "Incorrect template formatting")
+
+ // "{{cite web | url=https://en.wikipedia.org}}"
+ XCTAssertEqual(templateRange.location, 25, "Incorrect template formatting")
+ XCTAssertEqual(templateRange.length, 43, "Incorrect template formatting")
+ XCTAssertEqual(templateAttributes[.font] as! UIFont, fonts.baseFont, "Incorrect template formatting")
+ XCTAssertEqual(templateAttributes[.foregroundColor] as! UIColor, colors.purpleForegroundColor, "Incorrect base formatting")
+
+ // "]"
+ XCTAssertEqual(refCloseRange.location, 68, "Incorrect reference formatting")
+ XCTAssertEqual(refCloseRange.length, 6, "Incorrect reference formatting")
+ XCTAssertEqual(refCloseAttributes[.font] as! UIFont, fonts.baseFont, "Incorrect reference formatting")
+ XCTAssertEqual(refCloseAttributes[.foregroundColor] as! UIColor, colors.greenForegroundColor, "Incorrect base formatting")
+
+ // " Testing"
+ XCTAssertEqual(base2Range.location, 74, "Incorrect base formatting")
+ XCTAssertEqual(base2Range.length, 8, "Incorrect base formatting")
+ XCTAssertEqual(base2Attributes[.font] as! UIFont, fonts.baseFont, "Incorrect base formatting")
+ XCTAssertEqual(base2Attributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "Incorrect base formatting")
+ }
+
+ func testEmptyReference() {
+ let string = "Testing. Testing"
+ let mutAttributedString = NSMutableAttributedString(string: string)
+
+ for formatter in formatters {
+ formatter.addSyntaxHighlighting(to: mutAttributedString, in: NSRange(location: 0, length: string.count))
+ }
+
+ var base1Range = NSRange(location: 0, length: 0)
+ let base1Attributes = mutAttributedString.attributes(at: 0, effectiveRange: &base1Range)
+
+ var refRange = NSRange(location: 0, length: 0)
+ let refAttributes = mutAttributedString.attributes(at: 8, effectiveRange: &refRange)
+
+ var base2Range = NSRange(location: 0, length: 0)
+ let base2Attributes = mutAttributedString.attributes(at: 27, effectiveRange: &base2Range)
+
+ // "Testing."
+ XCTAssertEqual(base1Range.location, 0, "Incorrect base formatting")
+ XCTAssertEqual(base1Range.length, 8, "Incorrect base formatting")
+ XCTAssertEqual(base1Attributes[.font] as! UIFont, fonts.baseFont, "Incorrect base formatting")
+ XCTAssertEqual(base1Attributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "Incorrect base formatting")
+
+ // ""
+ XCTAssertEqual(refRange.location, 8, "Incorrect reference formatting")
+ XCTAssertEqual(refRange.length, 19, "Incorrect reference formatting")
+ XCTAssertEqual(refAttributes[.font] as! UIFont, fonts.baseFont, "Incorrect reference formatting")
+ XCTAssertEqual(refAttributes[.foregroundColor] as! UIColor, colors.greenForegroundColor, "Incorrect reference formatting")
+
+ // " Testing"
+ XCTAssertEqual(base2Range.location, 27, "Incorrect base formatting")
+ XCTAssertEqual(base2Range.length, 8, "Incorrect base formatting")
+ XCTAssertEqual(base2Attributes[.font] as! UIFont, fonts.baseFont, "Incorrect base formatting")
+ XCTAssertEqual(base2Attributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "Incorrect base formatting")
+ }
+
+ func testOpenOnlyReference() {
+ let string = "Testing.[ Testing"
+ let mutAttributedString = NSMutableAttributedString(string: string)
+
+ for formatter in formatters {
+ formatter.addSyntaxHighlighting(to: mutAttributedString, in: NSRange(location: 0, length: string.count))
+ }
+
+ var base1Range = NSRange(location: 0, length: 0)
+ let base1Attributes = mutAttributedString.attributes(at: 0, effectiveRange: &base1Range)
+
+ var refRange = NSRange(location: 0, length: 0)
+ let refAttributes = mutAttributedString.attributes(at: 8, effectiveRange: &refRange)
+
+ var base2Range = NSRange(location: 0, length: 0)
+ let base2Attributes = mutAttributedString.attributes(at: 13, effectiveRange: &base2Range)
+
+ // "Testing."
+ XCTAssertEqual(base1Range.location, 0, "Incorrect base formatting")
+ XCTAssertEqual(base1Range.length, 8, "Incorrect base formatting")
+ XCTAssertEqual(base1Attributes[.font] as! UIFont, fonts.baseFont, "Incorrect base formatting")
+ XCTAssertEqual(base1Attributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "Incorrect base formatting")
+
+ // "]["
+ XCTAssertEqual(refRange.location, 8, "Incorrect reference formatting")
+ XCTAssertEqual(refRange.length, 5, "Incorrect reference formatting")
+ XCTAssertEqual(refAttributes[.font] as! UIFont, fonts.baseFont, "Incorrect reference formatting")
+ XCTAssertEqual(refAttributes[.foregroundColor] as! UIColor, colors.greenForegroundColor, "Incorrect reference formatting")
+
+ // " Testing"
+ XCTAssertEqual(base2Range.location, 13, "Incorrect base formatting")
+ XCTAssertEqual(base2Range.length, 8, "Incorrect base formatting")
+ XCTAssertEqual(base2Attributes[.font] as! UIFont, fonts.baseFont, "Incorrect base formatting")
+ XCTAssertEqual(base2Attributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "Incorrect base formatting")
+ }
+
+ func testCloseOnlyReference() {
+ let string = "Testing.] Testing"
+ let mutAttributedString = NSMutableAttributedString(string: string)
+
+ for formatter in formatters {
+ formatter.addSyntaxHighlighting(to: mutAttributedString, in: NSRange(location: 0, length: string.count))
+ }
+
+ var base1Range = NSRange(location: 0, length: 0)
+ let base1Attributes = mutAttributedString.attributes(at: 0, effectiveRange: &base1Range)
+
+ var refRange = NSRange(location: 0, length: 0)
+ let refAttributes = mutAttributedString.attributes(at: 8, effectiveRange: &refRange)
+
+ var base2Range = NSRange(location: 0, length: 0)
+ let base2Attributes = mutAttributedString.attributes(at: 14, effectiveRange: &base2Range)
+
+ // "Testing."
+ XCTAssertEqual(base1Range.location, 0, "Incorrect base formatting")
+ XCTAssertEqual(base1Range.length, 8, "Incorrect base formatting")
+ XCTAssertEqual(base1Attributes[.font] as! UIFont, fonts.baseFont, "Incorrect base formatting")
+ XCTAssertEqual(base1Attributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "Incorrect base formatting")
+
+ // ""
+ XCTAssertEqual(refRange.location, 8, "Incorrect reference formatting")
+ XCTAssertEqual(refRange.length, 6, "Incorrect reference formatting")
+ XCTAssertEqual(refAttributes[.font] as! UIFont, fonts.baseFont, "Incorrect reference formatting")
+ XCTAssertEqual(refAttributes[.foregroundColor] as! UIColor, colors.greenForegroundColor, "Incorrect reference formatting")
+
+ // " Testing"
+ XCTAssertEqual(base2Range.location, 14, "Incorrect base formatting")
+ XCTAssertEqual(base2Range.length, 8, "Incorrect base formatting")
+ XCTAssertEqual(base2Attributes[.font] as! UIFont, fonts.baseFont, "Incorrect base formatting")
+ XCTAssertEqual(base2Attributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "Incorrect base formatting")
}
func testListSingleBullet() {
diff --git a/Components/Tests/ComponentsTests/WKSourceEditorTextFrameworkMediatorTests.swift b/Components/Tests/ComponentsTests/WKSourceEditorTextFrameworkMediatorTests.swift
index dbbf840a4d8..d35cbb2c6ca 100644
--- a/Components/Tests/ComponentsTests/WKSourceEditorTextFrameworkMediatorTests.swift
+++ b/Components/Tests/ComponentsTests/WKSourceEditorTextFrameworkMediatorTests.swift
@@ -157,6 +157,38 @@ final class WKSourceEditorTextFrameworkMediatorTests: XCTestCase {
XCTAssertFalse(selectionStates1.isHorizontalTemplate)
}
+ func testReferenceSelectionState() throws {
+ let text = "Testing [Testing] Testing"
+ mediator.textView.attributedText = NSAttributedString(string: text)
+
+ let selectionStates = mediator.selectionState(selectedDocumentRange: NSRange(location: 13, length: 7))
+ XCTAssertTrue(selectionStates.isHorizontalReference)
+ }
+
+ func testReferenceSelectionStateCursor() throws {
+ let text = "Testing [Testing] Testing"
+ mediator.textView.attributedText = NSAttributedString(string: text)
+
+ let selectionStates = mediator.selectionState(selectedDocumentRange: NSRange(location: 16, length: 0))
+ XCTAssertTrue(selectionStates.isHorizontalReference)
+ }
+
+ func testReferenceNamedSelectionState() throws {
+ let text = "Testing [Testing] Testing"
+ mediator.textView.attributedText = NSAttributedString(string: text)
+
+ let selectionStates = mediator.selectionState(selectedDocumentRange: NSRange(location: 28, length: 7))
+ XCTAssertTrue(selectionStates.isHorizontalReference)
+ }
+
+ func testReferenceNamedSelectionStateCursor() throws {
+ let text = "Testing [Testing] Testing"
+ mediator.textView.attributedText = NSAttributedString(string: text)
+
+ let selectionStates = mediator.selectionState(selectedDocumentRange: NSRange(location: 31, length: 0))
+ XCTAssertTrue(selectionStates.isHorizontalReference)
+ }
+
func testListBulletSingleSelectionState() throws {
let text = "* Test"