Merge "Pass phpcs-strict on includes/specials/ (2/3)"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Sat, 10 May 2014 22:50:22 +0000 (22:50 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Sat, 10 May 2014 22:50:22 +0000 (22:50 +0000)
33 files changed:
.gitattributes [new file with mode: 0644]
RELEASE-NOTES-1.23
RELEASE-NOTES-1.24
docs/hooks.txt
includes/Article.php
includes/AutoLoader.php
includes/DefaultSettings.php
includes/MagicWord.php
includes/Skin.php
includes/UserMailer.php
includes/api/ApiFeedContributions.php
includes/api/ApiFeedWatchlist.php
includes/content/AbstractContent.php
includes/content/TextContent.php
includes/content/WikitextContent.php
includes/htmlform/HTMLHiddenField.php
includes/installer/Installer.php
includes/installer/WebInstallerPage.php
includes/specials/SpecialBlock.php
includes/specials/SpecialEditWatchlist.php
includes/specials/SpecialNewimages.php
includes/specials/SpecialNewpages.php
includes/specials/SpecialProtectedpages.php
includes/specials/SpecialRevisiondelete.php
includes/specials/SpecialRunJobs.php
includes/specials/SpecialSearch.php
maintenance/generateJsonI18n.php
maintenance/pageExists.php [new file with mode: 0644]
resources/src/mediawiki.api/mediawiki.api.watch.js
skins/common/commonPrint.css
tests/phpunit/includes/content/ContentHandlerTest.php
tests/phpunit/includes/content/CssContentTest.php
tests/phpunit/includes/content/TextContentTest.php

diff --git a/.gitattributes b/.gitattributes
new file mode 100644 (file)
index 0000000..50ca329
--- /dev/null
@@ -0,0 +1 @@
+*.sh eol=lf
index 5326e23..575fdc3 100644 (file)
@@ -516,7 +516,7 @@ Don't forget to always back up your database before upgrading!
 
 See the file UPGRADE for more detailed upgrade instructions.
 
-For notes on 1.21.x and older releases, see HISTORY.
+For notes on 1.22.x and older releases, see HISTORY.
 
 == Online documentation ==
 
index ff73139..1bf308c 100644 (file)
@@ -15,12 +15,17 @@ production.
 === New features in 1.24 ===
 * Added a new hook, "WhatLinksHereProps", to allow extensions to annotate
   WhatLinksHere entries.
+* Added a new hook, "ContentGetParserOutput", to customize parser output for
+  a given content object.
+* Deprecated the hook "ShowRawCssJs", use "ContentGetParserOutput" instead.
 * HTMLForm's HTMLTextField now supports the 'url' type.
 * HTMLForm fields may now be dynamically hidden based on the values of other
   fields in the form.
 * HTMLForm now supports multiple copies of an input field or set of input
   fields, e.g. the form may request "one or more usernames" without having to
   have the user enter delimited list of names into a text field.
+* Added a new hook, "SidebarBeforeOutput", to allow to edit the structure of
+  the sidebar just before its display.
 
 === Bug fixes in 1.24 ===
 * (bug 62258) A bug was fixed in File::getUnscaledThumb when a height
@@ -73,6 +78,10 @@ changes to languages because of Bugzilla reports.
 * RevDel_RevisionItem to RevDelRevisionItem
 * RevDel_RevisionList to RevDelRevisionList
 
+==== Removed classes ====
+* IPBlockForm - Use SpecialBlock directly
+* WatchlistEditor - Use SpecialEditWatchlist directly
+
 == Compatibility ==
 
 MediaWiki 1.24 requires PHP 5.3.2 or later.
@@ -111,7 +120,7 @@ Don't forget to always back up your database before upgrading!
 
 See the file UPGRADE for more detailed upgrade instructions.
 
-For notes on 1.21.x and older releases, see HISTORY.
+For notes on 1.22.x and older releases, see HISTORY.
 
 == Online documentation ==
 
index 688e0cd..d455fd2 100644 (file)
@@ -887,6 +887,19 @@ $title: the Title in question.
 Handler functions that modify $ok should generally return false to prevent further
 hooks from further modifying $ok.
 
+'ContentGetParserOutput': Customize parser output for a given content object,
+called by AbstractContent::getParserOutput. May be used to override the normal
+model-specific rendering of page content.
+$content: The Content to render
+$title: Title of the page, as context
+$revId: The revision ID, as context
+$options: ParserOptions for rendering. To avoid confusing the parser cache,
+the output can only depend on parameters provided to this hook function, not on global state.
+$generateHtml: boolean, indicating whether full HTML should be generated. If false,
+generation of HTML may be skipped, but other information should still be present in the
+ParserOutput object.
+&$output: ParserOutput, to manipulate or replace
+
 'ConvertContent': Called by AbstractContent::convert when a conversion to another
 content model is requested.
 $content: The Content object to be converted.
@@ -2171,7 +2184,7 @@ $title : Current Title object being displayed in search results.
 $article: The article object corresponding to the page
 
 'ShowRawCssJs': Customise the output of raw CSS and JavaScript in page views.
-DEPRECATED, use the ContentHandler facility to handle CSS and JavaScript!
+DEPRECATED, use the ContentGetParserOutput hook instead!
 $text: Text being shown
 $title: Title of the custom script/stylesheet page
 $output: Current OutputPage object
@@ -2226,6 +2239,12 @@ $skin: Skin object
 &$bar: Sidebar contents
 Modify $bar to add or modify sidebar portlets.
 
+'SidebarBeforeOutput': Allows to edit sidebar just before its output by skins.
+$skin Skin object
+&$bar: Sidebar content
+Modify $bar to add or modify sidebar portlets.
+Warning: This hook is run on each display. You should consider to use 'SkinBuildSidebar' that is aggressively cached.
+
 'SkinCopyrightFooter': Allow for site and per-namespace customization of
 copyright notice.
 $title: displayed page title
index 0a4b5ee..3bb1563 100644 (file)
@@ -832,8 +832,9 @@ class Article implements Page {
         * Show a page view for a page formatted as CSS or JavaScript. To be called by
         * Article::view() only.
         *
-        * This is hooked by SyntaxHighlight_GeSHi to do syntax highlighting of these
-        * page views.
+        * This exists mostly to serve the deprecated ShowRawCssJs hook (used to customize these views).
+        * It has been replaced by the ContentGetParserOutput hook, which lets you do the same but with
+        * more flexibility.
         *
         * @param bool $showCacheHint Whether to show a message telling the user
         *   to clear the browser cache (default: true).
index 8e5b872..09f1667 100644 (file)
@@ -952,7 +952,6 @@ $wgAutoloadLocalClasses = array(
        'HTMLBlockedUsersItemSelect' => 'includes/specials/SpecialBlockList.php',
        'ImageListPager' => 'includes/specials/SpecialListfiles.php',
        'ImportReporter' => 'includes/specials/SpecialImport.php',
-       'IPBlockForm' => 'includes/specials/SpecialBlock.php',
        'LinkSearchPage' => 'includes/specials/SpecialLinkSearch.php',
        'ListredirectsPage' => 'includes/specials/SpecialListredirects.php',
        'ListDuplicatedFilesPage' => 'includes/specials/SpecialListDuplicatedFiles.php',
@@ -1063,7 +1062,6 @@ $wgAutoloadLocalClasses = array(
        'WantedFilesPage' => 'includes/specials/SpecialWantedfiles.php',
        'WantedPagesPage' => 'includes/specials/SpecialWantedpages.php',
        'WantedTemplatesPage' => 'includes/specials/SpecialWantedtemplates.php',
-       'WatchlistEditor' => 'includes/specials/SpecialEditWatchlist.php',
        'WithoutInterwikiPage' => 'includes/specials/SpecialWithoutinterwiki.php',
 
        # includes/templates
index 5d35c42..cf94bae 100644 (file)
@@ -2893,11 +2893,6 @@ $wgShowIPinHeader = true;
  */
 $wgSiteNotice = '';
 
-/**
- * A subtitle to add to the tagline, for skins that have it/
- */
-$wgExtraSubtitle = '';
-
 /**
  * If this is set, a "donate" link will appear in the sidebar. Set it to a URL.
  */
index 56786f1..4781667 100644 (file)
@@ -270,7 +270,7 @@ class MagicWord {
         * Allow external reads of TTL array
         *
         * @param int $id
-        * @return array
+        * @return int
         */
        static function getCacheTTL( $id ) {
                if ( array_key_exists( $id, self::$mCacheTTLs ) ) {
index 8300da7..cfa059e 100644 (file)
@@ -1244,6 +1244,8 @@ abstract class Skin extends ContextSource {
                if ( $wgEnableSidebarCache ) {
                        $cachedsidebar = $wgMemc->get( $key );
                        if ( $cachedsidebar ) {
+                               wfRunHooks( 'SidebarBeforeOutput', array( $this, &$cachedsidebar ) );
+
                                wfProfileOut( __METHOD__ );
                                return $cachedsidebar;
                        }
@@ -1257,6 +1259,8 @@ abstract class Skin extends ContextSource {
                        $wgMemc->set( $key, $bar, $wgSidebarCacheExpiry );
                }
 
+               wfRunHooks( 'SidebarBeforeOutput', array( $this, &$bar ) );
+
                wfProfileOut( __METHOD__ );
                return $bar;
        }
index 1ec2792..2885e6a 100644 (file)
@@ -58,7 +58,7 @@ class MailAddress {
                if ( $this->address ) {
                        if ( $this->name != '' && !wfIsWindows() ) {
                                global $wgEnotifUseRealName;
-                               $name = ( $wgEnotifUseRealName && $this->realName ) ? $this->realName : $this->name;
+                               $name = ( $wgEnotifUseRealName && $this->realName !== '' ) ? $this->realName : $this->name;
                                $quoted = UserMailer::quotedPrintable( $name );
                                if ( strpos( $quoted, '.' ) !== false || strpos( $quoted, ',' ) !== false ) {
                                        $quoted = '"' . $quoted . '"';
@@ -761,7 +761,8 @@ class EmailNotification {
                        $keys['$PAGEEDITOR_EMAIL'] = wfMessage( 'noemailtitle' )->inContentLanguage()->text();
 
                } else {
-                       $keys['$PAGEEDITOR'] = $wgEnotifUseRealName ? $this->editor->getRealName() : $this->editor->getName();
+                       $keys['$PAGEEDITOR'] = $wgEnotifUseRealName && $this->editor->getRealName() !== ''
+                               ? $this->editor->getRealName() : $this->editor->getName();
                        $emailPage = SpecialPage::getSafeTitleFor( 'Emailuser', $this->editor->getName() );
                        $keys['$PAGEEDITOR_EMAIL'] = $emailPage->getCanonicalURL();
                }
@@ -868,7 +869,8 @@ class EmailNotification {
                        array( '$WATCHINGUSERNAME',
                                '$PAGEEDITDATE',
                                '$PAGEEDITTIME' ),
-                       array( $wgEnotifUseRealName ? $watchingUser->getRealName() : $watchingUser->getName(),
+                       array( $wgEnotifUseRealName && $watchingUser->getRealName() !== ''
+                                       ? $watchingUser->getRealName() : $watchingUser->getName(),
                                $wgContLang->userDate( $this->timestamp, $watchingUser ),
                                $wgContLang->userTime( $this->timestamp, $watchingUser ) ),
                        $this->body );
index 6f7121b..afd5a13 100644 (file)
@@ -112,7 +112,7 @@ class ApiFeedContributions extends ApiBase {
                        return new FeedItem(
                                $title->getPrefixedText(),
                                $this->feedItemDesc( $revision ),
-                               $title->getFullURL(),
+                               $title->getFullURL( array( 'diff' => $revision->getId() ) ),
                                $date,
                                $this->feedItemAuthor( $revision ),
                                $comments
index 545b94d..64c3eec 100644 (file)
@@ -34,7 +34,6 @@
 class ApiFeedWatchlist extends ApiBase {
 
        private $watchlistModule = null;
-       private $linkToDiffs = false;
        private $linkToSections = false;
 
        /**
@@ -73,7 +72,7 @@ class ApiFeedWatchlist extends ApiBase {
                                'meta' => 'siteinfo',
                                'siprop' => 'general',
                                'list' => 'watchlist',
-                               'wlprop' => 'title|user|comment|timestamp',
+                               'wlprop' => 'title|user|comment|timestamp|ids',
                                'wldir' => 'older', // reverse order - from newest to oldest
                                'wlend' => $endTime, // stop at this time
                                'wllimit' => min( 50, $wgFeedLimit )
@@ -95,12 +94,6 @@ class ApiFeedWatchlist extends ApiBase {
                                $fauxReqArr['wltype'] = $params['wltype'];
                        }
 
-                       // Support linking to diffs instead of article
-                       if ( $params['linktodiffs'] ) {
-                               $this->linkToDiffs = true;
-                               $fauxReqArr['wlprop'] .= '|ids';
-                       }
-
                        // Support linking directly to sections when possible
                        // (possible only if section name is present in comment)
                        if ( $params['linktosections'] ) {
@@ -173,7 +166,7 @@ class ApiFeedWatchlist extends ApiBase {
        private function createFeedItem( $info ) {
                $titleStr = $info['title'];
                $title = Title::newFromText( $titleStr );
-               if ( $this->linkToDiffs && isset( $info['revid'] ) ) {
+               if ( isset( $info['revid'] ) ) {
                        $titleUrl = $title->getFullURL( array( 'diff' => $info['revid'] ) );
                } else {
                        $titleUrl = $title->getFullURL();
@@ -225,7 +218,6 @@ class ApiFeedWatchlist extends ApiBase {
                                ApiBase::PARAM_MIN => 1,
                                ApiBase::PARAM_MAX => 72,
                        ),
-                       'linktodiffs' => false,
                        'linktosections' => false,
                );
                if ( $flags ) {
@@ -254,7 +246,6 @@ class ApiFeedWatchlist extends ApiBase {
                return array(
                        'feedformat' => 'The format of the feed',
                        'hours' => 'List pages modified within this many hours from now',
-                       'linktodiffs' => 'Link to change differences instead of article pages',
                        'linktosections' => 'Link directly to changed sections if possible',
                        'allrev' => $wldescr['allrev'],
                        'wlowner' => $wldescr['owner'],
@@ -279,7 +270,7 @@ class ApiFeedWatchlist extends ApiBase {
        public function getExamples() {
                return array(
                        'api.php?action=feedwatchlist',
-                       'api.php?action=feedwatchlist&allrev=&linktodiffs=&hours=6'
+                       'api.php?action=feedwatchlist&allrev=&hours=6'
                );
        }
 
index 77d3542..8ba43f6 100644 (file)
@@ -450,4 +450,69 @@ abstract class AbstractContent implements Content {
 
                return $result;
        }
+
+       /**
+        * Returns a ParserOutput object containing information derived from this content.
+        * Most importantly, unless $generateHtml was false, the return value contains an
+        * HTML representation of the content.
+        *
+        * Subclasses that want to control the parser output may override this, but it is
+        * preferred to override fillParserOutput() instead.
+        *
+        * Subclasses that override getParserOutput() itself should take care to call the
+        * ContentGetParserOutput hook.
+        *
+        * @since 1.24
+        *
+        * @param Title $title Context title for parsing
+        * @param int|null $revId Revision ID (for {{REVISIONID}})
+        * @param ParserOptions|null $options Parser options
+        * @param bool $generateHtml Whether or not to generate HTML
+        *
+        * @return ParserOutput Containing information derived from this content.
+        */
+       public function getParserOutput( Title $title, $revId = null,
+               ParserOptions $options = null, $generateHtml = true
+       ) {
+               if ( $options === null ) {
+                       $options = $this->getContentHandler()->makeParserOptions( 'canonical' );
+               }
+
+               $po = new ParserOutput();
+
+               if ( wfRunHooks( 'ContentGetParserOutput',
+                       array( $this, $title, $revId, $options, $generateHtml, &$po ) ) ) {
+
+                       $this->fillParserOutput( $title, $revId, $options, $generateHtml, $po );
+               }
+
+               return $po;
+       }
+
+       /**
+        * Fills the provided ParserOutput with information derived from the content.
+        * Unless $generateHtml was false, this includes an HTML representation of the content.
+        *
+        * This is called by getParserOutput() after consulting the ContentGetParserOutput hook.
+        * Subclasses are expected to override this method (or getParserOutput(), if need be).
+        * Subclasses of TextContent should generally override getHtml() instead.
+        *
+        * This placeholder implementation always throws an exception.
+        *
+        * @since 1.24
+        *
+        * @param Title $title Context title for parsing
+        * @param int|null $revId Revision ID (for {{REVISIONID}})
+        * @param ParserOptions|null $options Parser options
+        * @param bool $generateHtml Whether or not to generate HTML
+        * @param ParserOutput &$output The output object to fill (reference).
+        *
+        * @throws MWException
+        */
+       protected function fillParserOutput( Title $title, $revId,
+               ParserOptions $options, $generateHtml, ParserOutput &$output
+       ) {
+               // Don't make abstract, so subclasses that override getParserOutput() directly don't fail.
+               throw new MWException( 'Subclasses of AbstractContent must override fillParserOutput!' );
+       }
 }
index 4c95d3c..b772f17 100644 (file)
@@ -201,30 +201,30 @@ class TextContent extends AbstractContent {
        }
 
        /**
-        * Returns a generic ParserOutput object, wrapping the HTML returned by
-        * getHtml().
+        * Fills the provided ParserOutput object with information derived from the content.
+        * Unless $generateHtml was false, this includes an HTML representation of the content
+        * provided by getHtml().
+        *
+        * For content models listed in $wgTextModelsToParse, this method will call the MediaWiki
+        * wikitext parser on the text to extract any (wikitext) links, magic words, etc.
+        *
+        * Subclasses may override this to provide custom content processing.
+        * For custom HTML generation alone, it is sufficient to override getHtml().
         *
         * @param Title $title Context title for parsing
         * @param int $revId Revision ID (for {{REVISIONID}})
         * @param ParserOptions $options Parser options
         * @param bool $generateHtml Whether or not to generate HTML
-        *
-        * @return ParserOutput Representing the HTML form of the text.
+        * @param ParserOutput $output The output object to fill (reference).
         */
-       public function getParserOutput( Title $title, $revId = null,
-               ParserOptions $options = null, $generateHtml = true ) {
+       protected function fillParserOutput( Title $title, $revId,
+               ParserOptions $options, $generateHtml, ParserOutput &$output
+       ) {
                global $wgParser, $wgTextModelsToParse;
 
-               if ( !$options ) {
-                       //NOTE: use canonical options per default to produce cacheable output
-                       $options = $this->getContentHandler()->makeParserOptions( 'canonical' );
-               }
-
                if ( in_array( $this->getModel(), $wgTextModelsToParse ) ) {
-                       // parse just to get links etc into the database
-                       $po = $wgParser->parse( $this->getNativeData(), $title, $options, true, true, $revId );
-               } else {
-                       $po = new ParserOutput();
+                       // parse just to get links etc into the database, HTML is replaced below.
+                       $output = $wgParser->parse( $this->getNativeData(), $title, $options, true, true, $revId );
                }
 
                if ( $generateHtml ) {
@@ -233,18 +233,16 @@ class TextContent extends AbstractContent {
                        $html = '';
                }
 
-               $po->setText( $html );
-
-               return $po;
+               $output->setText( $html );
        }
 
        /**
         * Generates an HTML version of the content, for display. Used by
-        * getParserOutput() to construct a ParserOutput object.
+        * fillParserOutput() to provide HTML for the ParserOutput object.
         *
         * Subclasses may override this to provide a custom HTML rendering.
         * If further information is to be derived from the content (such as
-        * categories), the getParserOutput() method can be overridden instead.
+        * categories), the fillParserOutput() method can be overridden instead.
         *
         * For backwards-compatibility, this default implementation just calls
         * getHighlightHtml().
index dba0205..ccea916 100644 (file)
@@ -311,41 +311,33 @@ class WikitextContent extends TextContent {
         * Returns a ParserOutput object resulting from parsing the content's text
         * using $wgParser.
         *
-        * @since 1.21
-        *
         * @param Title $title
         * @param int $revId Revision to pass to the parser (default: null)
         * @param ParserOptions $options (default: null)
         * @param bool $generateHtml (default: true)
-        *
-        * @return ParserOutput Representing the HTML form of the text
+        * @param &$output ParserOutput representing the HTML form of the text,
+        *           may be manipulated or replaced.
         */
-       public function getParserOutput( Title $title, $revId = null,
-               ParserOptions $options = null, $generateHtml = true ) {
+       protected function fillParserOutput( Title $title, $revId,
+                       ParserOptions $options, $generateHtml, ParserOutput &$output
+       ) {
                global $wgParser;
 
-               if ( !$options ) {
-                       //NOTE: use canonical options per default to produce cacheable output
-                       $options = $this->getContentHandler()->makeParserOptions( 'canonical' );
-               }
-
                list( $redir, $text ) = $this->getRedirectTargetAndText();
-               $po = $wgParser->parse( $text, $title, $options, true, true, $revId );
+               $output = $wgParser->parse( $text, $title, $options, true, true, $revId );
 
                // Add redirect indicator at the top
                if ( $redir ) {
                        // Make sure to include the redirect link in pagelinks
-                       $po->addLink( $redir );
+                       $output->addLink( $redir );
                        if ( $generateHtml ) {
                                $chain = $this->getRedirectChain();
-                               $po->setText(
+                               $output->setText(
                                        Article::getRedirectHeaderHtml( $title->getPageLanguage(), $chain, false ) .
-                                       $po->getText()
+                                       $output->getText()
                                );
                        }
                }
-
-               return $po;
        }
 
        /**
index 003ccfe..6ea95ed 100644 (file)
@@ -5,7 +5,7 @@ class HTMLHiddenField extends HTMLFormField {
                parent::__construct( $params );
 
                # Per HTML5 spec, hidden fields cannot be 'required'
-               # http://dev.w3.org/html5/spec/states-of-the-type-attribute.html#hidden-state
+               # http://www.w3.org/TR/html5/forms.html#hidden-state-%28type=hidden%29
                unset( $this->mParams['required'] );
        }
 
index 372091a..85717c5 100644 (file)
@@ -200,7 +200,7 @@ abstract class Installer {
                '_NamespaceType' => 'site-name',
                '_AdminName' => '', // will be set later, when the user selects language
                '_AdminPassword' => '',
-               '_AdminPassword2' => '',
+               '_AdminPasswordConfirm' => '',
                '_AdminEmail' => '',
                '_Subscribe' => false,
                '_SkipOptional' => 'continue',
index 3b3473b..4de7f06 100644 (file)
@@ -790,7 +790,7 @@ class WebInstaller_Name extends WebInstallerPage {
                                'label' => 'config-admin-password',
                        ) ) .
                        $this->parent->getPasswordBox( array(
-                               'var' => '_AdminPassword2',
+                               'var' => '_AdminPasswordConfirm',
                                'label' => 'config-admin-password-confirm'
                        ) ) .
                        $this->parent->getTextBox( array(
@@ -829,7 +829,7 @@ class WebInstaller_Name extends WebInstallerPage {
        public function submit() {
                $retVal = true;
                $this->parent->setVarsFromRequest( array( 'wgSitename', '_NamespaceType',
-                       '_AdminName', '_AdminPassword', '_AdminPassword2', '_AdminEmail',
+                       '_AdminName', '_AdminPassword', '_AdminPasswordConfirm', '_AdminEmail',
                        '_Subscribe', '_SkipOptional', 'wgMetaNamespace' ) );
 
                // Validate site name
@@ -911,7 +911,7 @@ class WebInstaller_Name extends WebInstallerPage {
                        # $user->getPasswordValidity just checks for $wgMinimalPasswordLength.
                        # This message is more specific and helpful.
                        $msg = 'config-admin-password-blank';
-               } elseif ( $pwd !== $this->getVar( '_AdminPassword2' ) ) {
+               } elseif ( $pwd !== $this->getVar( '_AdminPasswordConfirm' ) ) {
                        $msg = 'config-admin-password-mismatch';
                } elseif ( $valid !== true ) {
                        $msg = $valid;
@@ -919,7 +919,7 @@ class WebInstaller_Name extends WebInstallerPage {
                if ( $msg !== false ) {
                        call_user_func_array( array( $this->parent, 'showError' ), (array)$msg );
                        $this->setVar( '_AdminPassword', '' );
-                       $this->setVar( '_AdminPassword2', '' );
+                       $this->setVar( '_AdminPasswordConfirm', '' );
                        $retVal = false;
                }
 
index 007850b..8c46a93 100644 (file)
@@ -130,7 +130,6 @@ class SpecialBlock extends FormSpecialPage {
                        'Target' => array(
                                'type' => 'text',
                                'label-message' => 'ipaddressorusername',
-                               'tabindex' => '1',
                                'id' => 'mw-bi-target',
                                'size' => '45',
                                'autofocus' => true,
@@ -141,7 +140,6 @@ class SpecialBlock extends FormSpecialPage {
                                'type' => !count( $suggestedDurations ) ? 'text' : 'selectorother',
                                'label-message' => 'ipbexpiry',
                                'required' => true,
-                               'tabindex' => '2',
                                'options' => $suggestedDurations,
                                'other' => $this->msg( 'ipbother' )->text(),
                                'default' => $this->msg( 'ipb-default-expiry' )->inContentLanguage()->text(),
@@ -977,7 +975,3 @@ class SpecialBlock extends FormSpecialPage {
                return 'users';
        }
 }
-
-# BC @since 1.18
-class IPBlockForm extends SpecialBlock {
-}
index 409a6ae..86433ca 100644 (file)
@@ -718,10 +718,6 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
        }
 }
 
-# B/C since 1.18
-class WatchlistEditor extends SpecialEditWatchlist {
-}
-
 /**
  * Extend HTMLForm purely so we can have a more sane way of getting the section headers
  */
index 6891b16..147d176 100644 (file)
@@ -76,7 +76,7 @@ class NewFilesPager extends ReverseChronologicalPager {
        /**
         * @var ImageGallery
         */
-       var $gallery;
+       protected $gallery;
 
        function __construct( IContextSource $context, $par = null ) {
                $this->like = $context->getRequest()->getText( 'like' );
index 66ec693..505a1ec 100644 (file)
  * @ingroup SpecialPage
  */
 class SpecialNewpages extends IncludableSpecialPage {
-       // Stored objects
-
        /**
         * @var FormOptions
         */
        protected $opts;
        protected $customFilters;
 
-       // Some internal settings
        protected $showNavigation = false;
 
        public function __construct() {
@@ -394,7 +391,8 @@ class SpecialNewpages extends IncludableSpecialPage {
                        $oldTitleText = $this->msg( 'rc-old-title' )->params( $oldTitleText )->escaped();
                }
 
-               return "<li{$css}>{$time} {$dm}{$plink} {$hist} {$dm}{$length} {$dm}{$ulink} {$comment} {$tagDisplay} {$oldTitleText}</li>\n";
+               return "<li{$css}>{$time} {$dm}{$plink} {$hist} {$dm}{$length} "
+                       . "{$dm}{$ulink} {$comment} {$tagDisplay} {$oldTitleText}</li>\n";
        }
 
        /**
index 6edf2c0..7554e37 100644 (file)
@@ -27,7 +27,6 @@
  * @ingroup SpecialPage
  */
 class SpecialProtectedpages extends SpecialPage {
-
        protected $IdLevel = 'level';
        protected $IdType = 'type';
 
@@ -438,7 +437,11 @@ class ProtectedPagesPager extends TablePager {
                                        );
                                } else {
                                        $username = UserCache::singleton()->getProp( $value, 'name' );
-                                       if ( LogEventsList::userCanBitfield( $row->log_deleted, LogPage::DELETED_USER, $this->getUser() ) ) {
+                                       if ( LogEventsList::userCanBitfield(
+                                               $row->log_deleted,
+                                               LogPage::DELETED_USER,
+                                               $this->getUser()
+                                       ) ) {
                                                if ( $username === false ) {
                                                        $formatted = htmlspecialchars( $value );
                                                } else {
@@ -473,7 +476,11 @@ class ProtectedPagesPager extends TablePager {
                                                $this->msg( 'protectedpages-unknown-reason' )->escaped()
                                        );
                                } else {
-                                       if ( LogEventsList::userCanBitfield( $row->log_deleted, LogPage::DELETED_COMMENT, $this->getUser() ) ) {
+                                       if ( LogEventsList::userCanBitfield(
+                                               $row->log_deleted,
+                                               LogPage::DELETED_COMMENT,
+                                               $this->getUser()
+                                       ) ) {
                                                $formatted = Linker::formatComment( $value !== null ? $value : '' );
                                        } else {
                                                $formatted = $this->msg( 'rev-deleted-comment' )->escaped();
index 3cda8c6..797f588 100644 (file)
@@ -132,7 +132,9 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
                // $this->ids = array_map( 'intval', $this->ids );
                $this->ids = array_unique( array_filter( $this->ids ) );
 
-               if ( $request->getVal( 'action' ) == 'historysubmit' || $request->getVal( 'action' ) == 'revisiondelete' ) {
+               if ( $request->getVal( 'action' ) == 'historysubmit'
+                       || $request->getVal( 'action' ) == 'revisiondelete'
+               ) {
                        // For show/hide form submission from history page
                        // Since we are access through index.php?title=XXX&action=historysubmit
                        // getFullTitle() will contain the target title and not our title
@@ -162,7 +164,11 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
                $this->mIsAllowed = $user->isAllowed( RevisionDeleter::getRestriction( $this->typeName ) );
 
                # Allow the list type to adjust the passed target
-               $this->targetObj = RevisionDeleter::suggestTarget( $this->typeName, $this->targetObj, $this->ids );
+               $this->targetObj = RevisionDeleter::suggestTarget(
+                       $this->typeName,
+                       $this->targetObj,
+                       $this->ids
+               );
 
                $this->otherReason = $request->getVal( 'wpReason' );
                # We need a target page!
@@ -277,7 +283,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
 
        /**
         * Show a deleted file version requested by the visitor.
-        * TODO Mostly copied from Special:Undelete. Refactor.
+        * @todo Mostly copied from Special:Undelete. Refactor.
         * @param string $archiveName
         */
        protected function tryShowFile( $archiveName ) {
@@ -326,7 +332,9 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
                # a user without appropriate permissions can toddle off and
                # nab the image, and Squid will serve it
                $this->getRequest()->response()->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
-               $this->getRequest()->response()->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
+               $this->getRequest()->response()->header(
+                       'Cache-Control: no-cache, no-store, max-age=0, must-revalidate'
+               );
                $this->getRequest()->response()->header( 'Pragma: no-cache' );
 
                $key = $oimage->getStorageKey();
@@ -364,14 +372,18 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
                $numRevisions = 0;
                // Live revisions...
                $list = $this->getList();
+               // @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
                for ( $list->reset(); $list->current(); $list->next() ) {
+                       // @codingStandardsIgnoreEnd
                        $item = $list->current();
+
                        if ( !$item->canView() ) {
                                if ( !$this->submitClicked ) {
                                        throw new PermissionsError( 'suppressrevision' );
                                }
                                $userAllowed = false;
                        }
+
                        $numRevisions++;
                        $this->getOutput()->addHTML( $item->getHTML() );
                }
@@ -413,7 +425,12 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
                                                Xml::label( $this->msg( 'revdelete-otherreason' )->text(), 'wpReason' ) .
                                        '</td>' .
                                        '<td class="mw-input">' .
-                                               Xml::input( 'wpReason', 60, $this->otherReason, array( 'id' => 'wpReason', 'maxlength' => 100 ) ) .
+                                               Xml::input(
+                                                       'wpReason',
+                                                       60,
+                                                       $this->otherReason,
+                                                       array( 'id' => 'wpReason', 'maxlength' => 100 )
+                                               ) .
                                        '</td>' .
                                "</tr><tr>\n" .
                                        '<td></td>' .
@@ -454,10 +471,15 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
         */
        protected function addUsageText() {
                // Messages: revdelete-text-text, revdelete-text-file, logdelete-text
-               $this->getOutput()->wrapWikiMsg( "<strong>$1</strong>\n$2", $this->typeLabels['text'], 'revdelete-text-others' );
+               $this->getOutput()->wrapWikiMsg(
+                       "<strong>$1</strong>\n$2", $this->typeLabels['text'],
+                       'revdelete-text-others'
+               );
+
                if ( $this->getUser()->isAllowed( 'suppressrevision' ) ) {
                        $this->getOutput()->addWikiMsg( 'revdelete-suppress-text' );
                }
+
                if ( $this->mIsAllowed ) {
                        $this->getOutput()->addWikiMsg( 'revdelete-confirm' );
                }
@@ -473,26 +495,38 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
                if ( $list->length() == 1 ) {
                        $list->reset();
                        $bitfield = $list->current()->getBits(); // existing field
+
                        if ( $this->submitClicked ) {
                                $bitfield = RevisionDeleter::extractBitfield( $this->extractBitParams(), $bitfield );
                        }
+
                        foreach ( $this->checks as $item ) {
                                // Messages: revdelete-hide-text, revdelete-hide-image, revdelete-hide-name,
                                // revdelete-hide-comment, revdelete-hide-user, revdelete-hide-restricted
                                list( $message, $name, $field ) = $item;
-                               $innerHTML = Xml::checkLabel( $this->msg( $message )->text(), $name, $name, $bitfield & $field );
+                               $innerHTML = Xml::checkLabel(
+                                       $this->msg( $message )->text(),
+                                       $name,
+                                       $name,
+                                       $bitfield & $field
+                               );
+
                                if ( $field == Revision::DELETED_RESTRICTED ) {
                                        $innerHTML = "<b>$innerHTML</b>";
                                }
+
                                $line = Xml::tags( 'td', array( 'class' => 'mw-input' ), $innerHTML );
                                $html .= "<tr>$line</tr>\n";
                        }
                } else {
                        // Otherwise, use tri-state radios
                        $html .= '<tr>';
-                       $html .= '<th class="mw-revdel-checkbox">' . $this->msg( 'revdelete-radio-same' )->escaped() . '</th>';
-                       $html .= '<th class="mw-revdel-checkbox">' . $this->msg( 'revdelete-radio-unset' )->escaped() . '</th>';
-                       $html .= '<th class="mw-revdel-checkbox">' . $this->msg( 'revdelete-radio-set' )->escaped() . '</th>';
+                       $html .= '<th class="mw-revdel-checkbox">'
+                               . $this->msg( 'revdelete-radio-same' )->escaped() . '</th>';
+                       $html .= '<th class="mw-revdel-checkbox">'
+                               . $this->msg( 'revdelete-radio-unset' )->escaped() . '</th>';
+                       $html .= '<th class="mw-revdel-checkbox">'
+                               . $this->msg( 'revdelete-radio-set' )->escaped() . '</th>';
                        $html .= "<th></th></tr>\n";
                        foreach ( $this->checks as $item ) {
                                // Messages: revdelete-hide-text, revdelete-hide-image, revdelete-hide-name,
@@ -535,16 +569,20 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
                        return false;
                }
                $bitParams = $this->extractBitParams();
-               $listReason = $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' ); // from dropdown
+               // from dropdown
+               $listReason = $this->getRequest()->getText( 'wpRevDeleteReasonList', 'other' );
                $comment = $listReason;
                if ( $comment != 'other' && $this->otherReason != '' ) {
                        // Entry from drop down menu + additional comment
-                       $comment .= $this->msg( 'colon-separator' )->inContentLanguage()->text() . $this->otherReason;
+                       $comment .= $this->msg( 'colon-separator' )->inContentLanguage()->text()
+                               . $this->otherReason;
                } elseif ( $comment == 'other' ) {
                        $comment = $this->otherReason;
                }
                # Can the user set this field?
-               if ( $bitParams[Revision::DELETED_RESTRICTED] == 1 && !$this->getUser()->isAllowed( 'suppressrevision' ) ) {
+               if ( $bitParams[Revision::DELETED_RESTRICTED] == 1
+                       && !$this->getUser()->isAllowed( 'suppressrevision' )
+               ) {
                        throw new PermissionsError( 'suppressrevision' );
                }
                # If the save went through, go to success message...
@@ -567,7 +605,10 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
        protected function success() {
                // Messages: revdelete-success, logdelete-success
                $this->getOutput()->setPageTitle( $this->msg( 'actioncomplete' ) );
-               $this->getOutput()->wrapWikiMsg( "<span class=\"success\">\n$1\n</span>", $this->typeLabels['success'] );
+               $this->getOutput()->wrapWikiMsg(
+                       "<span class=\"success\">\n$1\n</span>",
+                       $this->typeLabels['success']
+               );
                $this->wasSaved = true;
                $this->revDelList->reloadFromMaster();
                $this->showForm();
index 10e7009..63eff36 100644 (file)
@@ -66,12 +66,13 @@ class SpecialRunJobs extends UnlistedSpecialPage {
 
                // Constant-time signature verification
                // http://www.emerose.com/timing-attacks-explained
-               // @todo: make a common method for this
+               // @todo Make a common method for this
                if ( !is_string( $rSig ) || strlen( $rSig ) !== strlen( $cSig ) ) {
                        $verified = false;
                } else {
                        $result = 0;
-                       for ( $i = 0; $i < strlen( $cSig ); $i++ ) {
+                       $cSigLength = strlen( $cSig );
+                       for ( $i = 0; $i < $cSigLength; $i++ ) {
                                $result |= ord( $cSig[$i] ) ^ ord( $rSig[$i] );
                        }
                        $verified = ( $result == 0 );
index c2b5f9b..2713a5f 100644 (file)
@@ -226,7 +226,11 @@ class SpecialSearch extends SpecialPage {
                                $out->addHTML(
                                        Xml::openElement( 'fieldset' ) .
                                        Xml::element( 'legend', null, $this->msg( 'search-external' )->text() ) .
-                                       Xml::element( 'p', array( 'class' => 'mw-searchdisabled' ), $this->msg( 'searchdisabled' )->text() ) .
+                                       Xml::element(
+                                               'p',
+                                               array( 'class' => 'mw-searchdisabled' ),
+                                               $this->msg( 'searchdisabled' )->text()
+                                       ) .
                                        $this->msg( 'googlesearch' )->rawParams(
                                                htmlspecialchars( $term ),
                                                'UTF-8',
@@ -284,7 +288,8 @@ class SpecialSearch extends SpecialPage {
                                $stParams
                        );
 
-                       $this->didYouMeanHtml = '<div class="searchdidyoumean">' . $this->msg( 'search-suggest' )->rawParams( $suggestLink )->text() . '</div>';
+                       $this->didYouMeanHtml = '<div class="searchdidyoumean">'
+                               . $this->msg( 'search-suggest' )->rawParams( $suggestLink )->text() . '</div>';
                }
 
                if ( !wfRunHooks( 'SpecialSearchResultsPrepend', array( $this, $out, $term ) ) ) {
@@ -363,7 +368,10 @@ class SpecialSearch extends SpecialPage {
                        // Show the create link ahead
                        $this->showCreateLink( $title, $num, $titleMatches, $textMatches );
                        if ( $totalRes > $this->limit || $this->offset ) {
-                               $prevnext = $this->getLanguage()->viewPrevNext( $this->getPageTitle(), $this->offset, $this->limit,
+                               $prevnext = $this->getLanguage()->viewPrevNext(
+                                       $this->getPageTitle(),
+                                       $this->offset,
+                                       $this->limit,
                                        $this->powerSearchOptions() + array( 'search' => $term ),
                                        max( $titleMatchesNum, $textMatchesNum ) < $this->limit
                                );
@@ -444,7 +452,11 @@ class SpecialSearch extends SpecialPage {
                } else {
                        $messageName = 'searchmenu-new-nocreate';
                }
-               $params = array( $messageName, wfEscapeWikiText( $title->getPrefixedText() ), Message::numParam( $num ) );
+               $params = array(
+                       $messageName,
+                       wfEscapeWikiText( $title->getPrefixedText() ),
+                       Message::numParam( $num )
+               );
                wfRunHooks( 'SpecialSearchCreateLink', array( $title, &$params ) );
 
                // Extensions using the hook might still return an empty $messageName
@@ -708,7 +720,8 @@ class SpecialSearch extends SpecialPage {
                        &$score, &$size, &$date, &$related,
                        &$html
                ) ) ) {
-                       $html = "<li><div class='mw-search-result-heading'>{$link} {$redirect} {$section} {$fileMatch}</div> {$extract}\n" .
+                       $html = "<li><div class='mw-search-result-heading'>" .
+                               "{$link} {$redirect} {$section} {$fileMatch}</div> {$extract}\n" .
                                "<div class='mw-search-result-data'>{$score}{$size} - {$date}{$related}</div>" .
                                "</li>\n";
                }
@@ -734,7 +747,8 @@ class SpecialSearch extends SpecialPage {
 
                // work out custom project captions
                $customCaptions = array();
-               $customLines = explode( "\n", $this->msg( 'search-interwiki-custom' )->text() ); // format per line <iwprefix>:<caption>
+               // format per line <iwprefix>:<caption>
+               $customLines = explode( "\n", $this->msg( 'search-interwiki-custom' )->text() );
                foreach ( $customLines as $line ) {
                        $parts = explode( ":", $line, 2 );
                        if ( count( $parts ) == 2 ) { // validate line
@@ -756,8 +770,7 @@ class SpecialSearch extends SpecialPage {
                        }
                }
 
-
-               // TODO: should support paging in a non-confusing way (not sure how though, maybe via ajax)..
+               // @todo Should support paging in a non-confusing way (not sure how though, maybe via ajax)..
                $out .= "</ul></div>\n";
 
                // convert the whole thing to desired language variant
index 7fe3bd9..83e731a 100644 (file)
@@ -36,17 +36,76 @@ class GenerateJsonI18n extends Maintenance {
        public function __construct() {
                parent::__construct();
                $this->mDescription = "Build JSON messages files from a PHP messages file";
-               $this->addArg( 'phpfile', 'PHP file defining a $messages array', true );
-               $this->addArg( 'jsondir', 'Directory to write JSON files to. ' .
-                       'Required unless <phpfile> exists and --shim-only is specified', false );
+
+               $this->addArg( 'phpfile', 'PHP file defining a $messages array', false );
+               $this->addArg( 'jsondir', 'Directory to write JSON files to', false );
                $this->addOption( 'langcode', 'Language code; only needed for converting core i18n files',
                        false, true );
+               $this->addOption( 'extension', 'Perform default conversion on an extension',
+                       false, true );
                $this->addOption( 'shim-only', 'Only create or update the backward-compatibility shim' );
+               $this->addOption( 'supplementary', 'Find supplementary i18n files in subdirs and convert those',
+                       false, false );
        }
 
        public function execute() {
+               global $IP;
+
                $phpfile = $this->getArg( 0 );
                $jsondir = $this->getArg( 1 );
+               $extension = $this->getOption( 'extension' );
+               $convertSupplementaryI18nFiles = $this->hasOption( 'supplementary' );
+
+               if ( $extension ) {
+                       if ( $phpfile ) {
+                               $this->error( "The phpfile is already specified, conflicts with --extension.\n", 1 );
+                       }
+                       $phpfile = "$IP/extensions/$extension/$extension.i18n.php";
+               }
+
+               if ( !$phpfile ) {
+                       $this->error( "I'm here for an argument!\n" );
+                       $this->maybeHelp( true );
+                       // dies.
+               }
+
+               if ( $convertSupplementaryI18nFiles ) {
+                       if ( is_readable( $phpfile ) ) {
+                               $this->transformI18nFile( $phpfile, $jsondir );
+                       } else {
+                               // This is non-fatal because we might want to continue searching for
+                               // i18n files in subdirs even if the extension does not include a
+                               // primary i18n.php.
+                               $this->error( "Warning: no primary i18n file was found." );
+                       }
+                       $this->output( "Searching for supplementary i18n files...\n" );
+                       $dir_iterator = new RecursiveDirectoryIterator( dirname( $phpfile ) );
+                       $iterator = new RecursiveIteratorIterator( $dir_iterator, RecursiveIteratorIterator::LEAVES_ONLY );
+                       foreach ( $iterator as $path => $fileObject ) {
+                               if ( fnmatch( "*.i18n.php", $fileObject->getFilename() ) ) {
+                                       $this->output( "Converting $path.\n" );
+                                       $this->transformI18nFile( $path );
+                               }
+                       }
+               } else {
+                       // Just convert the primary i18n file.
+                       $this->transformI18nFile( $phpfile, $jsondir );
+               }
+       }
+
+       public function transformI18nFile( $phpfile, $jsondir = null ) {
+               if ( !$jsondir ) {
+                       // Assume the json directory should be in the same directory as the
+                       // .i18n.php file.
+                       $jsondir = dirname( $phpfile ) . "/i18n";
+               }
+               if ( !is_dir( $jsondir ) ) {
+                       $this->output( "Creating directory $jsondir.\n" );
+                       $success = mkdir( $jsondir );
+                       if ( !$success ) {
+                               $this->error( "Could not create directory $jsondir\n", 1 );
+                       }
+               }
 
                if ( $this->hasOption( 'shim-only' ) ) {
                        $this->shimOnly( $phpfile, $jsondir );
diff --git a/maintenance/pageExists.php b/maintenance/pageExists.php
new file mode 100644 (file)
index 0000000..c4b208a
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * @ingroup Maintenance
+ */
+class PageExists extends Maintenance {
+       public function __construct() {
+               parent::__construct();
+               $this->mDescription = "Report whether a specific page exists";
+               $this->addArg( 'title', 'Page title to check whether it exists' );
+       }
+
+       public function execute() {
+               $titleArg = $this->getArg();
+               $title = Title::newFromText( $titleArg );
+               $pageExists = $title && $title->exists();
+
+               $text = '';
+               $code = 0;
+               if ( $pageExists ) {
+                       $text = "{$title} exists.";
+               } else {
+                       $text = "{$title} doesn't exist.";
+                       $code = 1;
+               }
+               $this->output( $text );
+               $this->error( '', $code );
+       }
+}
+
+$maintClass = "PageExists";
+require_once RUN_MAINTENANCE_IF_MAIN;
+
index aa33d86..af2dee1 100644 (file)
        function doWatchInternal( pages, ok, err, addParams ) {
                // XXX: Parameter addParams is undocumented because we inherit this
                // documentation in the public method...
-               var apiPromise = this.post(
+               var apiPromise = this.postWithToken( 'watch',
                        $.extend(
                                {
                                        action: 'watch',
                                        titles: $.isArray( pages ) ? pages.join( '|' ) : String( pages ),
-                                       token: mw.user.tokens.get( 'watchToken' ),
                                        uselang: mw.config.get( 'wgUserLanguage' )
                                },
                                addParams
index b64ceb0..a6d3b55 100644 (file)
@@ -104,16 +104,6 @@ img.thumbborder {
        border: 1px solid #dddddd;
 }
 
-/* table standards */
-table.rimage {
-       float: right;
-       width: 1pt;
-       position: relative;
-       margin-left: 1em;
-       margin-bottom: 1em;
-       text-align: center;
-}
-
 body {
        background: white;
        color: black;
@@ -277,7 +267,6 @@ span.texhtml {
 /* Galleries (see shared.css for more info) */
 li.gallerybox {
        vertical-align: top;
-       display: -moz-inline-box;
        display: inline-block;
 }
 
index ecfcfa3..2add9f2 100644 (file)
@@ -491,4 +491,18 @@ class DummyContentForTesting extends AbstractContent {
        ) {
                return new ParserOutput( $this->getNativeData() );
        }
+
+       /**
+        * @see AbstractContent::fillParserOutput()
+        *
+        * @param Title $title Context title for parsing
+        * @param int|null $revId Revision ID (for {{REVISIONID}})
+        * @param ParserOptions|null $options Parser options
+        * @param bool $generateHtml Whether or not to generate HTML
+        * @param ParserOutput &$output The output object to fill (reference).
+        */
+       protected function fillParserOutput( Title $title, $revId,
+                       ParserOptions $options, $generateHtml, ParserOutput &$output ) {
+               $output = new ParserOutput( $this->getNativeData() );
+       }
 }
index bd6d41f..40484d3 100644 (file)
@@ -5,7 +5,7 @@
  * @group Database
  *        ^--- needed, because we do need the database to test link updates
  */
-class CssContentTest extends MediaWikiTestCase {
+class CssContentTest extends JavaScriptContentTest {
 
        protected function setUp() {
                parent::setUp();
index 253a035..03cbbc0 100644 (file)
@@ -7,14 +7,21 @@
  */
 class TextContentTest extends MediaWikiLangTestCase {
        protected $context;
+       protected $savedContentGetParserOutput;
 
        protected function setUp() {
+               global $wgHooks;
+
                parent::setUp();
 
                // Anon user
                $user = new User();
                $user->setName( '127.0.0.1' );
 
+               $this->context = new RequestContext( new FauxRequest() );
+               $this->context->setTitle( Title::newFromText( 'Test' ) );
+               $this->context->setUser( $user );
+
                $this->setMwGlobals( array(
                        'wgUser' => $user,
                        'wgTextModelsToParse' => array(
@@ -26,9 +33,22 @@ class TextContentTest extends MediaWikiLangTestCase {
                        'wgAlwaysUseTidy' => false,
                ) );
 
-               $this->context = new RequestContext( new FauxRequest() );
-               $this->context->setTitle( Title::newFromText( 'Test' ) );
-               $this->context->setUser( $user );
+               // bypass hooks that force custom rendering
+               if ( isset( $wgHooks['ContentGetParserOutput'] )  ) {
+                       $this->savedContentGetParserOutput = $wgHooks['ContentGetParserOutput'];
+                       unset( $wgHooks['ContentGetParserOutput'] );
+               }
+       }
+
+       public function teardown() {
+               global $wgHooks;
+
+               // restore hooks that force custom rendering
+               if ( $this->savedContentGetParserOutput !== null ) {
+                       $wgHooks['ContentGetParserOutput'] = $this->savedContentGetParserOutput;
+               }
+
+               parent::teardown();
        }
 
        public function newContent( $text ) {