Skip to content

Commit 0ac5436

Browse files
committed
atom: switch from white-space: pre to converting newlines to <br>s
...because some feed readers follow it too strictly and don't even line wrap, eg https://forum.newsblur.com/t/android-cant-read-line-pre-formatted-lines/6116 re: #80
1 parent a2d83d8 commit 0ac5436

File tree

4 files changed

+28
-6
lines changed

4 files changed

+28
-6
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,8 @@ Changelog
318318
* Revise whitespace handling; use `white-space: pre` CSS in HTML output.
319319
* Facebook:
320320
* Bug fix: don't interpret `photo.php` as username in post URLs.
321+
* Atom:
322+
* Switch from `white-space: pre` CSS back to converting newlines to `<br>`s because some feed readers ([eg NewsBlur](https://forum.newsblur.com/t/android-cant-read-line-pre-formatted-lines/6116)) follow it too strictly and don't even line wrap.
321323
* RSS:
322324
* Default title to ellipsized content.
323325

granary/atom.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,11 @@ def _prepare_activity(a, reader=True):
357357

358358
# Render content as HTML; escape &s
359359
obj['rendered_content'] = _encode_ampersands(microformats2.render_content(
360-
primary, include_location=reader, render_attachments=True))
360+
primary, include_location=reader, render_attachments=True,
361+
# Readers often obey CSS white-space: pre strictly and don't even line wrap,
362+
# so don't use it.
363+
# https://forum.newsblur.com/t/android-cant-read-line-pre-formatted-lines/6116
364+
white_space_pre=False))
361365

362366
# Make sure every activity has the title field, since Atom <entry> requires
363367
# the title element.

granary/microformats2.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ def hcard_to_html(hcard, parent_props=None):
769769

770770

771771
def render_content(obj, include_location=True, synthesize_content=True,
772-
render_attachments=False):
772+
render_attachments=False, white_space_pre=True):
773773
"""Renders the content of an ActivityStreams object as HTML.
774774
775775
Includes tags, mentions, and non-note/article attachments. (Note/article
@@ -784,6 +784,9 @@ def render_content(obj, include_location=True, synthesize_content=True,
784784
include_location: whether to render location, if provided
785785
synthesize_content: whether to generate synthetic content if the object
786786
doesn't have its own, e.g. 'likes this.' or 'shared this.'
787+
white_space_pre: boolean, whether to wrap in CSS white-space: pre. If False,
788+
newlines will be converted to <br> tags instead. Background:
789+
https://indiewebcamp.com/note#Indieweb_whitespace_thinking
787790
788791
Returns:
789792
string, rendered HTML
@@ -826,7 +829,10 @@ def render_content(obj, include_location=True, synthesize_content=True,
826829
# https://indiewebcamp.com/note#Indieweb_whitespace_thinking
827830
# https://github.com/snarfed/granary/issues/80
828831
if content and not obj.get('content_is_html') and '\n' in content:
829-
content = '<div style="white-space: pre">%s</div>' % content
832+
if white_space_pre:
833+
content = '<div style="white-space: pre">%s</div>' % content
834+
else:
835+
content = content.replace('\n', '<br />\n')
830836

831837
# linkify embedded links. ignore the "mention" tags that we added ourselves.
832838
# TODO: fix the bug in test_linkify_broken() in webutil/tests/test_util.py, then

granary/tests/test_microformats2.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ def test_render_content_multiple_image_attachments(self):
204204
<img class="u-photo" src="http://2" alt="" />
205205
</p>""", microformats2.render_content(obj, render_attachments=True))
206206

207-
def test_render_content_converts_newlines_to_brs(self):
207+
def test_render_content_newlines_default_white_space_pre(self):
208208
self.assert_equals("""\
209209
<div style="white-space: pre">foo
210210
bar
@@ -214,6 +214,16 @@ def test_render_content_converts_newlines_to_brs(self):
214214
'tags': [{'url': 'http://baz', 'startIndex': 8, 'length': 3}]
215215
}))
216216

217+
def test_render_content_convert_newlines_to_brs(self):
218+
self.assert_equals("""\
219+
foo<br />
220+
bar<br />
221+
<a href="http://baz">baz</a>
222+
""", microformats2.render_content({
223+
'content': 'foo\nbar\nbaz',
224+
'tags': [{'url': 'http://baz', 'startIndex': 8, 'length': 3}]
225+
}, white_space_pre=False))
226+
217227
def test_render_content_omits_tags_without_urls(self):
218228
self.assert_equals("""\
219229
foo
@@ -633,8 +643,8 @@ def test_json_to_object_with_categories(self):
633643
},
634644
], obj.get('tags'))
635645

636-
def test_json_to_object_converts_text_newlines_to_brs(self):
637-
"""Text newlines should be converted to <br>s."""
646+
def test_json_to_object_text_newlines(self):
647+
"""Text newlines should not be converted to <br>s."""
638648
self.assert_equals({
639649
'objectType': 'note',
640650
'content': 'asdf\nqwer',

0 commit comments

Comments
 (0)