Add OutputPage::wrapWikiTextAsInterface() to safely wrap wikitext
authorC. Scott Ananian <cscott@cscott.net>
Thu, 27 Sep 2018 15:04:45 +0000 (11:04 -0400)
committerC. Scott Ananian <cscott@cscott.net>
Wed, 17 Oct 2018 03:39:43 +0000 (23:39 -0400)
This patch introduces a new method,
OutputPage::wrapWikiTextAsInterface(), which wraps the result of
OutputPage::addWikiTextAsInterface() in a tidy and robust way that
won't break if the wrapped message contains double newlines, extra
</div>, or other nasties.

This replaces a common unsafe pattern:
  $output->addWikiText( '<div class="..."' .... '</div>' );

Bug: T205624
Change-Id: I1040c7cf0ec1f5c4bef7c06d4486f50d85f2dc0f

includes/OutputPage.php
tests/phpunit/includes/OutputPageTest.php

index cde92e8..a5f5fab 100644 (file)
@@ -1793,6 +1793,29 @@ class OutputPage extends ContextSource {
                $this->addWikiTextTitleInternal( $text, $title, $linestart, /*tidy*/true, /*interface*/true );
        }
 
                $this->addWikiTextTitleInternal( $text, $title, $linestart, /*tidy*/true, /*interface*/true );
        }
 
+       /**
+        * Convert wikitext *in the user interface language* to HTML and
+        * add it to the buffer with a `<div class="$wrapperClass">`
+        * wrapper.  The result will not be language-converted, as user
+        * interface messages as already localized into a specific
+        * variant.  The $text will be parsed in start-of-line context.
+        * Output will be tidy.
+        *
+        * @param string $wrapperClass The class attribute value for the <div>
+        *   wrapper in the output HTML
+        * @param string $text Wikitext in the user interface language
+        * @since 1.32
+        */
+       public function wrapWikiTextAsInterface(
+               $wrapperClass, $text
+       ) {
+               $this->addWikiTextTitleInternal(
+                       $text, $this->getTitle(),
+                       /*linestart*/true, /*tidy*/true, /*interface*/true,
+                       $wrapperClass
+               );
+       }
+
        /**
         * Convert wikitext *in the page content language* to HTML and add
         * it to the buffer.  The result with be language-converted to the
        /**
         * Convert wikitext *in the page content language* to HTML and add
         * it to the buffer.  The result with be language-converted to the
@@ -1904,10 +1927,12 @@ class OutputPage extends ContextSource {
         *             since 1.32; all wikitext should be tidied.
         * @param bool $interface Whether it is an interface message
         *   (for example disables conversion)
         *             since 1.32; all wikitext should be tidied.
         * @param bool $interface Whether it is an interface message
         *   (for example disables conversion)
+        * @param string $wrapperClass if not empty, wraps the output in
+        *   a `<div class="$wrapperClass">`
         * @private
         */
        private function addWikiTextTitleInternal(
         * @private
         */
        private function addWikiTextTitleInternal(
-               $text, Title $title, $linestart, $tidy, $interface
+               $text, Title $title, $linestart, $tidy, $interface, $wrapperClass = null
        ) {
                global $wgParser;
 
        ) {
                global $wgParser;
 
@@ -1924,7 +1949,7 @@ class OutputPage extends ContextSource {
 
                $this->addParserOutput( $parserOutput, [
                        'enableSectionEditLinks' => false,
 
                $this->addParserOutput( $parserOutput, [
                        'enableSectionEditLinks' => false,
-                       'wrapperDivClass' => '',
+                       'wrapperDivClass' => $wrapperClass ?? '',
                ] );
        }
 
                ] );
        }
 
index 53e6f46..211169e 100644 (file)
@@ -1430,6 +1430,7 @@ class OutputPageTest extends MediaWikiTestCase {
         * @dataProvider provideAddWikiText
         * @covers OutputPage::addWikiText
         * @covers OutputPage::addWikiTextAsInterface
         * @dataProvider provideAddWikiText
         * @covers OutputPage::addWikiText
         * @covers OutputPage::addWikiTextAsInterface
+        * @covers OutputPage::wrapWikiTextAsInterface
         * @covers OutputPage::addWikiTextAsContent
         * @covers OutputPage::addWikiTextWithTitle
         * @covers OutputPage::addWikiTextTitle
         * @covers OutputPage::addWikiTextAsContent
         * @covers OutputPage::addWikiTextWithTitle
         * @covers OutputPage::addWikiTextTitle
@@ -1545,6 +1546,21 @@ class OutputPageTest extends MediaWikiTestCase {
                                        '<div class="mw-editintro">' . "Some page\n</div>"
                                ],
                        ],
                                        '<div class="mw-editintro">' . "Some page\n</div>"
                                ],
                        ],
+                       'wrapWikiTextAsInterface' => [
+                               'Simple' => [
+                                       [ 'wrapperClass', 'text' ],
+                                       "<div class=\"wrapperClass\"><p>text\n</p></div>"
+                               ], 'Spurious </div>' => [
+                                       [ 'wrapperClass', 'text</div><div>more' ],
+                                       "<div class=\"wrapperClass\"><p>text</p><div>more\n</div></div>"
+                               ], 'Extra newlines would break <p> wrappers' => [
+                                       [ 'two classes', "1\n\n2\n\n3" ],
+                                       "<div class=\"two classes\"><p>1\n</p><p>2\n</p><p>3\n</p></div>"
+                               ], 'Other unclosed tags' => [
+                                       [ 'error', 'a<b>c<i>d' ],
+                                       "<div class=\"error\"><p>a<b>c<i>d\n</i></b></p></div>"
+                               ],
+                       ],
                ];
 
                // Test all the others on addWikiTextTitle as well
                ];
 
                // Test all the others on addWikiTextTitle as well