From 0ccd7a56c7b0c4a7f066a16e0ddd2cf2b2ada872 Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Thu, 14 Dec 2023 14:49:28 -0600 Subject: [PATCH 01/17] Add common custom attribute key for green editor text --- Components/Sources/ComponentsObjC/WKSourceEditorFormatter.h | 3 +++ Components/Sources/ComponentsObjC/WKSourceEditorFormatter.m | 5 +++++ .../Sources/ComponentsObjC/WKSourceEditorFormatterBase.m | 5 ++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Components/Sources/ComponentsObjC/WKSourceEditorFormatter.h b/Components/Sources/ComponentsObjC/WKSourceEditorFormatter.h index f3cb213f291..9a67168c282 100644 --- a/Components/Sources/ComponentsObjC/WKSourceEditorFormatter.h +++ b/Components/Sources/ComponentsObjC/WKSourceEditorFormatter.h @@ -4,6 +4,9 @@ NS_ASSUME_NONNULL_BEGIN @interface WKSourceEditorFormatter : NSObject + +extern NSString *const WKSourceEditorCustomKeyColorGreen; + - (instancetype)initWithColors:(nonnull WKSourceEditorColors *)colors fonts:(nonnull WKSourceEditorFonts *)fonts; - (void)addSyntaxHighlightingToAttributedString:(NSMutableAttributedString *)attributedString inRange:(NSRange)range; diff --git a/Components/Sources/ComponentsObjC/WKSourceEditorFormatter.m b/Components/Sources/ComponentsObjC/WKSourceEditorFormatter.m index 5c4fb125102..63c589b2461 100644 --- a/Components/Sources/ComponentsObjC/WKSourceEditorFormatter.m +++ b/Components/Sources/ComponentsObjC/WKSourceEditorFormatter.m @@ -3,6 +3,11 @@ #import "WKSourceEditorFonts.h" @implementation WKSourceEditorFormatter + +#pragma mark - Common Custom Attributed String Keys + +NSString * const WKSourceEditorCustomKeyColorGreen = @"WKSourceEditorKeyColorGreen"; + - (nonnull instancetype)initWithColors:(nonnull WKSourceEditorColors *)colors fonts:(nonnull WKSourceEditorFonts *)fonts { self = [super init]; return self; diff --git a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterBase.m b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterBase.m index d7ad812afa3..a441ebcce07 100644 --- a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterBase.m +++ b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterBase.m @@ -29,10 +29,13 @@ - (instancetype)initWithColors:(nonnull WKSourceEditorColors *)colors fonts:(non - (void)addSyntaxHighlightingToAttributedString:(NSMutableAttributedString *)attributedString inRange:(NSRange)range { - // reset old attributes + // reset base attributes [attributedString removeAttribute:NSFontAttributeName range:range]; [attributedString removeAttribute:NSForegroundColorAttributeName range:range]; + // reset shared custom attributes + [attributedString removeAttribute:WKSourceEditorCustomKeyColorGreen range:range]; + [attributedString addAttributes:self.attributes range:range]; } From 0ff0de28e8679a46a98c6c370fab3d656027c144 Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Thu, 14 Dec 2023 15:36:16 -0600 Subject: [PATCH 02/17] Add new green color to WKSourceEditorColors --- .../WKSourceEditorTextFrameworkMediator.swift | 1 + Components/Sources/Components/Style/WKTheme.swift | 13 +++++++++---- .../Sources/ComponentsObjC/WKSourceEditorColors.h | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift index c414a31bee6..2f856b8e3e6 100644 --- a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift +++ b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift @@ -201,6 +201,7 @@ extension WKSourceEditorTextFrameworkMediator: WKSourceEditorStorageDelegate { colors.baseForegroundColor = WKAppEnvironment.current.theme.text colors.orangeForegroundColor = isSyntaxHighlightingEnabled ? WKAppEnvironment.current.theme.editorOrange : WKAppEnvironment.current.theme.text colors.purpleForegroundColor = isSyntaxHighlightingEnabled ? WKAppEnvironment.current.theme.editorPurple : WKAppEnvironment.current.theme.text + colors.greenForegroundColor = isSyntaxHighlightingEnabled ? WKAppEnvironment.current.theme.editorGreen : WKAppEnvironment.current.theme.text return colors } diff --git a/Components/Sources/Components/Style/WKTheme.swift b/Components/Sources/Components/Style/WKTheme.swift index 5be44a40c79..e5751d2af00 100644 --- a/Components/Sources/Components/Style/WKTheme.swift +++ b/Components/Sources/Components/Style/WKTheme.swift @@ -26,6 +26,7 @@ public struct WKTheme: Equatable { public let diffCompareAccent: UIColor public let editorOrange: UIColor public let editorPurple: UIColor + public let editorGreen: UIColor public static let light = WKTheme( name: "Light", @@ -50,7 +51,8 @@ public struct WKTheme: Equatable { keyboardBarSearchFieldBackground: WKColor.gray200, diffCompareAccent: WKColor.orange600, editorOrange: WKColor.orange600, - editorPurple: WKColor.purple600 + editorPurple: WKColor.purple600, + editorGreen: WKColor.green600 ) public static let sepia = WKTheme( @@ -76,7 +78,8 @@ public struct WKTheme: Equatable { keyboardBarSearchFieldBackground: WKColor.gray200, diffCompareAccent: WKColor.orange600, editorOrange: WKColor.orange600, - editorPurple: WKColor.purple600 + editorPurple: WKColor.purple600, + editorGreen: WKColor.green600 ) public static let dark = WKTheme( @@ -102,7 +105,8 @@ public struct WKTheme: Equatable { keyboardBarSearchFieldBackground: WKColor.gray650, diffCompareAccent: WKColor.orange600, editorOrange: WKColor.yellow600, - editorPurple: WKColor.red100 + editorPurple: WKColor.red100, + editorGreen: WKColor.green600 ) public static let black = WKTheme( @@ -128,7 +132,8 @@ public struct WKTheme: Equatable { keyboardBarSearchFieldBackground: WKColor.gray650, diffCompareAccent: WKColor.orange600, editorOrange: WKColor.yellow600, - editorPurple: WKColor.red100 + editorPurple: WKColor.red100, + editorGreen: WKColor.green600 ) } diff --git a/Components/Sources/ComponentsObjC/WKSourceEditorColors.h b/Components/Sources/ComponentsObjC/WKSourceEditorColors.h index b9df307bd49..9b3bf77a05f 100644 --- a/Components/Sources/ComponentsObjC/WKSourceEditorColors.h +++ b/Components/Sources/ComponentsObjC/WKSourceEditorColors.h @@ -6,6 +6,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong) UIColor *baseForegroundColor; @property (nonatomic, strong) UIColor *orangeForegroundColor; @property (nonatomic, strong) UIColor *purpleForegroundColor; +@property (nonatomic, strong) UIColor *greenForegroundColor; @end NS_ASSUME_NONNULL_END From 0cc7b1dacb329f69779923cb4ff4090c7b22e83c Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Thu, 14 Dec 2023 15:40:05 -0600 Subject: [PATCH 03/17] Add empty WKSourceEditorFormatterReference --- .../ComponentsObjC/WKSourceEditorFormatterReference.h | 9 +++++++++ .../ComponentsObjC/WKSourceEditorFormatterReference.m | 5 +++++ .../Sources/ComponentsObjC/include/ComponentsObjC.h | 1 + .../include/WKSourceEditorFormatterReference.h | 1 + 4 files changed, 16 insertions(+) create mode 100644 Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h create mode 100644 Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m create mode 120000 Components/Sources/ComponentsObjC/include/WKSourceEditorFormatterReference.h diff --git a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h new file mode 100644 index 00000000000..56e5d9ab4b0 --- /dev/null +++ b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h @@ -0,0 +1,9 @@ +#import "WKSourceEditorFormatter.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface WKSourceEditorFormatterReference : WKSourceEditorFormatter + +@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..4018b09e47c --- /dev/null +++ b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m @@ -0,0 +1,5 @@ +#import "WKSourceEditorFormatterReference.h" + +@implementation WKSourceEditorFormatterReference + +@end diff --git a/Components/Sources/ComponentsObjC/include/ComponentsObjC.h b/Components/Sources/ComponentsObjC/include/ComponentsObjC.h index 078e6dec5d6..898c7adffd5 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 "WKSourceEditorStorageDelegate.h" #endif /* Header_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 From 496f74710daaf7fe7beb08d24104a87ae2d0789a Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Thu, 14 Dec 2023 16:59:31 -0600 Subject: [PATCH 04/17] Add syntax highlighting logic to formatter --- .../WKSourceEditorFormatterReference.m | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m index 4018b09e47c..ea9e3996885 100644 --- a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m +++ b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m @@ -1,5 +1,117 @@ #import "WKSourceEditorFormatterReference.h" +#import "WKSourceEditorColors.h" + +@interface WKSourceEditorFormatterReference () +@property (nonatomic, strong) NSDictionary *refAttributes; +@property (nonatomic, strong) NSDictionary *refEmptyAttributes; + +@property (nonatomic, strong) NSRegularExpression *refOpenAndCloseRegex; +@property (nonatomic, strong) NSRegularExpression *refOpenRegex; +@property (nonatomic, strong) NSRegularExpression *refCloseRegex; +@property (nonatomic, strong) NSRegularExpression *refEmptyRegex; +@end @implementation WKSourceEditorFormatterReference +- (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] + }; + + _refOpenAndCloseRegex = [[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; +} + +#pragma mark - Overrides + +- (void)addSyntaxHighlightingToAttributedString:(nonnull NSMutableAttributedString *)attributedString inRange:(NSRange)range { + + [self.refOpenAndCloseRegex 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 (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 +} @end From 38b4eae3f45f653cf34dd1e43c218521b3f9c97c Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Thu, 14 Dec 2023 16:59:44 -0600 Subject: [PATCH 05/17] Implement formatteer in editor --- .../Source Editor/WKSourceEditorTextFrameworkMediator.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift index 2f856b8e3e6..2697e0a1553 100644 --- a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift +++ b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift @@ -35,6 +35,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? var isSyntaxHighlightingEnabled: Bool = true { didSet { @@ -103,11 +104,14 @@ final class WKSourceEditorTextFrameworkMediator: NSObject { let boldItalicsFormatter = WKSourceEditorFormatterBoldItalics(colors: colors, fonts: fonts) let templateFormatter = WKSourceEditorFormatterTemplate(colors: colors, fonts: fonts) + let referenceFormatter = WKSourceEditorFormatterReference(colors: colors, fonts: fonts) self.formatters = [WKSourceEditorFormatterBase(colors: colors, fonts: fonts, textAlignment: viewModel.textAlignment), templateFormatter, - boldItalicsFormatter] + boldItalicsFormatter, + referenceFormatter] self.boldItalicsFormatter = boldItalicsFormatter self.templateFormatter = templateFormatter + self.referenceFormatter = referenceFormatter if needsTextKit2 { if #available(iOS 16.0, *) { From ac6bf638ff44073c344939a88bc548792d27eeda Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Thu, 14 Dec 2023 17:36:43 -0600 Subject: [PATCH 06/17] Add syntax highlighting tests --- .../WKSourceEditorFormatterTests.swift | 221 +++++++++++++++++- 1 file changed, 220 insertions(+), 1 deletion(-) diff --git a/Components/Tests/ComponentsTests/WKSourceEditorFormatterTests.swift b/Components/Tests/ComponentsTests/WKSourceEditorFormatterTests.swift index 6330fe0ba7c..02a24e76b34 100644 --- a/Components/Tests/ComponentsTests/WKSourceEditorFormatterTests.swift +++ b/Components/Tests/ComponentsTests/WKSourceEditorFormatterTests.swift @@ -10,8 +10,9 @@ final class WKSourceEditorFormatterTests: XCTestCase { var baseFormatter: WKSourceEditorFormatterBase! var boldItalicsFormatter: WKSourceEditorFormatterBoldItalics! var templateFormatter: WKSourceEditorFormatterTemplate! + var referenceFormatter: WKSourceEditorFormatterReference! var formatters: [WKSourceEditorFormatter] { - return [baseFormatter, templateFormatter, boldItalicsFormatter] + return [baseFormatter, templateFormatter, boldItalicsFormatter, referenceFormatter] } override func setUpWithError() throws { @@ -21,6 +22,7 @@ final class WKSourceEditorFormatterTests: XCTestCase { self.colors.baseForegroundColor = WKTheme.light.text self.colors.orangeForegroundColor = WKTheme.light.editorOrange self.colors.purpleForegroundColor = WKTheme.light.editorPurple + self.colors.greenForegroundColor = WKTheme.light.editorGreen self.fonts = WKSourceEditorFonts() self.fonts.baseFont = WKFont.for(.body, compatibleWith: traitCollection) @@ -31,6 +33,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) } override func tearDownWithError() throws { @@ -709,4 +712,220 @@ final class WKSourceEditorFormatterTests: XCTestCase { XCTAssertEqual(refAttributes[.font] as! UIFont, fonts.baseFont, "Incorrect ref formatting") XCTAssertEqual(refAttributes[.foregroundColor] as! UIColor, colors.baseForegroundColor, "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") + } } From eaac9a7b69fa288718c389652516afb01d9e7ccb Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Fri, 15 Dec 2023 08:19:10 -0600 Subject: [PATCH 07/17] Allow reference formatter to detect if range contains custom content key --- .../WKSourceEditorFormatterReference.h | 2 +- .../WKSourceEditorFormatterReference.m | 58 ++++++++++++++++++- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h index 56e5d9ab4b0..af03eb7ef19 100644 --- a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h +++ b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h @@ -3,7 +3,7 @@ NS_ASSUME_NONNULL_BEGIN @interface WKSourceEditorFormatterReference : WKSourceEditorFormatter - +- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isReferenceInRange:(NSRange)range; @end NS_ASSUME_NONNULL_END diff --git a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m index ea9e3996885..2233791b433 100644 --- a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m +++ b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m @@ -4,6 +4,7 @@ @interface WKSourceEditorFormatterReference () @property (nonatomic, strong) NSDictionary *refAttributes; @property (nonatomic, strong) NSDictionary *refEmptyAttributes; +@property (nonatomic, strong) NSDictionary *refContentAttributes; @property (nonatomic, strong) NSRegularExpression *refOpenAndCloseRegex; @property (nonatomic, strong) NSRegularExpression *refOpenRegex; @@ -12,6 +13,13 @@ @interface WKSourceEditorFormatterReference () @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) { @@ -25,6 +33,10 @@ - (instancetype)initWithColors:(WKSourceEditorColors *)colors fonts:(WKSourceEdi WKSourceEditorCustomKeyColorGreen: [NSNumber numberWithBool:YES] }; + _refContentAttributes = @{ + WKSourceEditorCustomKeyContentReference: [NSNumber numberWithBool:YES] + }; + _refOpenAndCloseRegex = [[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]; @@ -34,10 +46,11 @@ - (instancetype)initWithColors:(WKSourceEditorColors *)colors fonts:(WKSourceEdi return self; } -#pragma mark - Overrides - - (void)addSyntaxHighlightingToAttributedString:(nonnull NSMutableAttributedString *)attributedString inRange:(NSRange)range { + // Reset + [attributedString removeAttribute:WKSourceEditorCustomKeyContentReference range:range]; + [self.refOpenAndCloseRegex enumerateMatchesInString:attributedString.string options:0 range:range @@ -51,6 +64,10 @@ - (void)addSyntaxHighlightingToAttributedString:(nonnull NSMutableAttributedStri [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]; } @@ -114,4 +131,41 @@ - (void)updateColors:(WKSourceEditorColors *)colors inAttributedString:(NSMutabl - (void)updateFonts:(WKSourceEditorFonts *)fonts inAttributedString:(NSMutableAttributedString *)attributedString inRange:(NSRange)range { // No special font handling needed for references } + +#pragma mark - Public + +- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isReferenceInRange:(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 { + [attributedString enumerateAttributesInRange:range options:nil usingBlock:^(NSDictionary * _Nonnull attrs, NSRange loopRange, BOOL * _Nonnull stop) { + if ((attrs[WKSourceEditorCustomKeyContentReference] != nil) && + (loopRange.location == range.location && loopRange.length == range.length)) { + isContentKey = YES; + stop = YES; + } + }]; + } + + return isContentKey; +} + @end From be8be1559a7969b12551093683d4f2ed43a8f923 Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Fri, 15 Dec 2023 08:26:27 -0600 Subject: [PATCH 08/17] Add reference properties to WKSourceEditorSelectionState, rename to horizontal --- .../WKSourceEditorTextFrameworkMediator.swift | 14 +++++++++----- .../WKSourceEditorFormatterReference.h | 2 +- .../WKSourceEditorFormatterReference.m | 8 ++++---- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift index 2697e0a1553..bdbe5d066e4 100644 --- a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift +++ b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorTextFrameworkMediator.swift @@ -17,11 +17,13 @@ fileprivate var needsTextKit2: Bool { let isBold: Bool let isItalics: Bool let isHorizontalTemplate: Bool + let isHorizontalReference: Bool - init(isBold: Bool, isItalics: Bool, isHorizontalTemplate: Bool) { + init(isBold: Bool, isItalics: Bool, isHorizontalTemplate: Bool, isHorizontalReference: Bool) { self.isBold = isBold self.isItalics = isItalics self.isHorizontalTemplate = isHorizontalTemplate + self.isHorizontalReference = isHorizontalReference } } @@ -151,24 +153,26 @@ final class WKSourceEditorTextFrameworkMediator: NSObject { if needsTextKit2 { guard let textKit2Data = textkit2SelectionData(selectedDocumentRange: selectedDocumentRange) else { - return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false) + return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isHorizontalReference: 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 - return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate) + return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isHorizontalReference: isHorizontalReference) } else { guard let textKit1Storage else { - return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false) + return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isHorizontalReference: 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 - return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate) + return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isHorizontalReference: isHorizontalReference) } } diff --git a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h index af03eb7ef19..a3296aedfe2 100644 --- a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h +++ b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.h @@ -3,7 +3,7 @@ NS_ASSUME_NONNULL_BEGIN @interface WKSourceEditorFormatterReference : WKSourceEditorFormatter -- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isReferenceInRange:(NSRange)range; +- (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 index 2233791b433..ad6c18b34c5 100644 --- a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m +++ b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m @@ -6,7 +6,7 @@ @interface WKSourceEditorFormatterReference () @property (nonatomic, strong) NSDictionary *refEmptyAttributes; @property (nonatomic, strong) NSDictionary *refContentAttributes; -@property (nonatomic, strong) NSRegularExpression *refOpenAndCloseRegex; +@property (nonatomic, strong) NSRegularExpression *refHorizontalRegex; @property (nonatomic, strong) NSRegularExpression *refOpenRegex; @property (nonatomic, strong) NSRegularExpression *refCloseRegex; @property (nonatomic, strong) NSRegularExpression *refEmptyRegex; @@ -37,7 +37,7 @@ - (instancetype)initWithColors:(WKSourceEditorColors *)colors fonts:(WKSourceEdi WKSourceEditorCustomKeyContentReference: [NSNumber numberWithBool:YES] }; - _refOpenAndCloseRegex = [[NSRegularExpression alloc] initWithPattern:@"(]+?)?>)(.*?)(<\\/ref>)" options:0 error:nil]; + _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]; @@ -51,7 +51,7 @@ - (void)addSyntaxHighlightingToAttributedString:(nonnull NSMutableAttributedStri // Reset [attributedString removeAttribute:WKSourceEditorCustomKeyContentReference range:range]; - [self.refOpenAndCloseRegex enumerateMatchesInString:attributedString.string + [self.refHorizontalRegex enumerateMatchesInString:attributedString.string options:0 range:range usingBlock:^(NSTextCheckingResult *_Nullable result, NSMatchingFlags flags, BOOL *_Nonnull stop) { @@ -134,7 +134,7 @@ - (void)updateFonts:(WKSourceEditorFonts *)fonts inAttributedString:(NSMutableAt #pragma mark - Public -- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isReferenceInRange:(NSRange)range { +- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isHorizontalReferenceInRange:(NSRange)range { __block BOOL isContentKey = NO; if (range.length == 0) { From 9a267465b3ee32eff3a373f6253e741bfc56aacd Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Fri, 15 Dec 2023 08:31:59 -0600 Subject: [PATCH 09/17] Rename citationButton > referenceButton in toolbars --- .../Expanding/WKEditorToolbarExpandingView.swift | 10 +++++----- .../Expanding/WKEditorToolbarExpandingView.xib | 9 ++++----- .../Highlight/WKEditorToolbarHighlightView.swift | 10 +++++----- .../Highlight/WKEditorToolbarHighlightView.xib | 7 +++---- .../WKEditorToolbarPlainView.swift | 10 +++++----- .../WKEditorToolbarPlainView.xib | 7 +++---- 6 files changed, 25 insertions(+), 28 deletions(-) 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 bbf183ad600..06fadb2bc39 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 @@ -41,7 +41,7 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView { @IBOutlet private weak var formatTextButton: WKEditorToolbarButton! @IBOutlet private weak var formatHeadingButton: 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 mediaButton: WKEditorToolbarButton! @@ -87,9 +87,9 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView { formatHeadingButton.accessibilityIdentifier = WKSourceEditorAccessibilityIdentifiers.current?.formatHeadingButton formatHeadingButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current.accessibilityLabelButtonFormatHeading - 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) @@ -200,7 +200,7 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView { delegate?.toolbarExpandingViewDidTapFormatHeading(toolbarView: self) } - @objc private func tappedCitation() { + @objc private func tappedReference() { } @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 a303c68443c..12b92031740 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 @@ -1,9 +1,8 @@ - + - - + @@ -271,7 +270,6 @@ - @@ -284,8 +282,9 @@ - + + 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 7003ab32d0c..9e7e0be4ba9 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 @@ -17,7 +17,7 @@ class WKEditorToolbarHighlightView: WKEditorToolbarView { @IBOutlet private weak var boldButton: WKEditorToolbarButton! @IBOutlet private weak var italicsButton: WKEditorToolbarButton! @IBOutlet private weak var formatHeadingButton: 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 clearMarkupButton: WKEditorToolbarButton! @@ -46,9 +46,9 @@ class WKEditorToolbarHighlightView: WKEditorToolbarView { formatHeadingButton.accessibilityIdentifier = WKSourceEditorAccessibilityIdentifiers.current?.formatHeadingButton formatHeadingButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current?.accessibilityLabelButtonFormatHeading - 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) @@ -96,7 +96,7 @@ class WKEditorToolbarHighlightView: WKEditorToolbarView { delegate?.toolbarHighlightViewDidTapFormatHeading(toolbarView: self) } - @objc private func tappedCitation() { + @objc private func tappedReference() { } @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 ece76adee38..5e3510c5e49 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 @@ -1,9 +1,8 @@ - + - - + @@ -98,11 +97,11 @@ - + diff --git a/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.swift b/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.swift index 8f9a0be668d..f005ff1e69d 100644 --- a/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.swift +++ b/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/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) @@ -67,7 +67,7 @@ class WKEditorToolbarPlainView: WKEditorToolbarView { delegate?.didTapItalics(isSelected: italicsButton.isSelected) } - @objc private func tappedCitation() { + @objc private func tappedReference() { } @objc private func tappedTemplate() { diff --git a/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.xib b/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.xib index 0e700570dac..61d1e9b3fb0 100644 --- a/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.xib +++ b/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.xib @@ -1,9 +1,8 @@ - + - - + @@ -54,10 +53,10 @@ - + From bfb1e465061970420230a417ebc641935752720f Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Fri, 15 Dec 2023 08:34:58 -0600 Subject: [PATCH 10/17] Add delegate callbacks --- .../Expanding/WKEditorToolbarExpandingView.swift | 2 ++ .../Highlight/WKEditorToolbarHighlightView.swift | 2 ++ .../WKEditorToolbarPlainView.swift | 1 + .../Input Views/WKEditorInputViewController.swift | 1 + .../Source Editor/WKSourceEditorViewController.swift | 12 ++++++++++++ 5 files changed, 18 insertions(+) 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 06fadb2bc39..e27cb10965f 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 @@ -5,6 +5,7 @@ protocol WKEditorToolbarExpandingViewDelegate: AnyObject { func toolbarExpandingViewDidTapFormatText(toolbarView: WKEditorToolbarExpandingView) func toolbarExpandingViewDidTapFormatHeading(toolbarView: WKEditorToolbarExpandingView) func toolbarExpandingViewDidTapTemplate(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool) + func toolbarExpandingViewDidTapReference(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool) } class WKEditorToolbarExpandingView: WKEditorToolbarView { @@ -201,6 +202,7 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView { } @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/Highlight/WKEditorToolbarHighlightView.swift b/Components/Sources/Components/Components/Editors/Common Views/Input Accessory Views/Highlight/WKEditorToolbarHighlightView.swift index 9e7e0be4ba9..52cc9f48845 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 toolbarHighlightViewDidTapShowMore(toolbarView: WKEditorToolbarHighlightView) func toolbarHighlightViewDidTapFormatHeading(toolbarView: WKEditorToolbarHighlightView) } @@ -97,6 +98,7 @@ class WKEditorToolbarHighlightView: WKEditorToolbarView { } @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 Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.swift b/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.swift index f005ff1e69d..f2b20695192 100644 --- a/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.swift +++ b/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.swift @@ -68,6 +68,7 @@ class WKEditorToolbarPlainView: WKEditorToolbarView { } @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/WKEditorInputViewController.swift b/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorInputViewController.swift index a2ae309b88f..7c37b07bfe9 100644 --- a/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorInputViewController.swift +++ b/Components/Sources/Components/Components/Editors/Common Views/Input Views/WKEditorInputViewController.swift @@ -6,6 +6,7 @@ protocol WKEditorInputViewDelegate: AnyObject { func didTapBold(isSelected: Bool) func didTapItalics(isSelected: Bool) func didTapTemplate(isSelected: Bool) + func didTapReference(isSelected: Bool) } class WKEditorInputViewController: WKComponentViewController { diff --git a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorViewController.swift b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorViewController.swift index 5a5d7447287..8c6aa3a7cac 100644 --- a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorViewController.swift +++ b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorViewController.swift @@ -310,6 +310,10 @@ extension WKSourceEditorViewController: WKEditorToolbarExpandingViewDelegate { let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add textFrameworkMediator.templateFormatter?.toggleTemplateFormatting(action: action, in: textView) } + + func toolbarExpandingViewDidTapReference(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool) { + + } } // MARK: - WKEditorToolbarHighlightViewDelegate @@ -331,6 +335,9 @@ extension WKSourceEditorViewController: WKEditorToolbarHighlightViewDelegate { textFrameworkMediator.templateFormatter?.toggleTemplateFormatting(action: action, in: textView) } + func toolbarHighlightViewDidTapReference(toolbarView: WKEditorToolbarHighlightView, isSelected: Bool) { + } + func toolbarHighlightViewDidTapShowMore(toolbarView: WKEditorToolbarHighlightView) { inputViewType = .main postUpdateButtonSelectionStatesNotification(withDelay: true) @@ -344,6 +351,7 @@ extension WKSourceEditorViewController: WKEditorToolbarHighlightViewDelegate { // MARK: - WKEditorInputViewDelegate extension WKSourceEditorViewController: WKEditorInputViewDelegate { + func didTapBold(isSelected: Bool) { let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add textFrameworkMediator.boldItalicsFormatter?.toggleBoldFormatting(action: action, in: textView) @@ -359,6 +367,10 @@ extension WKSourceEditorViewController: WKEditorInputViewDelegate { textFrameworkMediator.templateFormatter?.toggleTemplateFormatting(action: action, in: textView) } + func didTapReference(isSelected: Bool) { + + } + func didTapClose() { inputViewType = nil let isRangeSelected = textView.selectedRange.length > 0 From 6b4529a69eee079d537cdbcf2c2d916cabc1838f Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Fri, 15 Dec 2023 08:37:01 -0600 Subject: [PATCH 11/17] Apply reference selection state to toolbars --- .../Expanding/WKEditorToolbarExpandingView.swift | 1 + .../Highlight/WKEditorToolbarHighlightView.swift | 1 + .../Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.swift | 1 + 3 files changed, 3 insertions(+) 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 e27cb10965f..8d499b372d7 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 @@ -151,6 +151,7 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView { } templateButton.isSelected = selectionState.isHorizontalTemplate + referenceButton.isSelected = selectionState.isHorizontalReference cursorRightButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current.accessibilityLabelButtonCursorRight } 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 52cc9f48845..792dec3631a 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 @@ -81,6 +81,7 @@ class WKEditorToolbarHighlightView: WKEditorToolbarView { boldButton.isSelected = selectionState.isBold italicsButton.isSelected = selectionState.isItalics templateButton.isSelected = selectionState.isHorizontalTemplate + referenceButton.isSelected = selectionState.isHorizontalReference } // MARK: - Button Actions diff --git a/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.swift b/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.swift index f2b20695192..b1a8e02df6b 100644 --- a/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.swift +++ b/Components/Sources/Components/Components/Editors/Common Views/Input Views/Main/Plain Toolbar Table Item/WKEditorToolbarPlainView.swift @@ -55,6 +55,7 @@ class WKEditorToolbarPlainView: WKEditorToolbarView { boldButton.isSelected = selectionState.isBold italicsButton.isSelected = selectionState.isItalics templateButton.isSelected = selectionState.isHorizontalTemplate + referenceButton.isSelected = selectionState.isHorizontalReference } // MARK: Button Actions From 7ac0a3f30359dc5575b6704bdb60b96fc9b72074 Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Fri, 15 Dec 2023 08:41:16 -0600 Subject: [PATCH 12/17] Add reference formatter extension to toggle formatting --- ...WKSourceEditorBoldItalicsReference+ButtonActions.swift | 8 ++++++++ .../Source Editor/WKSourceEditorViewController.swift | 8 ++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorBoldItalicsReference+ButtonActions.swift diff --git a/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorBoldItalicsReference+ButtonActions.swift b/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorBoldItalicsReference+ButtonActions.swift new file mode 100644 index 00000000000..7be8fdbd4b2 --- /dev/null +++ b/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorBoldItalicsReference+ButtonActions.swift @@ -0,0 +1,8 @@ +import Foundation +import ComponentsObjC + +extension WKSourceEditorFormatterReference { + func toggleReferenceFormatting(action: WKSourceEditorFormatterButtonAction, in textView: UITextView) { + toggleFormatting(startingFormattingString: "", endingFormattingString: "", action: action, in: textView) + } +} diff --git a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorViewController.swift b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorViewController.swift index 8c6aa3a7cac..9b5fbd9a51a 100644 --- a/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorViewController.swift +++ b/Components/Sources/Components/Components/Editors/Source Editor/WKSourceEditorViewController.swift @@ -312,7 +312,8 @@ extension WKSourceEditorViewController: WKEditorToolbarExpandingViewDelegate { } func toolbarExpandingViewDidTapReference(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool) { - + let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add + textFrameworkMediator.referenceFormatter?.toggleReferenceFormatting(action: action, in: textView) } } @@ -336,6 +337,8 @@ extension WKSourceEditorViewController: WKEditorToolbarHighlightViewDelegate { } func toolbarHighlightViewDidTapReference(toolbarView: WKEditorToolbarHighlightView, isSelected: Bool) { + let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add + textFrameworkMediator.referenceFormatter?.toggleReferenceFormatting(action: action, in: textView) } func toolbarHighlightViewDidTapShowMore(toolbarView: WKEditorToolbarHighlightView) { @@ -368,7 +371,8 @@ extension WKSourceEditorViewController: WKEditorInputViewDelegate { } func didTapReference(isSelected: Bool) { - + let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add + textFrameworkMediator.referenceFormatter?.toggleReferenceFormatting(action: action, in: textView) } func didTapClose() { From d0201d5ff680a05f265db025c53cc4e4fe407c7e Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Fri, 15 Dec 2023 08:50:16 -0600 Subject: [PATCH 13/17] Fix bug --- .../WKSourceEditorFormatterReference.m | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m index ad6c18b34c5..f427197c3b4 100644 --- a/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m +++ b/Components/Sources/ComponentsObjC/WKSourceEditorFormatterReference.m @@ -156,13 +156,21 @@ - (BOOL)attributedString:(NSMutableAttributedString *)attributedString isHorizon } } 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) && - (loopRange.location == range.location && loopRange.length == range.length)) { - isContentKey = YES; - stop = YES; + 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; From 8d73c22e17d56492cb2799b5123ce78ac6646965 Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Fri, 15 Dec 2023 10:09:06 -0600 Subject: [PATCH 14/17] Allow ability to toggle starting formatting string with wildcard --- ...KSourceEditorFormatter+ButtonActions.swift | 87 +++++++++++++++++-- ...SourceEditorReference+ButtonActions.swift} | 2 +- 2 files changed, 81 insertions(+), 8 deletions(-) rename Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/{WKSourceEditorBoldItalicsReference+ButtonActions.swift => WKSourceEditorReference+ButtonActions.swift} (54%) 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 e0e70e9d2f6..8c464dea60c 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,25 +14,98 @@ 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) { switch action { case .remove: - expandSelectedRangeUpToNearestFormattingStrings(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView) - if selectedRangeIsSurroundedByFormattingStrings(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView) { - removeSurroundingFormattingStringsFromSelectedRange(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView) + var resolvedStartingFormattingString = startingFormattingString + if let wildcardStartingFormattingString { + resolvedStartingFormattingString = getModifiedStartingFormattingStringForSingleWildcard(startingFormattingString: wildcardStartingFormattingString, textView: textView) + } + + expandSelectedRangeUpToNearestFormattingStrings(startingFormattingString: resolvedStartingFormattingString, endingFormattingString: endingFormattingString, in: textView) + + if selectedRangeIsSurroundedByFormattingStrings(startingFormattingString: resolvedStartingFormattingString, endingFormattingString: endingFormattingString, in: textView) { + removeSurroundingFormattingStringsFromSelectedRange(startingFormattingString: resolvedStartingFormattingString, endingFormattingString: endingFormattingString, in: textView) } case .add: - if textView.selectedRange.length == 0 && - selectedRangeIsSurroundedByFormattingStrings(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView) { - removeSurroundingFormattingStringsFromSelectedRange(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView) + if textView.selectedRange.length == 0 { + + var resolvedStartingFormattingString = startingFormattingString + if let wildcardStartingFormattingString { + resolvedStartingFormattingString = getModifiedStartingFormattingStringForSingleWildcard(startingFormattingString: wildcardStartingFormattingString, textView: textView) + } + + if selectedRangeIsSurroundedByFormattingStrings(startingFormattingString: resolvedStartingFormattingString, endingFormattingString: endingFormattingString, in: textView) { + removeSurroundingFormattingStringsFromSelectedRange(startingFormattingString: resolvedStartingFormattingString, endingFormattingString: endingFormattingString, in: textView) + } else { + addStringFormattingCharacters(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView) + } } else { addStringFormattingCharacters(startingFormattingString: startingFormattingString, endingFormattingString: endingFormattingString, in: textView) } } } + + /// 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 private func expandSelectedRangeUpToNearestFormattingStrings(startingFormattingString: String, endingFormattingString: String, in textView: UITextView) { diff --git a/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorBoldItalicsReference+ButtonActions.swift b/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorReference+ButtonActions.swift similarity index 54% rename from Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorBoldItalicsReference+ButtonActions.swift rename to Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorReference+ButtonActions.swift index 7be8fdbd4b2..baf19113136 100644 --- a/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorBoldItalicsReference+ButtonActions.swift +++ b/Components/Sources/Components/Components/Editors/Source Editor/Formatter Extensions/WKSourceEditorReference+ButtonActions.swift @@ -3,6 +3,6 @@ import ComponentsObjC extension WKSourceEditorFormatterReference { func toggleReferenceFormatting(action: WKSourceEditorFormatterButtonAction, in textView: UITextView) { - toggleFormatting(startingFormattingString: "", endingFormattingString: "", action: action, in: textView) + toggleFormatting(startingFormattingString: "", wildcardStartingFormattingString: "", endingFormattingString: "", action: action, in: textView) } } From 8d2ea94821db9939e1a07b4f0a77c9d48bb768f4 Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Fri, 15 Dec 2023 11:09:13 -0600 Subject: [PATCH 15/17] Add selection state and button action tests --- ...urceEditorFormatterButtonActionTests.swift | 40 +++++++++++++++++++ ...urceEditorTextFrameworkMediatorTests.swift | 32 +++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/Components/Tests/ComponentsTests/WKSourceEditorFormatterButtonActionTests.swift b/Components/Tests/ComponentsTests/WKSourceEditorFormatterButtonActionTests.swift index ee99fe49cd6..97c3357d453 100644 --- a/Components/Tests/ComponentsTests/WKSourceEditorFormatterButtonActionTests.swift +++ b/Components/Tests/ComponentsTests/WKSourceEditorFormatterButtonActionTests.swift @@ -122,4 +122,44 @@ final class WKSourceEditorFormatterButtonActionTests: XCTestCase { mediator.templateFormatter?.toggleTemplateFormatting(action: .remove, in: mediator.textView) 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") + } } diff --git a/Components/Tests/ComponentsTests/WKSourceEditorTextFrameworkMediatorTests.swift b/Components/Tests/ComponentsTests/WKSourceEditorTextFrameworkMediatorTests.swift index 5f01b4b4c71..88ffe459195 100644 --- a/Components/Tests/ComponentsTests/WKSourceEditorTextFrameworkMediatorTests.swift +++ b/Components/Tests/ComponentsTests/WKSourceEditorTextFrameworkMediatorTests.swift @@ -121,4 +121,36 @@ final class WKSourceEditorTextFrameworkMediatorTests: XCTestCase { let selectionStates1 = mediator.selectionState(selectedDocumentRange: NSRange(location: 1, length: 0)) 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) + } } From 11972063f157410ce6247481cd9cc5447b30e3be Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Fri, 15 Dec 2023 13:00:53 -0600 Subject: [PATCH 16/17] Fix tests --- .../ComponentsTests/WKSourceEditorFormatterTests.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Components/Tests/ComponentsTests/WKSourceEditorFormatterTests.swift b/Components/Tests/ComponentsTests/WKSourceEditorFormatterTests.swift index 02a24e76b34..fc950f56b4a 100644 --- a/Components/Tests/ComponentsTests/WKSourceEditorFormatterTests.swift +++ b/Components/Tests/ComponentsTests/WKSourceEditorFormatterTests.swift @@ -618,7 +618,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") @@ -630,7 +630,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 testVerticalStartTemplate() { @@ -710,7 +710,7 @@ 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() { From 7653f6c329fb167dfa04202ad44f04b510460315 Mon Sep 17 00:00:00 2001 From: Toni Sevener Date: Tue, 9 Jan 2024 16:51:04 -0600 Subject: [PATCH 17/17] Bug fixes after merge --- .../Editors/Common Views/Input Views/WKEditorInputView.swift | 1 + 1 file changed, 1 insertion(+) 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 9e6fead4fc2..f0c9f75cffc 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 didTapStrikethrough(isSelected: Bool) }