Skip to content

Commit

Permalink
web UI: add unicode-bidi: isolate spans around external content
Browse files Browse the repository at this point in the history
fixes RTL/LTR override chars extending into UI and other text. thanks @electricduck, @tantek! for #1666
  • Loading branch information
snarfed committed Jan 5, 2025
1 parent 9c1602e commit fe6da84
Show file tree
Hide file tree
Showing 6 changed files with 16 additions and 15 deletions.
5 changes: 3 additions & 2 deletions models.py
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,8 @@ def user_link(self, name=True, handle=True, pictures=False, proto=None,
a_open = f'<a class="h-card u-author" rel="me" href="{url}" title="{name_str}{dot}{handle_str}">'
a_close = '</a>'

return f'{logo}{a_open}{img}{ellipsize(name_str, chars=40)}{dot}{ellipsize(handle_str, chars=40)}{a_close}'
name_html = f'<span style="unicode-bidi: isolate">{ellipsize(name_str, chars=40)}</span>' if name_str else ''
return f'{logo}{a_open}{img}{name_html}{dot}{ellipsize(handle_str, chars=40)}{a_close}'

def profile_picture(self):
"""Returns the user's profile picture image URL, if available, or None."""
Expand Down Expand Up @@ -1209,7 +1210,7 @@ def actor_link(self, image=True, sized=False, user=None):
{logo}
<a class="h-card u-author" href="{url}" title="{name}">
<img class="profile" src="{img_url}" {'width="32"' if sized else ''}/>
{util.ellipsize(name, chars=40)}
<span style="unicode-bidi: isolate">{util.ellipsize(name, chars=40)}</span>
</a>"""

def get_copy(self, proto):
Expand Down
2 changes: 1 addition & 1 deletion templates/activities.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{% endif %}
{{ obj.phrase|safe }}
{% if obj.url %}<a target="_blank" href="{{ obj.url }}" class="u-url">{% endif %}
{{ obj.content|default('--', true)|striptags|truncate(50) }}
<span style="unicode-bidi: isolate">{{ obj.content|default('--', true)|striptags|truncate(50) }}</span>
{% if obj.url %}</a>{% endif %}
</div>

Expand Down
2 changes: 1 addition & 1 deletion templates/user_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
<nobr title="{{ proto.__name__ }} (bridged): {{ handle }}">
{% if url %} <a rel="me" href="{{ url }}"> {% endif %}
<span class="logo">{{ proto.LOGO_HTML|safe }}</span>
{{ util.ellipsize(handle, chars=40) }}
<span style="unicode-bidi: isolate">{{ util.ellipsize(handle, chars=40) }}</span>
{% if url %}
</a>
{% else %}
Expand Down
2 changes: 1 addition & 1 deletion tests/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_pretty_link(self):

# current user's homepage gets converted to BF user page
self.assert_multiline_equals("""\
<span class="logo" title="Web">🌐</span> <a class="h-card u-author" rel="me" href="https://user.com/" title="user.com">user.com</a>""", common.pretty_link('https://user.com/', user=Web(id='user.com')),
<span class="logo" title="Web">🌐</span> <a class="h-card u-author" rel="me" href="https://user.com/" title="user.com"><span style="unicode-bidi: isolate">user.com</span></a>""", common.pretty_link('https://user.com/', user=Web(id='user.com')),
ignore_blanks=True)

def test_redirect_wrap_empty(self):
Expand Down
4 changes: 2 additions & 2 deletions tests/test_dms.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
}
ALICE_CONFIRMATION_CONTENT = """Got it! We'll send <a class="h-card u-author" rel="me" href="web:other:bob" title="other:handle:bob">other:handle:bob</a> a message and say that you hope they'll enable the bridge. Fingers crossed!"""
ALICE_REQUEST_CONTENT = """\
<p>Hi! <a class="h-card u-author" rel="me" href="web:other:efake:alice" title="efake:handle:alice &middot; other:handle:efake:handle:alice">efake:handle:alice &middot; other:handle:efake:handle:alice</a> is using Bridgy Fed to bridge their account from efake-phrase into other-phrase, and they'd like to follow you. You can bridge your account into efake-phrase by following this account. <a href="https://fed.brid.gy/docs">See the docs</a> for more information.
<p>Hi! <a class="h-card u-author" rel="me" href="web:other:efake:alice" title="efake:handle:alice &middot; other:handle:efake:handle:alice"><span style="unicode-bidi: isolate">efake:handle:alice</span> &middot; other:handle:efake:handle:alice</a> is using Bridgy Fed to bridge their account from efake-phrase into other-phrase, and they'd like to follow you. You can bridge your account into efake-phrase by following this account. <a href="https://fed.brid.gy/docs">See the docs</a> for more information.
<p>If you do nothing, your account won't be bridged, and users on efake-phrase won't be able to see or interact with you.
<p>Bridgy Fed will only send you this message once."""

Expand Down Expand Up @@ -305,7 +305,7 @@ def test_receive_prompt_already_bridged(self):

