Skip to content

Commit

Permalink
Merge pull request wikimedia#4703 from wikimedia/native-editor-lists-…
Browse files Browse the repository at this point in the history
…actions

Native Editor - Add list support
  • Loading branch information
mazevedofs authored Jan 10, 2024
2 parents ec2e21d + 0f4e7d5 commit 32b31ed
Show file tree
Hide file tree
Showing 15 changed files with 708 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ class WKEditorToolbarButton: WKComponentView {
}
}

var isEnabled: Bool {
get {
return button.isEnabled
}
set {
button.isEnabled = newValue
updateColors()
accessibilityTraits = newValue ? [.button, .selected] : [.button, .notEnabled]
}
}

func setImage(_ image: UIImage?, for state: UIControl.State) {
button.setImage(image, for: state)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ protocol WKEditorToolbarExpandingViewDelegate: AnyObject {
func toolbarExpandingViewDidTapFind(toolbarView: WKEditorToolbarExpandingView)
func toolbarExpandingViewDidTapFormatText(toolbarView: WKEditorToolbarExpandingView)
func toolbarExpandingViewDidTapTemplate(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool)
func toolbarExpandingViewDidTapUnorderedList(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool)
func toolbarExpandingViewDidTapOrderedList(toolbarView: WKEditorToolbarExpandingView, isSelected: Bool)
func toolbarExpandingViewDidTapIncreaseIndent(toolbarView: WKEditorToolbarExpandingView)
func toolbarExpandingViewDidTapDecreaseIndent(toolbarView: WKEditorToolbarExpandingView)
}

class WKEditorToolbarExpandingView: WKEditorToolbarView {
Expand Down Expand Up @@ -112,10 +116,12 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView {
decreaseIndentionButton.setImage(WKSFSymbolIcon.for(symbol: .decreaseIndent), for: .normal)
decreaseIndentionButton.addTarget(self, action: #selector(tappedDecreaseIndentation), for: .touchUpInside)
decreaseIndentionButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current.accessibilityLabelButtonDecreaseIndent
decreaseIndentionButton.isEnabled = false

increaseIndentionButton.setImage(WKSFSymbolIcon.for(symbol: .increaseIndent), for: .normal)
increaseIndentionButton.addTarget(self, action: #selector(tappedIncreaseIndentation), for: .touchUpInside)
increaseIndentionButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current.accessibilityLabelButtonInceaseIndent
increaseIndentionButton.isEnabled = false

cursorUpButton.setImage(WKIcon.chevronUp, for: .normal)
cursorUpButton.addTarget(self, action: #selector(tappedCursorUp), for: .touchUpInside)
Expand Down Expand Up @@ -143,6 +149,27 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView {
}

templateButton.isSelected = selectionState.isHorizontalTemplate

unorderedListButton.isSelected = selectionState.isBulletSingleList || selectionState.isBulletMultipleList
unorderedListButton.isEnabled = !selectionState.isNumberSingleList && !selectionState.isNumberMultipleList

orderedListButton.isSelected = selectionState.isNumberSingleList || selectionState.isNumberMultipleList
orderedListButton.isEnabled = !selectionState.isBulletSingleList && !selectionState.isBulletMultipleList

decreaseIndentionButton.isEnabled = false
if selectionState.isBulletMultipleList || selectionState.isNumberMultipleList {
decreaseIndentionButton.isEnabled = true
}

if selectionState.isBulletSingleList ||
selectionState.isBulletMultipleList ||
selectionState.isNumberSingleList ||
selectionState.isNumberMultipleList {
increaseIndentionButton.isEnabled = true
} else {
increaseIndentionButton.isEnabled = false
}

cursorRightButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current.accessibilityLabelButtonCursorRight
}

Expand Down Expand Up @@ -199,15 +226,19 @@ class WKEditorToolbarExpandingView: WKEditorToolbarView {
}

@objc private func tappedUnorderedList() {
delegate?.toolbarExpandingViewDidTapUnorderedList(toolbarView: self, isSelected: unorderedListButton.isSelected)
}

@objc private func tappedOrderedList() {
delegate?.toolbarExpandingViewDidTapOrderedList(toolbarView: self, isSelected: orderedListButton.isSelected)
}

@objc private func tappedDecreaseIndentation() {
delegate?.toolbarExpandingViewDidTapDecreaseIndent(toolbarView: self)
}

@objc private func tappedIncreaseIndentation() {
delegate?.toolbarExpandingViewDidTapIncreaseIndent(toolbarView: self)
}

@objc private func tappedCursorUp() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ protocol WKEditorInputViewDelegate: AnyObject {
func didTapBold(isSelected: Bool)
func didTapItalics(isSelected: Bool)
func didTapTemplate(isSelected: Bool)
func didTapBulletList(isSelected: Bool)
func didTapNumberList(isSelected: Bool)
func didTapIncreaseIndent()
func didTapDecreaseIndent()
func didTapHeading(type: WKEditorInputView.HeadingButtonType)
func didTapStrikethrough(isSelected: Bool)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ class WKEditorToolbarGroupedView: WKEditorToolbarView {
decreaseIndentButton.setImage(WKSFSymbolIcon.for(symbol: .decreaseIndent), for: .normal)
decreaseIndentButton.addTarget(self, action: #selector(tappedDecreaseIndent), for: .touchUpInside)
decreaseIndentButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current?.accessibilityLabelButtonDecreaseIndent
decreaseIndentButton.isEnabled = false

increaseIndentButton.setImage(WKSFSymbolIcon.for(symbol: .increaseIndent), for: .normal)
increaseIndentButton.addTarget(self, action: #selector(tappedIncreaseIndent), for: .touchUpInside)
increaseIndentButton.accessibilityLabel = WKSourceEditorLocalizedStrings.current?.accessibilityLabelButtonInceaseIndent
increaseIndentButton.isEnabled = false

superscriptButton.setImage(WKSFSymbolIcon.for(symbol: .textFormatSuperscript), for: .normal)
superscriptButton.addTarget(self, action: #selector(tappedSuperscript), for: .touchUpInside)
Expand All @@ -56,27 +58,51 @@ class WKEditorToolbarGroupedView: WKEditorToolbarView {
}

// MARK: - Notifications

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

unorderedListButton.isSelected = selectionState.isBulletSingleList || selectionState.isBulletMultipleList
unorderedListButton.isEnabled = !selectionState.isNumberSingleList && !selectionState.isNumberMultipleList

orderedListButton.isSelected = selectionState.isNumberSingleList || selectionState.isNumberMultipleList
orderedListButton.isEnabled = !selectionState.isBulletSingleList && !selectionState.isBulletMultipleList

decreaseIndentButton.isEnabled = false
if selectionState.isBulletMultipleList || selectionState.isNumberMultipleList {
decreaseIndentButton.isEnabled = true
}

if selectionState.isBulletSingleList ||
selectionState.isBulletMultipleList ||
selectionState.isNumberSingleList ||
selectionState.isNumberMultipleList {
increaseIndentButton.isEnabled = true
} else {
increaseIndentButton.isEnabled = false
}

strikethroughButton.isSelected = selectionState.isStrikethrough
}

// MARK: - Button Actions

@objc private func tappedIncreaseIndent() {
delegate?.didTapIncreaseIndent()
}

@objc private func tappedDecreaseIndent() {
delegate?.didTapDecreaseIndent()
}

@objc private func tappedUnorderedList() {
delegate?.didTapBulletList(isSelected: unorderedListButton.isSelected)
}

@objc private func tappedOrderedList() {
delegate?.didTapNumberList(isSelected: orderedListButton.isSelected)
}

@objc private func tappedSuperscript() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import Foundation
import ComponentsObjC

extension WKSourceEditorFormatterList {
func toggleListBullet(action: WKSourceEditorFormatterButtonAction, in textView: UITextView) {
toggleListItem(action: action, formattingCharacter: "*", in: textView)
}

func toggleListNumber(action: WKSourceEditorFormatterButtonAction, in textView: UITextView) {
toggleListItem(action: action, formattingCharacter: "#", in: textView)
}

func tappedIncreaseIndent(currentSelectionState: WKSourceEditorSelectionState, textView: UITextView) {

guard currentSelectionState.isBulletSingleList ||
currentSelectionState.isBulletMultipleList ||
currentSelectionState.isNumberSingleList ||
currentSelectionState.isNumberMultipleList else {
assertionFailure("Increase / Decrease indent buttons should have been disabled.")
return
}

let formattingCharacter = (currentSelectionState.isBulletSingleList ||
currentSelectionState.isBulletMultipleList) ? "*" : "#"

let nsString = textView.attributedText.string as NSString
let lineRange = nsString.lineRange(for: textView.selectedRange)

textView.textStorage.insert(NSAttributedString(string: String(formattingCharacter)), at: lineRange.location)

// reset cursor so it doesn't move
if let selectedRange = textView.selectedTextRange {
if let newStart = textView.position(from: selectedRange.start, offset: 1),
let newEnd = textView.position(from: selectedRange.end, offset: 1) {
textView.selectedTextRange = textView.textRange(from: newStart, to: newEnd)
}
}
}

func tappedDecreaseIndent(currentSelectionState: WKSourceEditorSelectionState, textView: UITextView) {

guard currentSelectionState.isBulletSingleList ||
currentSelectionState.isBulletMultipleList ||
currentSelectionState.isNumberSingleList ||
currentSelectionState.isNumberMultipleList else {
assertionFailure("Increase / Decrease indent buttons should have been disabled.")
return
}

let nsString = textView.attributedText.string as NSString
let lineRange = nsString.lineRange(for: textView.selectedRange)

guard textView.textStorage.length > lineRange.location else {
return
}

textView.textStorage.replaceCharacters(in: NSRange(location: lineRange.location, length: 1), with: "")

// reset cursor so it doesn't move
if let selectedRange = textView.selectedTextRange {
if let newStart = textView.position(from: selectedRange.start, offset: -1),
let newEnd = textView.position(from: selectedRange.end, offset: -1) {
textView.selectedTextRange = textView.textRange(from: newStart, to: newEnd)
}
}
}

private func toggleListItem(action: WKSourceEditorFormatterButtonAction, formattingCharacter: Character, in textView: UITextView) {
let nsString = textView.attributedText.string as NSString
let lineRange = nsString.lineRange(for: textView.selectedRange)
switch action {
case .add:

var numBullets = 0
for char in textView.textStorage.attributedSubstring(from: lineRange).string {
if char == formattingCharacter {
numBullets += 1
}
}

let insertString = numBullets == 0 ? "\(String(formattingCharacter)) " : String(formattingCharacter)
textView.textStorage.insert(NSAttributedString(string: insertString), at: lineRange.location)

// reset cursor so it doesn't move
if let selectedRange = textView.selectedTextRange {
if let newStart = textView.position(from: selectedRange.start, offset: insertString.count),
let newEnd = textView.position(from: selectedRange.end, offset: insertString.count) {
textView.selectedTextRange = textView.textRange(from: newStart, to: newEnd)
}
}
case .remove:

var numBullets = 0
var hasSpace = false
for char in textView.textStorage.attributedSubstring(from: lineRange).string {
if char != formattingCharacter {
if char == " " {
hasSpace = true
}
break
}

if char == formattingCharacter {
numBullets += 1
}
}

let replacementLength = numBullets + (hasSpace ? 1 : 0)
textView.textStorage.replaceCharacters(in: NSRange(location: lineRange.location, length: replacementLength), with: "")

// reset cursor so it doesn't move
if let selectedRange = textView.selectedTextRange {
if let newStart = textView.position(from: selectedRange.start, offset: -1 * replacementLength),
let newEnd = textView.position(from: selectedRange.end, offset: -1 * replacementLength) {
textView.selectedTextRange = textView.textRange(from: newStart, to: newEnd)
}
}
}
}
}
Loading

0 comments on commit 32b31ed

Please sign in to comment.