-
Notifications
You must be signed in to change notification settings - Fork 147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Retain Heading attribute when headings are autocorrected. #1334
Conversation
b411078
to
acdfaaa
Compare
8dd4eaf
to
80bcf0b
Compare
80bcf0b
to
3936da5
Compare
ad87fed
to
cce2da7
Compare
I tested this POC locally and see the same output you shared in this code comment. Looking at that output, the custom attribute seems to be still applied to the "Hello " portion of the string, as well as the a trailing space. Is this how you interpret the output? I may be wrong, but the I ask because reading this PR description (which I haven't tested yet), seems to outline a solution that doesn't make reference to what I noted above, so I wanted to ask you if this was relevant. |
Thanks for pointing this out @guarani! I've made this clearer by adding better testing steps. Just let me know if anything is unclear or if you notice anything's incorrect. 🙇 The Aztec demo with the new steps should be followed over the POC. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree there does appear to be bug in how the UITextView
's typingAttributes
are cleared. I came across https://stackoverflow.com/questions/38399702/maintain-custom-attributes-when-replacing-attributed-text-on-uitextview, would you agree it matches the issue we're seeing here?
If replaceCharacters
is only ever called when text is edited, I would assume that the text's attributes shouldn't change, so we can copy the custom heading attribute across.
If replaceCharacters
is called in other scenarios for example when switching from a header to a paragraph, then I suspect the heading attribute might be copied across from the header to the paragraph. To test this, I followed these steps:
- On the Empty Demo screen, switch to a Header
- Add a breakpoint to the end of the
replaceCharacters
function mentioned above - Type one or more characters, and (when the breakpoint is hit) notice that
textStore
containsheadingRepresentation = 1;
for the all characters (as expected) - Convert the Heading to a Paragraph
- Notice the breakpoint is hit again, print
textStore
and notice that theheadingRepresentation = 1;
is still present (not expected)
I'm not sure why visually the text looks like a paragraph even though the heading custom attribute is still there. Also, I tested the Heading block to Paragraph block transformation and it seemed to work, so not sure what the impact is here. Would you say it's a bug? I'm not sure yet.
I also want to share something I noticed while testing this. Take this example (based on your above POC):
After running the app, I type
Note that no autocorrect has taken place, and no text has been set programmatically. I'd previously thought that the bug affected only autocorrect (and possibly programatically set text), but this suggests it's present in other scenarios. |
That's a good observation @guarani and the reason why I had to implement In the case of autocorrect this differed slightly in that attempts to force the current typing attributes failed. [textViewShouldBeginEditing, shouldChangeTextIn]. |
This is a good catch! We really shouldn't be retaining the Furthermore it seems to "pollute" the |
@guarani I observed that when headings are used they contain a I've also added a test for this and updated the original test to use a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is working great! I tested using both the original testing steps and the scenario where a Heading is converted to a Paragraph and both worked as expected.
I also spent some time checking for regressions and was unable to spot any.
Thanks for your awesome work here finding a fix @twstokes! 💯
Thanks for the review @guarani and for making this work better! |
Related:
This PR aims to resolve an issue where
TextStorage
attributed string replacements from the operating system (e.g. autocorrect, keyboard suggestions, double-tapping the spacebar to insert a period) aren't copying all of the existing attributes for the range they're replacing. When this is performed on a Heading, theheadingRepresentation
attribute key is missing, and ultimately causes the HTML generator to wrap certain strings in<strong>
tags. This PR only addresses missingheadingRepresentation
keys.I've created a POC to show that may be a bug on Apple's side.
State inspection using the Aztec demo:
When inserting a breakpoint here, outputting the supplied
attrString
after autocorrect has taken place will show theNSAttributedString
doesn't contain theheadingRepresentation
attribute.Functionality of these changes:
func replaceCharacters(in range: NSRange, with attrString: NSAttributedString)
is called, the provided attributed string is checked to see if it includes aheadingRepresentation
custom key.textStore
includes it. If so, we determine that it's a heading and inject the custom attribute. Otherwise we don't mutate the string.An edge case may come into question: What if the first word is autocorrected, won't the first character be missing the heading attribute?
This should be no due to the insertion of the initial characters from the keyboard, which carry the heading attribute.
To test:
Add a breakpoint to this line., but don't enable it yet.
7a. Observe the value of
attrString
. It should equal:7b. Observe the value of
textStore
. It should equal:preprocessedString
. It should equal:textStore
. It should equal:Before this change, the output would equal:
Note that the trailing space doesn't appear until after this text is processed, so it won't be shown in these steps.