[1.5.x] Fixed #8627 -- Prevented textareas to swallow first newline content
Browsers consider the first newline in textareas as some display
artifact, not real content. Hence they are not sending it back to
the server. If we want to keep initial newlines, we have to add one
when we render the textarea.
Thanks bastih for the report and initial patch.
Backport of 78f66691ee
from master.
This commit is contained in:
parent
c7d5e7c75b
commit
a23c9c48a8
|
@ -403,7 +403,7 @@ class Textarea(Widget):
|
||||||
def render(self, name, value, attrs=None):
|
def render(self, name, value, attrs=None):
|
||||||
if value is None: value = ''
|
if value is None: value = ''
|
||||||
final_attrs = self.build_attrs(attrs, name=name)
|
final_attrs = self.build_attrs(attrs, name=name)
|
||||||
return format_html('<textarea{0}>{1}</textarea>',
|
return format_html('<textarea{0}>\r\n{1}</textarea>',
|
||||||
flatatt(final_attrs),
|
flatatt(final_attrs),
|
||||||
force_text(value))
|
force_text(value))
|
||||||
|
|
||||||
|
|
|
@ -84,3 +84,7 @@ class Group(models.Model):
|
||||||
|
|
||||||
class Cheese(models.Model):
|
class Cheese(models.Model):
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
|
|
||||||
|
|
||||||
|
class Article(models.Model):
|
||||||
|
content = models.TextField()
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<form method="post" action=".">
|
||||||
|
{{ form.as_p }}<br>
|
||||||
|
<input id="submit" type="submit">
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -18,4 +18,4 @@ from .regressions import FormsRegressionsTestCase
|
||||||
from .util import FormsUtilTestCase
|
from .util import FormsUtilTestCase
|
||||||
from .validators import TestFieldWithValidators
|
from .validators import TestFieldWithValidators
|
||||||
from .widgets import (FormsWidgetTestCase, FormsI18NWidgetsTestCase,
|
from .widgets import (FormsWidgetTestCase, FormsI18NWidgetsTestCase,
|
||||||
WidgetTests, ClearableFileInputTests)
|
WidgetTests, LiveWidgetTests, ClearableFileInputTests)
|
||||||
|
|
|
@ -4,7 +4,9 @@ from __future__ import unicode_literals
|
||||||
import copy
|
import copy
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
|
||||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
from django.forms import *
|
from django.forms import *
|
||||||
from django.forms.widgets import RadioFieldRenderer
|
from django.forms.widgets import RadioFieldRenderer
|
||||||
from django.utils import formats
|
from django.utils import formats
|
||||||
|
@ -15,6 +17,8 @@ from django.test import TestCase
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
from ..models import Article
|
||||||
|
|
||||||
|
|
||||||
class FormsWidgetTestCase(TestCase):
|
class FormsWidgetTestCase(TestCase):
|
||||||
# Each Widget class corresponds to an HTML form widget. A Widget knows how to
|
# Each Widget class corresponds to an HTML form widget. A Widget knows how to
|
||||||
|
@ -1095,6 +1099,22 @@ class WidgetTests(TestCase):
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
|
|
||||||
|
|
||||||
|
class LiveWidgetTests(AdminSeleniumWebDriverTestCase):
|
||||||
|
urls = 'regressiontests.forms.urls'
|
||||||
|
|
||||||
|
def test_textarea_trailing_newlines(self):
|
||||||
|
"""
|
||||||
|
Test that a roundtrip on a ModelForm doesn't alter the TextField value
|
||||||
|
"""
|
||||||
|
article = Article.objects.create(content="\nTst\n")
|
||||||
|
self.selenium.get('%s%s' % (self.live_server_url,
|
||||||
|
reverse('article_form', args=[article.pk])))
|
||||||
|
self.selenium.find_element_by_id('submit').submit()
|
||||||
|
article = Article.objects.get(pk=article.pk)
|
||||||
|
# Should be "\nTst\n" after #19251 is fixed
|
||||||
|
self.assertEqual(article.content, "\r\nTst\r\n")
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class FakeFieldFile(object):
|
class FakeFieldFile(object):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
from django.conf.urls import patterns, url
|
||||||
|
from django.views.generic.edit import UpdateView
|
||||||
|
|
||||||
|
from .views import ArticleFormView
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
url(r'^/model_form/(?P<pk>\d+)/$', ArticleFormView.as_view(), name="article_form"),
|
||||||
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
from django.views.generic.edit import UpdateView
|
||||||
|
|
||||||
|
from .models import Article
|
||||||
|
|
||||||
|
|
||||||
|
class ArticleFormView(UpdateView):
|
||||||
|
model = Article
|
||||||
|
success_url = '/'
|
Loading…
Reference in New Issue