Skip to content

Commit

Permalink
Merge branch 'main' into native-editor-reference
Browse files Browse the repository at this point in the history
  • Loading branch information
tonisevener committed Jan 8, 2024
2 parents 1197206 + 3371bb9 commit 7040dc0
Show file tree
Hide file tree
Showing 61 changed files with 1,445 additions and 135 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,21 @@ class WKEditorToolbarGroupedCell: UITableViewCell {

// MARK: - Properties

private lazy var componentView: UIView = {
let view = UINib(nibName: String(describing: WKEditorToolbarGroupedView.self), bundle: Bundle.module).instantiate(withOwner: nil).first as! UIView
private lazy var componentView: WKEditorToolbarGroupedView = {
let view = UINib(nibName: String(describing: WKEditorToolbarGroupedView.self), bundle: Bundle.module).instantiate(withOwner: nil).first as! WKEditorToolbarGroupedView

return view
}()

var delegate: WKEditorInputViewDelegate? {
get {
return componentView.delegate
}
set {
componentView.delegate = newValue
}
}

// MARK: - Lifecycle

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class WKEditorToolbarGroupedView: WKEditorToolbarView {
@IBOutlet private weak var underlineButton: WKEditorToolbarButton!
@IBOutlet private weak var strikethroughButton: WKEditorToolbarButton!

weak var delegate: WKEditorInputViewDelegate?

// MARK: - Lifecycle

override func awakeFromNib() {
Expand Down Expand Up @@ -49,6 +51,18 @@ class WKEditorToolbarGroupedView: WKEditorToolbarView {
strikethroughButton.setImage(WKSFSymbolIcon.for(symbol: .strikethrough), for: .normal)
strikethroughButton.addTarget(self, action: #selector(tappedStrikethrough), for: .touchUpInside)
strikethroughButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current?.accessibilityLabelButtonStrikethrough

NotificationCenter.default.addObserver(self, selector: #selector(updateButtonSelectionState(_:)), name: Notification.WKSourceEditorSelectionState, object: nil)
}

// MARK: - Notifications

@objc private func updateButtonSelectionState(_ notification: NSNotification) {
guard let selectionState = notification.userInfo?[Notification.WKSourceEditorSelectionStateKey] as? WKSourceEditorSelectionState else {
return
}

strikethroughButton.isSelected = selectionState.isStrikethrough
}

// MARK: - Button Actions
Expand All @@ -75,6 +89,7 @@ class WKEditorToolbarGroupedView: WKEditorToolbarView {
}

@objc private func tappedStrikethrough() {
delegate?.didTapStrikethrough(isSelected: strikethroughButton.isSelected)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ extension WKEditorInputMainViewController: UITableViewDataSource {
cell.selectionStyle = .none
case 1:
cell = tableView.dequeueReusableCell(withIdentifier: groupedReuseIdentifier, for: indexPath)

if let groupedCell = cell as? WKEditorToolbarGroupedCell {
groupedCell.delegate = delegate
}

cell.selectionStyle = .none
case 2:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ protocol WKEditorInputViewDelegate: AnyObject {
func didTapItalics(isSelected: Bool)
func didTapTemplate(isSelected: Bool)
func didTapReference(isSelected: Bool)
func didTapStrikethrough(isSelected: Bool)
}

class WKEditorInputViewController: WKComponentViewController {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Foundation
import ComponentsObjC

extension WKSourceEditorFormatterStrikethrough {
func toggleStrikethroughFormatting(action: WKSourceEditorFormatterButtonAction, in textView: UITextView) {
toggleFormatting(startingFormattingString: "<s>", endingFormattingString: "</s>", action: action, in: textView)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ fileprivate var needsTextKit2: Bool {
let isItalics: Bool
let isHorizontalTemplate: Bool
let isHorizontalReference: Bool
let isStrikethrough: Bool

init(isBold: Bool, isItalics: Bool, isHorizontalTemplate: Bool, isHorizontalReference: Bool) {
init(isBold: Bool, isItalics: Bool, isHorizontalTemplate: Bool, isHorizontalReference: Bool, isStrikethrough: Bool) {
self.isBold = isBold
self.isItalics = isItalics
self.isHorizontalTemplate = isHorizontalTemplate
self.isHorizontalReference = isHorizontalReference
self.isStrikethrough = isStrikethrough
}
}

Expand All @@ -38,6 +40,7 @@ final class WKSourceEditorTextFrameworkMediator: NSObject {
private(set) var boldItalicsFormatter: WKSourceEditorFormatterBoldItalics?
private(set) var templateFormatter: WKSourceEditorFormatterTemplate?
private(set) var referenceFormatter: WKSourceEditorFormatterReference?
private(set) var strikethroughFormatter: WKSourceEditorFormatterStrikethrough?

var isSyntaxHighlightingEnabled: Bool = true {
didSet {
Expand Down Expand Up @@ -107,14 +110,17 @@ 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)
let strikethroughFormatter = WKSourceEditorFormatterStrikethrough(colors: colors, fonts: fonts)
self.formatters = [WKSourceEditorFormatterBase(colors: colors, fonts: fonts, textAlignment: viewModel.textAlignment),
templateFormatter,
boldItalicsFormatter,
referenceFormatter]
referenceFormatter,
strikethroughFormatter]
self.boldItalicsFormatter = boldItalicsFormatter
self.templateFormatter = templateFormatter
self.referenceFormatter = referenceFormatter

self.strikethroughFormatter = strikethroughFormatter

if needsTextKit2 {
if #available(iOS 16.0, *) {
let textContentManager = textView.textLayoutManager?.textContentManager
Expand Down Expand Up @@ -153,26 +159,28 @@ final class WKSourceEditorTextFrameworkMediator: NSObject {

if needsTextKit2 {
guard let textKit2Data = textkit2SelectionData(selectedDocumentRange: selectedDocumentRange) else {
return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isHorizontalReference: false)
return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isHorizontalReference: false, isStrikethrough: 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 isStrikethrough = strikethroughFormatter?.attributedString(textKit2Data.paragraphAttributedString, isStrikethroughIn: textKit2Data.paragraphSelectedRange) ?? false

return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isHorizontalReference: isHorizontalReference)
return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isHorizontalReference: isHorizontalReference, isStrikethrough: isStrikethrough)
} else {
guard let textKit1Storage else {
return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isHorizontalReference: false)
return WKSourceEditorSelectionState(isBold: false, isItalics: false, isHorizontalTemplate: false, isHorizontalReference: false, isStrikethrough: 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 isStrikethrough = strikethroughFormatter?.attributedString(textKit1Storage, isStrikethroughIn: selectedDocumentRange) ?? false

return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isHorizontalReference: isHorizontalReference)
return WKSourceEditorSelectionState(isBold: isBold, isItalics: isItalics, isHorizontalTemplate: isHorizontalTemplate, isHorizontalReference: isHorizontalReference, isStrikethrough: isStrikethrough)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,11 @@ extension WKSourceEditorViewController: WKEditorInputViewDelegate {
textFrameworkMediator.referenceFormatter?.toggleReferenceFormatting(action: action, in: textView)
}

func didTapStrikethrough(isSelected: Bool) {
let action: WKSourceEditorFormatterButtonAction = isSelected ? .remove : .add
textFrameworkMediator.strikethroughFormatter?.toggleStrikethroughFormatting(action: action, in: textView)
}

func didTapClose() {
inputViewType = nil
let isRangeSelected = textView.selectedRange.length > 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,54 +278,56 @@ - (void)updateFonts:(WKSourceEditorFonts *)fonts inAttributedString:(NSMutableAt
#pragma mark - Public

- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isBoldInRange:(NSRange)range {
__block BOOL isBold = NO;
if (range.length == 0) {

if (attributedString.length > range.location) {
NSDictionary<NSAttributedStringKey,id> *attrs = [attributedString attributesAtIndex:range.location effectiveRange:nil];

if (attrs[WKSourceEditorCustomKeyFontBoldItalics] != nil || attrs[WKSourceEditorCustomKeyFontBold] != nil) {
isBold = YES;
}
}

} else {
[attributedString enumerateAttributesInRange:range options:nil usingBlock:^(NSDictionary<NSAttributedStringKey,id> * _Nonnull attrs, NSRange loopRange, BOOL * _Nonnull stop) {
if ((attrs[WKSourceEditorCustomKeyFontBoldItalics] != nil || attrs[WKSourceEditorCustomKeyFontBold] != nil) &&
(loopRange.location == range.location && loopRange.length == range.length)) {
isBold = YES;
stop = YES;
}
}];
}


return isBold;
return [self attributedString:attributedString isFormattedInRange:range formattingKey:WKSourceEditorCustomKeyFontBold];
}

- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isItalicsInRange:(NSRange)range {
__block BOOL isItalics = NO;
return [self attributedString:attributedString isFormattedInRange:range formattingKey:WKSourceEditorCustomKeyFontItalics];
}

#pragma mark - Private

- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isFormattedInRange:(NSRange)range formattingKey: (NSString *)formattingKey {
__block BOOL isFormatted = NO;

if (range.length == 0) {

if (attributedString.length > range.location) {
NSDictionary<NSAttributedStringKey,id> *attrs = [attributedString attributesAtIndex:range.location effectiveRange:nil];

if (attrs[WKSourceEditorCustomKeyFontBoldItalics] != nil || attrs[WKSourceEditorCustomKeyFontItalics] != nil) {
isItalics = YES;
isFormatted = YES;
} else {
// Edge case, check previous character if we are up against a closing bold or italic
if (attrs[WKSourceEditorCustomKeyColorOrange]) {
attrs = [attributedString attributesAtIndex:range.location - 1 effectiveRange:nil];
if (attrs[WKSourceEditorCustomKeyFontBold] != nil || attrs[WKSourceEditorCustomKeyFontItalics] != nil) {
isFormatted = YES;
}
}
}
}

} else {

__block NSRange unionRange = NSMakeRange(NSNotFound, 0);
[attributedString enumerateAttributesInRange:range options:nil usingBlock:^(NSDictionary<NSAttributedStringKey,id> * _Nonnull attrs, NSRange loopRange, BOOL * _Nonnull stop) {
if ((attrs[WKSourceEditorCustomKeyFontBoldItalics] != nil || attrs[WKSourceEditorCustomKeyFontItalics] != nil) &&
(loopRange.location == range.location && loopRange.length == range.length)) {
isItalics = YES;
if (attrs[WKSourceEditorCustomKeyFontBoldItalics] != nil || attrs[formattingKey] != nil) {
if (unionRange.location == NSNotFound) {
unionRange = loopRange;
} else {
unionRange = NSUnionRange(unionRange, loopRange);
}
stop = YES;
}
}];

if (NSEqualRanges(unionRange, range)) {
isFormatted = YES;
}
}

return isItalics;
return isFormatted;
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#import "WKSourceEditorFormatter.h"

NS_ASSUME_NONNULL_BEGIN

@interface WKSourceEditorFormatterStrikethrough : WKSourceEditorFormatter

- (BOOL)attributedString:(NSMutableAttributedString *)attributedString isStrikethroughInRange:(NSRange)range;

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 7040dc0

Please sign in to comment.