Skip to content

Conversation

@jleandroperez
Copy link
Contributor

@jleandroperez jleandroperez commented Apr 17, 2017

Description:

In this PR we're nuking Zero Width Spaces from the TextLists Formatter.

All of the Testing Scenarios are backed up by a unit test. Ain't that cool?

Needs Review: @diegoreymendez @SergioEstevao
Diego: Thanks for the infinite help on this one!!

Closes #421
Ref.: #414

Details:

  • Yes. We're removing the Zero Width Spaces from the TextLists's inner working. Whenever a bullet must be rendered, and there's no text, we'll be inserting a \n character.

    Hook points for this behavior are insertText and the formatter's toggle themselves.

  • And yes. We're overriding typingAttributes, because the didSet observer of both, selectedRange and selectedTextRange is not being always triggered (ie. user touch).

  • TextListFormatter got a new helper to verify if lists of any kind are present in a collection of attributes.

  • Removed a workaround from LayoutManager, which was being used to render the extra line fragment (Bullets when there was no text).

--

Testing:

Detailing below all of the test cases.

Scenario I: List after Backspace

  1. Empty Document
  2. Toggle List
  3. Type something
  4. Backspace

Verify that the list remains onscreen.

Scenario II: Deleting after List

  1. Empty Document
  2. Toggle List
  3. Arrow Down
  4. Backspace

Verify that the List is gone.

Scenario III: Newline Not Inserted

  1. Empty Document
  2. Toggle List
  3. Arrow Down
  4. Enter

Verify that the Newline gets inserted.

Scenario IV: New List Item when at the edge of the document

  1. Empty Document
  2. Toggle List
  3. Type something
  4. Arrow Down
  5. Backspace
  6. Enter

Verify that a new bullet gets added.

Scenario V: Typing Attributes on new line

  1. Empty Document
  2. Toggle List
  3. Arrow Down

Verify that the Typing Attributes do not contain a Text List: indentation should be normal. Typing any character should not display a bullet.

Scenario VI: Empty Lines

  1. Empty Document
  2. Toggle List
  3. Insert a newline

Verify that the bullet in the first line gets removed.

@jleandroperez jleandroperez changed the title [NOT Ready!] Lists: Nuking Zero Width Spaces Lists: Nuking Zero Width Spaces Apr 18, 2017
Copy link
Contributor

@diegoreymendez diegoreymendez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jorge - this is working incredibly well. Very nice work!!!

I've pointed out a few changes that I think are key before merging this in. Can you give them a look? I'll keep reviewing the code to try and find any other issues.

PS: it hasn't crashed yet on me!

return attributes
}

var updatedAttributes = attributes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From this line below, the problem is that we're not only removing the textList style, but we're actually resetting the full paragraph configuration to the default, which is not really desired. For instance: we may not want to remove the blockquote style.

To avoid resetting the whole paragraph, you can use this code instead (or an equivalent code):

let orderedListFormatter = TextListFormatter(style: .ordered)
let unorderedListFormatter = TextListFormatter(style: .unordered)

if orderedListFormatter.present(in: attributes) {
    return orderedListFormatter.remove(from: attributes)
} else if unorderedListFormatter.present(in: attributes) {
    return unorderedListFormatter.remove(from: attributes)
} else {
    return attributes
}

PS: don't worry too much about the code being perfect. This code will change ENORMOUSLY once we change to using a mechanism closer to what Apple uses for nested lists, but this should be a good starting point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100% good call, thanks for the snippet!!

/// - Returns: Updated Typing Attributes.
///
private func ensureRemovalOfListAttribute(from attributes: [String: Any]) -> [String: Any] {
guard selectedRange.location == storage.length && selectedRange.length == 0 else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reading simplicity I'd consider removing selectedRange.length == 0. If the caret position is indeed at EOF, then the length will always be zero.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely right, updating as well, thanks!!


/// Removes the List Attributes from a collection of attributes, whenever:
///
/// A. The caret is at the very end of the document (+ there is no selected text)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the selected range location starts at EOF, then (+ there is no selected text) is always true.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, thank you!!

}


/// Removes the List Attributes from a collection of attributes, whenever:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd consider adding extra documentation to explain why this is necessary. Specifically something like:

// This is necessary because when the caret is at EOF, and the previous `\n` character has
// a textList style, that style will remain in the `typingAttributes`.  We'll only allow the style
// to remain if there are contents in the current line with the textList style (in which case
// this condition won't ever trigger because we'll either no longer be at EOF, or the previous
// character won't be `\n`).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, thank you!

return
}

// Note: We *really* need to use super, so that we prevent recursive loops.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed all references to super in this method, and the code seems to work fine. Is it possible this was a problem when this code was called directly from the typingAttributes getter instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record:

Removed the super.typingAttributes (it was probably crashing due to testing code!), but left the super.insertText, since, without that one, we do get a loop.

Re: extra docs, as discussed over Slack, we've got a unit test that would trigger the loop, so we're cool.

Thanks a lot Diego!

Copy link
Contributor

@diegoreymendez diegoreymendez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pure gold! Thanks @jleandroperez !

@jleandroperez
Copy link
Contributor Author

Woooooo thanks SO much for the support Diego!! this one is more yours than mine!!!

@jleandroperez jleandroperez merged commit 5f28a3a into develop Apr 18, 2017
@jleandroperez jleandroperez deleted the issue/414-nuking-zero-width-spaces-from-text-lists branch April 18, 2017 21:03
@SergioEstevao
Copy link
Contributor

@jleandroperez late to the party, but this PR was excellent!!!

@jleandroperez
Copy link
Contributor Author

Thanks a lot @SergioEstevao!!! 🔥 🔥 🔥 🔥 🔥 🔥

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants