Problem/Motivation

I have a text_long entity field and when I submit the entity form through AJAX it generates different result then submitting it normally.
The value of this text input field contains at the end :
normal submit - "\r\n"
ajax submit - "\n".

This is a problem and a serious one because there is no workaround and if you do stuff in a submit for an ajax call like building the entity and calling $entity->hasTranslationChanges() then this will return TRUE even if there aren't any changes and this will happen simply because ajax generates different values.

The real problem relies in jquery-form, as it is not ensuring that new lines are encoded as CRLF pairs like browsers are doing it.

jQuery has added support a while ago for this, but jquery-form hasn't adopted it yet. I've opened a pull request about this - https://github.com/jquery-form/form/pull/516

However we still have to figure out how we should ensure that new lines are encoded as CRLF pairs in Drupal. Is it fine to temporary adjust ajax.js or should we have an request subscriber or something like this processing the form values early in the boot process and ensuring new lines are presented as CRLF pairs?

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

hchonov created an issue. See original summary.

hchonov’s picture

Issue summary: View changes

What I've discovered by setting a breakpoint in index.php is that when submitting normally the form at the end of the string value there is "\r\n" contained, but submitting it through Ajax there is only "\n" contained.

hchonov’s picture

Title: Submission through AJAX might add line breaks » Submission through AJAX generates different values than normal submission
hchonov’s picture

I've found some related topics:
https://bugs.jquery.com/ticket/9007
https://bugs.jquery.com/ticket/6876
https://github.com/jquery/jquery/commit/eed3803c98bf5c074e40aad12f2e9143...

But it looks like that jquery isn't serializing our input otherwise it should've contained \r\n based on that commit. Unfortunately I am not that good with JS. Could probably someone help me out?

hchonov’s picture

Status: Active » Needs review
FileSize
664 bytes

Based on the application/x-www-form-urlencoded specification all line breaks should be encoded as CRLF pairs. See the links from the previous comment about this.

hchonov’s picture

oups wrong indentation ..

tstoeckler’s picture

ESLint complains about this, see https://dispatcher.drupalci.org/job/drupal_patches/3937/checkstyleResult/ :

The body of a for-in should be wrapped in an if statement to filter unwanted properties from the prototype. (guard-for-in)

Can't say anything about the patch itself, so leaving at needs review for now, but a re-roll should fix the above.

hchonov’s picture

Title: Submission through AJAX generates different values than normal submission » AJAX Submission is not encoding new lines as CRLF pairs, but only as LF - resulting into a different values than browser submission
Issue summary: View changes

So the real problem relies in jquery-form, as it is not ensuring that new lines are encoded as CRLF pairs like browsers are doing it.

jQuery has added support a while ago for this, but jquery-form hasn't adopted it yet. I've opened a pull request about this - https://github.com/jquery-form/form/pull/516

However we still have to figure out how we should ensure that new lines are encoded as CRLF pairs in Drupal. Is it fine to temporary adjust ajax.js or should we have an request subscriber or something like this processing the form values early in the boot process and ensuring new lines are presented as CRLF pairs?

tstoeckler’s picture

should we have an request subscriber or something like this processing the form values early in the boot process and ensuring new lines are presented as CRLF pairs?

So we already have the abstraction layer between $form_state->getUserInput() and $form_state->getValues() so since problem seems to be limited to form submissions whether we could solve it in the Form API itself. If this is in fact limited to textareas, maybe we could even implement this logic in \Drupal\Core\Render\Element\Textarea::valueCallback(). Then in $form_state->getUserInput() we would still have the potentially inconsistent value but anything going through $form_state->getValues() would have a properly normalized value. And it would still be pretty self-contained.

hchonov’s picture

FileSize
857 bytes

Something like this? I am fine with this if we are sure that this is the only place where new lines should be formatted with CRLF pairs.

hchonov’s picture

We have to use double quotes for the replacement "\r\n" :).

The last submitted patch, 10: 2856801-10.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 11: 2856801-11.patch, failed testing.

hchonov’s picture

Status: Needs work » Needs review
FileSize
4.73 KB
3.51 KB

And we actually already have tests there, which had to be adjusted :).

hchonov’s picture

Title: AJAX Submission is not encoding new lines as CRLF pairs, but only as LF - resulting into a different values than browser submission » AJAX Submission is not encoding new lines in textarea values as CRLF pairs, but only as LF - resulting into a different values than browser submission
tstoeckler’s picture

Nice! To me this looks like a pretty nice fix, but this should be looked at by a Form API maintainer. Tagging accordingly. Although since this is in the ajax system component, I guess they might not see it?

One minor note on the patch, looks great otherwise:

+++ b/core/lib/Drupal/Core/Render/Element/Textarea.php
@@ -57,7 +57,10 @@ public static function valueCallback(&$element, $input, FormStateInterface $form
+      // Ensure that new lines are always formatted as CRLF pairs.
+      $processed_input = preg_replace('@\r?\n@', "\r\n", $input) ?: $input;

Maybe we could document why we do this?

hchonov’s picture

Component: ajax system » forms system
FileSize
5.34 KB
1.28 KB

While the bug occurs in the ajax subsystem we are ensuring in the form subsystem that we fulfill the HTML specification for textarea form elements, so I think it is fine to move the bug report to the form subsystem.

hchonov’s picture

Title: AJAX Submission is not encoding new lines in textarea values as CRLF pairs, but only as LF - resulting into a different values than browser submission » AJAX form submission is not encoding new lines in textarea values as CRLF pairs, but only as LF - resulting into a different values than browser submission
tstoeckler’s picture

Wow, that comment is awesome, thank you!!!

hchonov’s picture

Re-roll only.

tstoeckler’s picture

Status: Needs review » Reviewed & tested by the community

Looked at this again after a while. The fix is really nice and self-contained and comes with test coverage, so I think it's good to go from my point of view. Subsystem maintainer review wouldn't hurt, but since this doesn't actually touch FormBuilder or anything of the sort I think the risk here is very limited.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 20: 2856801-20.patch, failed testing.

hchonov’s picture

FileSize
5.46 KB

Re-roll after #2863996: Convert web tests to browser tests for ckeditor module, therefore I think it is fine to put the status back to RTBC as set by @tstoeckler in #21.

hchonov’s picture

Status: Needs work » Reviewed & tested by the community

Hmm .. I've forgotten to put the status back to RTBC.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 23: 2856801-23.patch, failed testing.

tacituseu’s picture

Status: Needs work » Reviewed & tested by the community

Unrelated failure

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 23: 2856801-23.patch, failed testing.

tacituseu’s picture

Status: Needs work » Reviewed & tested by the community
tstoeckler’s picture

+++ b/core/lib/Drupal/Core/Render/Element/Textarea.php
@@ -57,7 +57,18 @@ public static function valueCallback(&$element, $input, FormStateInterface $form
+      $processed_input = preg_replace('@\r?\n@', "\r\n", $input) ?: $input;

I asked @hchonov about why we do the ?: $input fallback.

tl;dr: It makes sense, thus, leaving at RTBC.

Details:
He pointed me to the PHP documentation which says that NULL will be returned if an error occurred.

So I thought that in case of an error, it would probably be good to fail explicitly (which in this case would be returning NULL as the form value) instead of just using the unprocessed string so that one becomes aware of the error and can fix it.

@hchonov then pointed me to https://bugs.php.net/bug.php?id=70110 (see #2792877: Symfony YAML parser fails on some strings when running PHP 7 for more information), which could result in such an error leading preg_replace() to return NULL. In this edge case, where PCRE JIT compilation is on, and someone posts a string which reveals this bug into a textarea, it is presumably better to simply submit the text without normalized newlines into the database instead of failing.This is exactly what the fallback achieves. If someone does want the newlines to be normalized they can turn PCRE JIT compilation off.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

This got fixed upstream https://github.com/jquery-form/form/pull/516 - perhaps we should just pull that it and not have to do this on all text submitted in textareas.

Plus the text in #29 that explains:

+++ b/core/lib/Drupal/Core/Render/Element/Textarea.php
@@ -57,7 +57,18 @@ public static function valueCallback(&$element, $input, FormStateInterface $form
+      $processed_input = preg_replace('@\r?\n@', "\r\n", $input) ?: $input;

the ternary should also be in the code - if we are going to do this.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

tstoeckler’s picture

Status: Needs work » Postponed

Yeah, I agree with #30 that that is the better fix. Talked to @hchonov (a while back) and he agreed, as well.
I do think it's worth to keep this open for reference, though, until we have upgraded jquery form. So marking postponed on #2899141: jQuery Form Plugin update to latest stable release. Once that is in, this can go straight to "closed (duplicate)".

kfritsche’s picture

FileSize
5.57 KB

I know its postponed, but we still need and use it, therefore rerolled #23

Just in case some one runs in here ;)

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

tstoeckler’s picture

tstoeckler’s picture

Status: Postponed » Closed (duplicate)

Per #32