bidi-isolate usernames in Linker::userLink
authorMoriel Schottlender <moriel@gmail.com>
Wed, 31 Aug 2016 20:58:05 +0000 (13:58 -0700)
committerMoriel Schottlender <moriel@gmail.com>
Thu, 1 Sep 2016 00:44:06 +0000 (17:44 -0700)
Usernames can be in any script/language and include weak and neutral
characters like parentheses and dashes - these flip and make things
look very weird when displayed in the opposite directionality.

This fix adds <bdi> tags to isolate the username when we output user
links. This will affect displays like user personal tools, history
and diff view.

Also, fixing LogFormatterTestCase::removeSomeHtml() that expected
a very rigid html input (and thus failed with the new <bdi> wrapping)
to use strip_tags() instead.

Change-Id: I2db5f4b7d3a00726461eb6b699fbdf0ecd47a1cb

includes/Linker.php
tests/phpunit/includes/LinkerTest.php
tests/phpunit/includes/logging/LogFormatterTestCase.php

index 2b38a96..f8b1bae 100644 (file)
@@ -993,9 +993,10 @@ class Linker {
                        $page = Title::makeTitle( NS_USER, $userName );
                }
 
+               // Wrap the output with <bdi> tags for directionality isolation
                return self::link(
                        $page,
-                       htmlspecialchars( $altUserName !== false ? $altUserName : $userName ),
+                       '<bdi>' . htmlspecialchars( $altUserName !== false ? $altUserName : $userName ) . '</bdi>',
                        [ 'class' => $classes ]
                );
        }
index 63753f9..3edf99f 100644 (file)
@@ -37,34 +37,34 @@ class LinkerTest extends MediaWikiLangTestCase {
                        [
                                '<a href="/wiki/Special:Contributions/JohnDoe" '
                                        . 'class="mw-userlink mw-anonuserlink" '
-                                       . 'title="Special:Contributions/JohnDoe">JohnDoe</a>',
+                                       . 'title="Special:Contributions/JohnDoe"><bdi>JohnDoe</bdi></a>',
                                0, 'JohnDoe', false,
                        ],
                        [
                                '<a href="/wiki/Special:Contributions/::1" '
                                        . 'class="mw-userlink mw-anonuserlink" '
-                                       . 'title="Special:Contributions/::1">::1</a>',
+                                       . 'title="Special:Contributions/::1"><bdi>::1</bdi></a>',
                                0, '::1', false,
                                'Anonymous with pretty IPv6'
                        ],
                        [
                                '<a href="/wiki/Special:Contributions/0:0:0:0:0:0:0:1" '
                                        . 'class="mw-userlink mw-anonuserlink" '
-                                       . 'title="Special:Contributions/0:0:0:0:0:0:0:1">::1</a>',
+                                       . 'title="Special:Contributions/0:0:0:0:0:0:0:1"><bdi>::1</bdi></a>',
                                0, '0:0:0:0:0:0:0:1', false,
                                'Anonymous with almost pretty IPv6'
                        ],
                        [
                                '<a href="/wiki/Special:Contributions/0000:0000:0000:0000:0000:0000:0000:0001" '
                                        . 'class="mw-userlink mw-anonuserlink" '
-                                       . 'title="Special:Contributions/0000:0000:0000:0000:0000:0000:0000:0001">::1</a>',
+                                       . 'title="Special:Contributions/0000:0000:0000:0000:0000:0000:0000:0001"><bdi>::1</bdi></a>',
                                0, '0000:0000:0000:0000:0000:0000:0000:0001', false,
                                'Anonymous with full IPv6'
                        ],
                        [
                                '<a href="/wiki/Special:Contributions/::1" '
                                        . 'class="mw-userlink mw-anonuserlink" '
-                                       . 'title="Special:Contributions/::1">AlternativeUsername</a>',
+                                       . 'title="Special:Contributions/::1"><bdi>AlternativeUsername</bdi></a>',
                                0, '::1', 'AlternativeUsername',
                                'Anonymous with pretty IPv6 and an alternative username'
                        ],
@@ -73,14 +73,14 @@ class LinkerTest extends MediaWikiLangTestCase {
                        [
                                '<a href="/wiki/Special:Contributions/127.0.0.1" '
                                        . 'class="mw-userlink mw-anonuserlink" '
-                                       . 'title="Special:Contributions/127.0.0.1">127.0.0.1</a>',
+                                       . 'title="Special:Contributions/127.0.0.1"><bdi>127.0.0.1</bdi></a>',
                                0, '127.0.0.1', false,
                                'Anonymous with IPv4'
                        ],
                        [
                                '<a href="/wiki/Special:Contributions/127.0.0.1" '
                                        . 'class="mw-userlink mw-anonuserlink" '
-                                       . 'title="Special:Contributions/127.0.0.1">AlternativeUsername</a>',
+                                       . 'title="Special:Contributions/127.0.0.1"><bdi>AlternativeUsername</bdi></a>',
                                0, '127.0.0.1', 'AlternativeUsername',
                                'Anonymous with IPv4 and an alternative username'
                        ],
index b09e5b1..c289839 100644 (file)
@@ -50,7 +50,7 @@ abstract class LogFormatterTestCase extends MediaWikiLangTestCase {
        private static function removeSomeHtml( $html ) {
                $html = str_replace( '&quot;', '"', $html );
                $html = preg_replace( '/\xE2\x80[\x8E\x8F]/', '', $html ); // Strip lrm/rlm
-               return trim( preg_replace( '/<(a|span)[^>]*>([^<]*)<\/\1>/', '$2', $html ) );
+               return trim( strip_tags( $html ) );
        }
 
        private static function removeApiMetaData( $val ) {