Skip to content
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

Autocapitalization, autopunctuation, and autocorrect not working on Markdown field on iOS #16690

Open
josephdpurcell opened this issue Dec 1, 2022 · 21 comments · Fixed by codemirror/codemirror5#7010

Comments

@josephdpurcell
Copy link

josephdpurcell commented Dec 1, 2022

Describe the Bug

The iOS features of autocapitalization, autopunctuation, and autocorrect are not functioning on the Markdown field on iOS.

To illustrate the issue I have taken recordings of how the Directus Markdown field works and how the GitHub editor works.

Directus Markdown

Here is a recording:

16690-screen-recording.mov

Note: ignore the white square/circle in the recording, that is AssistiveTouch because my home button is broken.

GitHub Editor

FullSizeRender.MOV

To Reproduce

  1. Create a Collection with a field type Markdown
  2. On an iOS device (I used my iPhone), go to the item detail page of that content and edit the Markdown field
  3. Notice that these features do not work: words are not autocapitalized, two spaces does not result in an automatic period, and words like "cant" are not autocorrected to "can't".

Errors Shown

None.

What version of Directus are you using?

9.21.0

What version of Node.js are you using?

16.18.1

What database are you using?

MySQL 8.0.31

What browser are you using?

Safari

How are you deploying Directus?

Docker

Edit 12/2 9p ET: Added recording of GitHub Markdown for comparison.

@josephdpurcell
Copy link
Author

I do see a discussion regarding spell check in the browser #14409, but that is different functionality.

I see that the Markdown field uses Codemirror, and its possible that Codemirror itself does not support these features so I opened a ticket there: codemirror/dev#1020.

The importance of this issue impacts users who are writing content in a Markdown field on a mobile device (iPhone, iPad). I don't know if Android or similar OS's are impacted. It would be interesting to know from Directus Cloud analytics how many users are on an iOS device editing content, that may clarify whether I'm an odd duck or a meaningful statistic.

Details on my use case I enjoy writing. I like the simplicity of Markdown over HTML for the kind of writing I do. I am often on a mobile device when inspiration comes and I want to write. Well, writing long form content on a mobile device is far less efficient than on a proper keyboard. The iOS features of autocapitalization, autopunctuation, and autocorrect even the score and make writing on a mobile device at least tolerable. It follows that without these features I cannot use the Markdown field, and thus have to compromise by either switching to a different CMS to author content or switch to an HTML (WYSIWYG) field.

@josephdpurcell
Copy link
Author

It looks that CodeMirror (v6 and also v5?) support configuring autocapitalize and autocorrect behavior, see codemirror/dev#1020 (comment).

I can see that currently autocorrect="off" and autocapitalize="none" is set on the contenteditable element:

Screenshot from 2022-12-01 19-59-22_2

Perhaps this ticket is a question: should the Markdown field support autocapitalize and autocorrect by default? I hope the answer is yes so that it is in alignment with the WYSIWYG field. But, if the answer is no I hope there is an easy workaround for those who do wish this field to have this functionality supported.

@paescuj
Copy link
Member

paescuj commented Dec 2, 2022

Basically a good idea 😃 I wonder though if it doesn't get in the way when using Markdown specific syntax...?
We could add this in form of an new option, so users can turn it on / off as needed.

@josephdpurcell
Copy link
Author

josephdpurcell commented Dec 2, 2022

Should these functions be supported by default?

Here I attempt to give reasoning for or against having autocapitalization, autopunctuation, and autocorrect enabled by default in Directus' Markdown field. I will attempt to come to an agreeable conclusion through a few questions.

1 - What is the impact to writing Markdown?

First, let's look at @paescuj's very good question, but with my own wording:

Does having the specific features of autocapitalization, autopunctuation, and autocorrect get in the way of writing Markdown?

Let's start with the RFC. The RFC for Markdown is an enjoyable and informative read: https://datatracker.ietf.org/doc/html/rfc7764. The RFC explains what Markdown is. It is an informal specification for formatted text. The syntactical meaning of textual characters is left to implementations of Markdown. My interpretation of this is that the Directus Markdown field cannot say with certainty which textual characters have non-textual meaning, and therefore it cannot determine what is "in the way" vs not. That is, unless a flavor of markdown is stated as the supported flavor.

Even while not having an "officially supported" Directus Markdown flavor we can still attempt to identify the common textual characters that have non-textual meaning and conclude with decent reason whether the functions mentioned would interfere.

But first, let's list the textual characters affected by this functionality. Saving a formal review, here are top of mind thoughts, ignoring internationalization (I cannot speak to whether i18n would introduce additional considerations):

  • Characters a-z would be converted to A-Z at the start of a "word" (autocapitalization)
  • Character sequence "space space" would be converted to "period space" (autopunctuation)
  • Any character sequence could be replaced with an arbitrary difference character sequence (autocorrect)

Now, are any of those characters considered "meaningful" in the most common flavors of Markdown? Some thoughts:

  • Periods (.) are used after a number in lists. I'm unaware of autocorrect affecting this, though autopunctuation would take affect if the author entered two spaces. But, the common Markdown flavors suggest only one space, which means autopunctuation would only be a problem for numeric lists if the author mis-types an extra space. This would result in two periods like 1.. and could cause a Markdown interpreter to not render it as a list.
  • The letter "x" is used in checklists. However, both lowercase and uppercase X characters have equivalent meaning. So, autocapitalization here would not interfere. Autocorrect will probably not alter the sequence [x nor [X. Autopunctuation could interfere, but only on an error by the author. As best I can tell, the x character should not have any surrounding space characters, it should be [x]. If an author typed two spaces to cause autopunctuation they have already gone far astray.
  • HTML tags like <details> use a variety of characters, usually [a-z0-9-_], wrapped between open and close angle brackets. Autcapitalization shouldn't take effect because a tag starts with a <. Autopunctuation wouldn't apply because a space isn't used in tag names. Autocorrect could interfere especially with custom tags, but that may improve authoring experience given tag names are usually correctly spelled words.

I can't think of any other characters that an author might type that would cause autopunctuation or autocapitalization to possibly interfere. That leaves autocorrect, which could interfere in arbitrary ways given it is a dynamic pattern recognition. However, that very dynamic nature would hopefully "teach" autocorrect for an author of Markdown as they write more Markdown.

2 - What is the impact to non-Markdown-specific authoring?

It's not enough to consider how these functions affect writing Markdown, we must also consider how they impact whatever else people may write in a Markdown field.

Does having the specific features of autocapitalization, auto punctuation, and autocorrect get in the way of writing non-Markdown specific portions of content?

This question would probably be best answered by the gatekeepers of Markdown flavors. I can't imagine all the scenarios Github Flavored Markdown implementers have had to consider.

So, I'll limit the answer to what I know, and while it's not very much it's a common (and growing) pain point for many humans: writing code.

When writing code you certainly do not want the features of autocapitalization, autopunctuation, and autocorrect. Instead, you would want the editor to help you in other ways that are specific to the language or framework you are writing in.

But, I posit that originating the creation of code within Directus' Markdown field is less than the most-common case. I suspect the most common case would be the contents of a code block originate outside of Directus, perhaps originally written using VSCode or PHPStorm and copied into Directus.

But, we can take a different angle. Look at the RFC for Markdown. It states that Markdown is "intentionally targeted at non-technical users." By definition, the primary audience of Directus' Markdown field is not writing code inside of Markdown. (I speak hyperbole here to make the point.)

3 - What impact is not considered?

The question of enabling these functions can go far deeper into philosophy than I do here. The commons of the Internet should be well cared for, and I won't say I've considered all impacts of enabling this functionality by default. I don't even know if I've considered the most common impact. But, I will note a few that I intentionally did not cover:

  • Internationalization - I am not well versed in all the nuances of these functions for non-English languages.
  • Text Replacement - I do not know if the iOS "Text Replacement" feature intersects in some way with these functions.

Conclusion

I believe a reasonable conclusion is that the features of autocapitalization, autopunctuation, and autocorrect should be enabled by default on the Markdown field. It will be left to the more technical audience (who are not the targeted audience of Markdown) to adjust the behavior of the Markdown field if needed. That avoids putting the undue effort of enabling these functions on non-technical users.

Edit 12/2 8:20p ET: Edit Q1 to note HTML tags are commonly used in Markdown.

@tobius
Copy link

tobius commented Dec 3, 2022

Two features jump out at me as being problematic:

  1. Forcing a paragraph break is done by entering two spaces at the end of a line (now a period would be inserted, thereby erasing the paragraph marker).
  2. Assume you're not copy/pasting a code block but are writing it, auto capitalizing a case-sensitive command at the beginning of a line would cause that code to become invalid.

For those two reasons alone I would not want to make this a default behavior (unless the solution was aware of those issues and was able to avoid them). Can someone confirm this before committing to this change?

@rijkvanzanten
Copy link
Member

@tobius This is iOS only, both those things are settings in the OS, and afaik auto capitalization doesn't kick in on paste, so it should be fine as a default 👍🏻

@kenzik
Copy link

kenzik commented Dec 5, 2022

Rather than considering a new default behaviour, eg:

should the Markdown field support autocapitalize and autocorrect by default?

Could the component just retain its current defaults (not impacting anyone or negating any argument) but also allow the swapping of the component prop's value if a build var is set? Eg: VITE_MD_AUTO_CORRECT and/or VITE_MD_AUTO_CAP or similar.

It could be checked using the magic importa.meta.env.VITE_* stuff within the component, right?

I'm not an expert with vite yet, nor rollup, but I do something similar in a couple of my newer vite apps (and older webpack apps) by making a UI-centric .env.{tier} file map to the build environment and just let vite/webpack do the expansion during build time.

I find it to be a nice pattern when dealing with multiple audiences, but still wanting to retain a single codebase.

Of course this is only relevant if you do your own build. And one may argue that if you do that, you may as well maintain your own fork. But I'd argue that maintaining a fork for a simple prop preference is lame.

I'm not prepared to make a PR to demonstrate this, but figured I'd toss the idea out there.

Anyway, just a thought from another newbie to Directus...

@josephdpurcell
Copy link
Author

josephdpurcell commented Dec 7, 2022

I like @kenzik's idea.

Here is a diff that I got to work in Directus on iOS:

diff --git a/app/src/interfaces/input-rich-text-md/input-rich-text-md.vue b/app/src/interfaces/input-rich-text-md/input-rich-text-md.vue
index 1cb44d71a..59dd7837d 100644
--- a/app/src/interfaces/input-rich-text-md/input-rich-text-md.vue
+++ b/app/src/interfaces/input-rich-text-md/input-rich-text-md.vue
@@ -317,8 +317,18 @@ export default defineComponent({
                                        placeholder: props.placeholder,
                                        value: props.value || '',
                                        spellcheck: true,
-                                       inputStyle: 'contenteditable',
+                                       inputStyle: 'textarea',
+                                       autocapitalize: true,
+                                       autocorrect: true,
                                });
+                               setTimeout(() => {
+                                       const el = document.querySelectorAll(".CodeMirror textarea");
+                                       el.forEach((e) => {
+                                               alert('changed oooooooone');
+                                               e.setAttribute('autocorrect', 'on');
+                                               e.setAttribute('autocapitalize', 'on');
+                                       });
+                               }, 5000);
 
                                codemirror.on('change', (cm, { origin }) => {
                                        if (origin === 'setValue') return;

Here is a screen recording of what that looks like:

Expand to view video
FullSizeRender.MOV

Video is 2x speed.

What I found is that simply setting autocapitalize: true and autocorrect: true is not enough. I had to modify the field after render, hence the 5s wait. I tried duplicating this issue on CodeMirror v5 and was able to reproduce it locally but not with a CodePen, so I gave up.

My impression is that this could be a "bug" in CodeMirror 5. The above autocapitalize: true bits are supposed to work but they don't. And, in my CodeMirror v5 specific test I had to use this setTimeout as well. Here is my test there:

<!doctype html>
<html lang="en-US">
<head>
    <meta charset="UTF-8">
    <title>Browsersync Server Example</title>
    <script src="lib/codemirror.js"></script>
    <link rel="stylesheet" href="lib/codemirror.css">
    <script src="mode/javascript/javascript.js"></script>
</head>
<body>
    <h1>Browsersync Server Example 3</h1>
    <textarea id="myCode"></textarea>

  <script type="text/javascript">
      window.onload = function() {
        var myTextarea = document.getElementById("myCode");
        editor = CodeMirror.fromTextArea(myTextarea, {
          lineNumbers: true,
          autocorrect: "on",
          spellcheck: true,
	  autocapitalize: true,
          inputStyle: 'textarea'
        });
        editor.setOption("autocorrect", "on");

        setTimeout(() => {
          myTextarea.setAttribute("autocorrect", "on");
          myTextarea.setAttribute("autocapitalize", "on");

          const el = document.querySelectorAll(".CodeMirror textarea");
          el.forEach((e) => {
            console.log(e);
            e.setAttribute('autocorrect', 'on');
            e.setAttribute('autocapitalize', 'on');
          });
          alert('ready');
        }, 500);
      };
    </script>
</body>
</html>

Forgive the mess, I'm doing this in haste.

@josephdpurcell
Copy link
Author

I've created a ticket over at CodeMirror5: codemirror/codemirror5#7009. Hopefully I'm missing something simple.

@josephdpurcell
Copy link
Author

I am unable to make progress on addressing the issue with CodeMirror5, see my latest comment over there codemirror/codemirror5#7009 (comment). I believe CodeMirror5 does not support autocomplete and autocorrect on iOS.

As a result, I think these attrs need manually set like I showed above, except you don't need a setTimeout, just do it like I show here codemirror/codemirror5#7009 (comment).

When I have a moment I'll submit a new Directus diff.

@paescuj
Copy link
Member

paescuj commented Dec 8, 2022

Hey there!

Many thanks for all your detailed contributions! 👍

@josephdpurcell Did you by chance also test it with CodeMirror v6? I think I'll take a look at it soon seeing if an upgrade is easily possible...

@josephdpurcell
Copy link
Author

@paescuj CodeMirror6 has proper support, based on threads I read and testing. V6 is a complete rewrite as I understand and addresses several important architectural issues.

If/when I get a chance I'll submit a code pen for V6.

@josephdpurcell
Copy link
Author

After doing more testing of CodeMirror5 I discovered that even when setting the attributes "manually" on CodeMirror5 autocapitalization still is not fully functional, it does not work for new lines. I updated the CodeMirror5 ticket: codemirror/codemirror5#7009 (comment). So, I think CodeMirror5 is a non-starter, unless I missed something in my investigation (see that 7009 for details).

I Iike the idea of trying CodeMirror6. I attempted to get CodeMirror6 working in a code pen but failed to get it to load, I'm certain I'm doing something wrong. Instead, I'll try to just get CodeMirror6 working locally so I can test and confirm this functionality works. THEN I'll attempt a code pen again.

@josephdpurcell
Copy link
Author

I did a test with CodeMirror6 and these features works! See codemirror/dev#1020 (comment).

I'm not a huge fan of the experience because it looks like both the CodeMirror6 autocorrect and iOS autocorrect are taking effect, and it autoindents. Maybe these are just settings.

Here is a migration guide for going from 5 to 6: https://codemirror.net/docs/migration/.

@josephdpurcell
Copy link
Author

My desired authoring experience for a Markdown field on iOS can be seen by using a simple textarea field, see recording codemirror/codemirror5#7009 (comment). It nicely handles autocorrect, autopunctuation, and autocapitalization even on newlines.

@josephdpurcell
Copy link
Author

josephdpurcell commented Dec 8, 2022

I did a little more testing with CodeMirror5 and found some interesting things. If you change the codemirrorEl from a div to a textarea the field becomes uneditable.

The other thing I observed is that I can get very close to having these functions working as expected, but I noticed the select menu (which houses the Select All and Paste functions on iOS) do not appear. I don't know if this is because of some change I made in this diff or if it was previous behavior.

diff --git a/app/src/interfaces/input-rich-text-md/input-rich-text-md.vue b/app/src/interfaces/input-rich-text-md/input-rich-text-md.vue
index 1cb44d71a..5580113f0 100644
--- a/app/src/interfaces/input-rich-text-md/input-rich-text-md.vue
+++ b/app/src/interfaces/input-rich-text-md/input-rich-text-md.vue
@@ -317,8 +317,11 @@ export default defineComponent({
                                        placeholder: props.placeholder,
                                        value: props.value || '',
                                        spellcheck: true,
-                                       inputStyle: 'contenteditable',
+                                       inputStyle: 'textarea',
                                });
+                               var input = codemirror.getInputField();
+                               input.setAttribute('autocorrect', 'on');
+                               input.setAttribute('autocapitalize', 'on');
 
                                codemirror.on('change', (cm, { origin }) => {
                                        if (origin === 'setValue') return;

Here is a recording at 2x of the behavior:

Expand to see video
FullSizeRender.MOV

@josephdpurcell
Copy link
Author

I just tested having inputStyle: 'contenteditable' and it allows the select menu to appear, but autocapitalization, autocorrect, and autopunctuation don't work.

@josephdpurcell
Copy link
Author

I started a discussion in case its worth considering an alternative editor for Markdown #16762.

@josephdpurcell
Copy link
Author

@paescuj I see there is an issue created for an upgrade to CodeMirror6 #16061. Let's discuss that idea there, I have some notes to share.

@rijkvanzanten
Copy link
Member

Linear: ENG-123

@josephdpurcell
Copy link
Author

I commented on the CodeMirror6 upgrade ticket #16061 but wanted to cross-post here in case it gets missed. Agit CMS is using CodeMirror6 and the authoring experience is really nice, the author of the project was able to make a small change to enable these autocorrect, autopunctuation, and autocapitalization features, see related Agit CMS ticket: 0xsuk/agitcms#30 (comment). This suggests that upgrading to CodeMirror6 would very likely address the issue identified in this ticket.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: 📋 Backlog
Development

Successfully merging a pull request may close this issue.

5 participants