obj = Object(our_as1=DM_EFAKE_ALICE_REQUESTS_OTHER_BOB)
self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))
self.assert_replied(OtherFake, alice, '?', """<a class="h-card u-author" rel="me" href="web:efake:other:bob" title="other:handle:bob &middot; efake:handle:other:handle:bob">other:handle:bob &middot; efake:handle:other:handle:bob</a> is already bridged into efake-phrase.""")
self.assert_replied(OtherFake, alice, '?', """<a class="h-card u-author" rel="me" href="web:efake:other:bob" title="other:handle:bob &middot; efake:handle:other:handle:bob"><span style="unicode-bidi: isolate">other:handle:bob</span> &middot; efake:handle:other:handle:bob</a> is already bridged into efake-phrase.""")
self.assertEqual([], OtherFake.sent)

def test_receive_prompt_already_requested(self):
Expand Down
16 changes: 8 additions & 8 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,24 +191,24 @@ def test_user_link_page_path(self):

def test_user_link_pictures_true(self):
self.assert_multiline_equals(
'<span class="logo" title="Web">🌐</span> <a class="h-card u-author" rel="me" href="https://y.za/" title="y.za">y.za</a>',
'<span class="logo" title="Web">🌐</span> <a class="h-card u-author" rel="me" href="https://y.za/" title="y.za"><span style="unicode-bidi: isolate">y.za</span></a>',
self.user.user_link(pictures=True, handle=False))

self.user.obj = Object(id='a', as2=ACTOR)
self.assert_multiline_equals(
'<span class="logo" title="Web">🌐</span> <a class="h-card u-author" rel="me" href="https://y.za/" title="Mrs. ☕ Foo"><img src="https://user.com/me.jpg" class="profile"> Mrs. ☕ Foo</a>',
'<span class="logo" title="Web">🌐</span> <a class="h-card u-author" rel="me" href="https://y.za/" title="Mrs. ☕ Foo"><img src="https://user.com/me.jpg" class="profile"> <span style="unicode-bidi: isolate">Mrs. ☕ Foo</span></a>',
self.user.user_link(pictures=True, handle=False))

def test_user_link_pictures_false(self):
self.user.obj = Object(id='a', as2=ACTOR)
self.assert_multiline_equals(
'<a class="h-card u-author" rel="me" href="https://y.za/" title="Mrs. ☕ Foo">Mrs. ☕ Foo</a>',
'<a class="h-card u-author" rel="me" href="https://y.za/" title="Mrs. ☕ Foo"><span style="unicode-bidi: isolate">Mrs. ☕ Foo</span></a>',
self.user.user_link(pictures=False, handle=False))

def test_user_link_handle_true(self):
self.user.obj = Object(id='a', as2=ACTOR)
self.assert_multiline_equals(
'<a class="h-card u-author" rel="me" href="https://y.za/" title="Mrs. ☕ Foo &middot; y.za">Mrs. ☕ Foo &middot; y.za</a>',
'<a class="h-card u-author" rel="me" href="https://y.za/" title="Mrs. ☕ Foo &middot; y.za"><span style="unicode-bidi: isolate">Mrs. ☕ Foo</span> &middot; y.za</a>',
self.user.user_link(pictures=False, handle=True))

def test_user_link_name_false(self):
Expand All @@ -225,13 +225,13 @@ def test_user_link_dont_duplicate_handle_as_name(self):
def test_user_link_proto(self):
self.user.obj = Object(id='y.za', as2=ACTOR)
self.assert_multiline_equals(
'<a class="h-card u-author" rel="me" href="web:fake:y.za" title="Mrs. ☕ Foo &middot; fake:handle:y.za">Mrs. ☕ Foo &middot; fake:handle:y.za</a>',
'<a class="h-card u-author" rel="me" href="web:fake:y.za" title="Mrs. ☕ Foo &middot; fake:handle:y.za"><span style="unicode-bidi: isolate">Mrs. ☕ Foo</span> &middot; fake:handle:y.za</a>',
self.user.user_link(proto=Fake, handle=True))

def test_user_link_proto_fallback(self):
self.user.obj = Object(id='y.za', as2=ACTOR)
self.assert_multiline_equals(
'<a class="h-card u-author" rel="me" href="https://y.za/" title="Mrs. ☕ Foo &middot; @[email protected]">Mrs. ☕ Foo &middot; @[email protected]</a>',
'<a class="h-card u-author" rel="me" href="https://y.za/" title="Mrs. ☕ Foo &middot; @[email protected]"><span style="unicode-bidi: isolate">Mrs. ☕ Foo</span> &middot; @[email protected]</a>',
self.user.user_link(proto=ActivityPub, proto_fallback=True, handle=True))

def test_user_link_proto_not_enabled(self):
Expand Down Expand Up @@ -714,7 +714,7 @@ def test_actor_link(self):
("""\
title="Alice">
<img class="profile" src="http://pic/" />
Alice""", {'actor': {
<span style="unicode-bidi: isolate">Alice</span>""", {'actor': {
'name': 'Alice',
'icon': {'type': 'Image', 'url': 'http://pic'},
}}),
Expand Down Expand Up @@ -763,7 +763,7 @@ def test_actor_link_sized(self):
self.assert_multiline_equals("""\
<a class="h-card u-author" href="" title="Alice">
<img class="profile" src="foo.jpg" width="32"/>
Alice
<span style="unicode-bidi: isolate">Alice</span>
</a>""", obj.actor_link(sized=True), ignore_blanks=True)

def test_actor_link_composite_url(self):
Expand Down

0 comments on commit fe6da84

Please sign in to comment.