* Added: kbp (Kabɩyɛ / Kabiyè)
* Added: skr (Saraiki, سرائیکی)
* Added: tay (Tayal / Atayal)
+* Removed: tokipona (Toki Pona)
==== Pig Latin added ====
* (T45547) Added Pig Latin, a made-up English variant (en-x-piglatin),
# Render error page if no LocalSettings file can be found
try {
+ global $wgVersion;
echo $templateParser->processTemplate(
'NoLocalSettings',
[
+++ /dev/null
-<?php
-/**
- * File-scope setup actions, loaded before LocalSettings.php, shared by
- * WebStart.php and doMaintenance.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
- */
-
-if ( !defined( 'MEDIAWIKI' ) ) {
- // Not an entry point
- exit( 1 );
-}
-
-// Grab profiling functions
-require_once "$IP/includes/profiler/ProfilerFunctions.php";
-
-// Start the autoloader, so that extensions can derive classes from core files
-require_once "$IP/includes/AutoLoader.php";
-
-// Load up some global defines.
-require_once "$IP/includes/Defines.php";
-
-// Start the profiler
-$wgProfiler = [];
-if ( file_exists( "$IP/StartProfiler.php" ) ) {
- require "$IP/StartProfiler.php";
-}
-
-// Load default settings
-require_once "$IP/includes/DefaultSettings.php";
-
-// Load global functions
-require_once "$IP/includes/GlobalFunctions.php";
-
-// Load composer's autoloader if present
-if ( is_readable( "$IP/vendor/autoload.php" ) ) {
- require_once "$IP/vendor/autoload.php";
-}
exit( 1 );
}
+/**
+ * Pre-config setup: Before loading LocalSettings.php
+ */
+
+// Grab profiling functions
+require_once "$IP/includes/profiler/ProfilerFunctions.php";
+
+// Start the autoloader, so that extensions can derive classes from core files
+require_once "$IP/includes/AutoLoader.php";
+
+// Load up some global defines
+require_once "$IP/includes/Defines.php";
+
+// Start the profiler
+$wgProfiler = [];
+if ( file_exists( "$IP/StartProfiler.php" ) ) {
+ require "$IP/StartProfiler.php";
+}
+
+// Load default settings
+require_once "$IP/includes/DefaultSettings.php";
+
+// Load global functions
+require_once "$IP/includes/GlobalFunctions.php";
+
+// Load composer's autoloader if present
+if ( is_readable( "$IP/vendor/autoload.php" ) ) {
+ require_once "$IP/vendor/autoload.php";
+}
+
+// Assert that composer dependencies were successfully loaded
+// Purposely no leading \ due to it breaking HHVM RepoAuthorative mode
+// PHP works fine with both versions
+// See https://github.com/facebook/hhvm/issues/5833
+if ( !interface_exists( 'Psr\Log\LoggerInterface' ) ) {
+ $message = (
+ 'MediaWiki requires the <a href="https://github.com/php-fig/log">PSR-3 logging ' .
+ "library</a> to be present. This library is not embedded directly in MediaWiki's " .
+ "git repository and must be installed separately by the end user.\n\n" .
+ 'Please see <a href="https://www.mediawiki.org/wiki/Download_from_Git' .
+ '#Fetch_external_libraries">mediawiki.org</a> for help on installing ' .
+ 'the required components.'
+ );
+ echo $message;
+ trigger_error( $message, E_USER_ERROR );
+ die( 1 );
+}
+
+// Install a header callback
+MediaWiki\HeaderCallback::register();
+
+/**
+ * Load LocalSettings.php
+ */
+
+if ( defined( 'MW_CONFIG_CALLBACK' ) ) {
+ call_user_func( MW_CONFIG_CALLBACK );
+} else {
+ if ( !defined( 'MW_CONFIG_FILE' ) ) {
+ define( 'MW_CONFIG_FILE', "$IP/LocalSettings.php" );
+ }
+ require_once MW_CONFIG_FILE;
+}
+
+/**
+ * Customization point after all loading (constants, functions, classes,
+ * DefaultSettings, LocalSettings). Specifically, this is before usage of
+ * settings, before instantiation of Profiler (and other singletons), and
+ * before any setup functions or hooks run.
+ */
+
+if ( defined( 'MW_SETUP_CALLBACK' ) ) {
+ call_user_func( MW_SETUP_CALLBACK );
+}
+
+/**
+ * Main setup
+ */
+
$fname = 'Setup.php';
$ps_setup = Profiler::instance()->scopedProfileIn( $fname );
$IP = realpath( '.' ) ?: dirname( __DIR__ );
}
-require_once "$IP/includes/PreConfigSetup.php";
-
-# Assert that composer dependencies were successfully loaded
-# Purposely no leading \ due to it breaking HHVM RepoAuthorative mode
-# PHP works fine with both versions
-# See https://github.com/facebook/hhvm/issues/5833
-if ( !interface_exists( 'Psr\Log\LoggerInterface' ) ) {
- $message = (
- 'MediaWiki requires the <a href="https://github.com/php-fig/log">PSR-3 logging ' .
- "library</a> to be present. This library is not embedded directly in MediaWiki's " .
- "git repository and must be installed separately by the end user.\n\n" .
- 'Please see <a href="https://www.mediawiki.org/wiki/Download_from_Git' .
- '#Fetch_external_libraries">mediawiki.org</a> for help on installing ' .
- 'the required components.'
- );
- echo $message;
- trigger_error( $message, E_USER_ERROR );
- die( 1 );
-}
-
-# Install a header callback
-MediaWiki\HeaderCallback::register();
-
-if ( defined( 'MW_CONFIG_CALLBACK' ) ) {
- # Use a callback function to configure MediaWiki
- call_user_func( MW_CONFIG_CALLBACK );
-} else {
+// If no LocalSettings file exists, try to display an error page
+// (use a callback because it depends on TemplateParser)
+if ( !defined( 'MW_CONFIG_CALLBACK' ) ) {
if ( !defined( 'MW_CONFIG_FILE' ) ) {
define( 'MW_CONFIG_FILE', "$IP/LocalSettings.php" );
}
-
- # LocalSettings.php is the per site customization file. If it does not exist
- # the wiki installer needs to be launched or the generated file uploaded to
- # the root wiki directory. Give a hint, if it is not readable by the server.
if ( !is_readable( MW_CONFIG_FILE ) ) {
- require_once "$IP/includes/NoLocalSettings.php";
- die();
+ function wfWebStartNoLocalSettings() {
+ # LocalSettings.php is the per-site customization file. If it does not exist
+ # the wiki installer needs to be launched or the generated file uploaded to
+ # the root wiki directory. Give a hint, if it is not readable by the server.
+ global $IP;
+ require_once "$IP/includes/NoLocalSettings.php";
+ die();
+ }
+ define( 'MW_CONFIG_CALLBACK', 'wfWebStartNoLocalSettings' );
}
-
- # Include site settings. $IP may be changed (hopefully before the AutoLoader is invoked)
- require_once MW_CONFIG_FILE;
}
-# Initialise output buffering
-# Check that there is no previous output or previously set up buffers, because
-# that would cause us to potentially mix gzip and non-gzip output, creating a
-# big mess.
-if ( ob_get_level() == 0 ) {
- require_once "$IP/includes/OutputHandler.php";
- ob_start( 'wfOutputHandler' );
+// Custom setup for WebStart entry point
+if ( !defined( 'MW_SETUP_CALLBACK' ) ) {
+ function wfWebStartSetup() {
+ # Initialise output buffering
+ # Check that there is no previous output or previously set up buffers, because
+ # that would cause us to potentially mix gzip and non-gzip output, creating a
+ # big mess.
+ global $IP;
+ if ( ob_get_level() == 0 ) {
+ require_once "$IP/includes/OutputHandler.php";
+ ob_start( 'wfOutputHandler' );
+ }
+ }
+ define( 'MW_SETUP_CALLBACK', 'wfWebStartSetup' );
}
require_once "$IP/includes/Setup.php";
$context->setOutput( $outputPage );
if ( $skin ) {
+ // Based on OutputPage::headElement()
+ $skin->setupSkinUserCss( $outputPage );
// Based on OutputPage::output()
foreach ( $skin->getDefaultModules() as $group ) {
$outputPage->addModules( $group );
$updates = $content->getSecondaryDataUpdates(
$title, null, $forceRecursiveLinkUpdate, $p_result );
foreach ( $updates as $update ) {
+ $update->setCause( 'api-purge', $this->getUser()->getName() );
DeferredUpdates::addUpdate( $update, DeferredUpdates::PRESEND );
}
abstract class DataUpdate implements DeferrableUpdate {
/** @var mixed Result from LBFactory::getEmptyTransactionTicket() */
protected $ticket;
+ /** @var string Short update cause action description */
+ protected $causeAction = 'unknown';
+ /** @var string Short update cause user description */
+ protected $causeAgent = 'unknown';
public function __construct() {
// noop
$this->ticket = $ticket;
}
+ /**
+ * @param string $action Action type
+ * @param string $user User name
+ */
+ public function setCause( $action, $user ) {
+ $this->causeAction = $action;
+ $this->causeAgent = $user;
+ }
+
+ /**
+ * @return string
+ */
+ public function getCauseAction() {
+ return $this->causeAction;
+ }
+
+ /**
+ * @return string
+ */
+ public function getCauseAgent() {
+ return $this->causeAgent;
+ }
+
/**
* Convenience method, calls doUpdate() on every DataUpdate in the array.
*
* using the job queue.
*/
protected function queueRecursiveJobs() {
- self::queueRecursiveJobsForTable( $this->mTitle, 'templatelinks' );
+ $action = $this->getCauseAction();
+ $agent = $this->getCauseAgent();
+
+ self::queueRecursiveJobsForTable( $this->mTitle, 'templatelinks', $action, $agent );
if ( $this->mTitle->getNamespace() == NS_FILE ) {
// Process imagelinks in case the title is or was a redirect
- self::queueRecursiveJobsForTable( $this->mTitle, 'imagelinks' );
+ self::queueRecursiveJobsForTable( $this->mTitle, 'imagelinks', $action, $agent );
}
$bc = $this->mTitle->getBacklinkCache();
// Which ever runs first generally no-ops the other one.
$jobs = [];
foreach ( $bc->getCascadeProtectedLinks() as $title ) {
- $jobs[] = RefreshLinksJob::newPrioritized( $title, [] );
+ $jobs[] = RefreshLinksJob::newPrioritized(
+ $title,
+ [
+ 'causeAction' => $action,
+ 'causeAgent' => $agent
+ ]
+ );
}
JobQueueGroup::singleton()->push( $jobs );
}
*
* @param Title $title Title to do job for
* @param string $table Table to use (e.g. 'templatelinks')
+ * @param string $action Triggering action
+ * @param string $userName Triggering user name
*/
- public static function queueRecursiveJobsForTable( Title $title, $table ) {
+ public static function queueRecursiveJobsForTable(
+ Title $title, $table, $action = 'unknown', $userName = 'unknown'
+ ) {
if ( $title->getBacklinkCache()->hasLinks( $table ) ) {
$job = new RefreshLinksJob(
$title,
'recursive' => true,
] + Job::newRootJobParams( // "overall" refresh links job info
"refreshlinks:{$table}:{$title->getPrefixedText()}"
- )
+ ) + [ 'causeAction' => $action, 'causeAgent' => $userName ]
);
JobQueueGroup::singleton()->push( $job );
'useRecursiveLinksUpdate' => $this->mRecursive,
'triggeringUser' => $userInfo,
'triggeringRevisionId' => $triggeringRevisionId,
+ 'causeAction' => $this->getCauseAction(),
+ 'causeAgent' => $this->getCauseAgent()
],
[ 'removeDuplicates' => true ],
$this->getTitle()
);
} else {
# Update backlink pages pointing to this title if created
- LinksUpdate::queueRecursiveJobsForTable( $this->getTitle(), 'imagelinks' );
+ LinksUpdate::queueRecursiveJobsForTable(
+ $this->getTitle(),
+ 'imagelinks',
+ 'upload-image',
+ $user->getName()
+ );
}
$this->prerenderThumbnails();
+++ /dev/null
-{
- "@metadata": {
- "authors": [
- "Robin0van0der0vliet"
- ]
- },
- "config-page-language": "toki"
-}
// Multiple pages per job make matches unlikely
!( isset( $params['pages'] ) && count( $params['pages'] ) != 1 )
);
+ $this->params += [ 'causeAction' => 'unknown', 'causeAgent' => 'unknown' ];
}
/**
// Carry over information for de-duplication
$extraParams = $this->getRootJobParams();
$extraParams['triggeredRecursive'] = true;
+ // Carry over cause information for logging
+ $extraParams['causeAction'] = $this->params['causeAction'];
+ $extraParams['causeAgent'] = $this->params['causeAgent'];
// Convert this into no more than $wgUpdateRowsPerJob RefreshLinks per-title
// jobs and possibly a recursive RefreshLinks job for the rest of the backlinks
$jobs = BacklinkJobUtils::partitionBacklinkJob(
$lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
foreach ( $updates as $update ) {
+ // Carry over cause in case so the update can do extra logging
+ $update->setCause( $this->params['causeAction'], $this->params['causeAgent'] );
// FIXME: This code probably shouldn't be here?
// Needed by things like Echo notifications which need
// to know which user caused the links update
public function getDeduplicationInfo() {
$info = parent::getDeduplicationInfo();
+ unset( $info['causeAction'] );
+ unset( $info['causeAgent'] );
if ( is_array( $info['params'] ) ) {
// For per-pages jobs, the job title is that of the template that changed
// (or similar), so remove that since it ruins duplicate detection
$this->getTitle(), null, $recursive, $editInfo->output
);
foreach ( $updates as $update ) {
+ $update->setCause( 'edit-page', $user->getName() );
if ( $update instanceof LinksUpdate ) {
$update->setRevision( $revision );
$update->setTriggeringUser( $user );
$dbw->endAtomic( __METHOD__ );
- $this->doDeleteUpdates( $id, $content, $revision );
+ $this->doDeleteUpdates( $id, $content, $revision, $user );
Hooks::run( 'ArticleDeleteComplete', [
&$wikiPageBeforeDelete,
* the required updates. This may be needed because $this->getContent()
* may already return null when the page proper was deleted.
* @param Revision|null $revision The latest page revision
+ * @param User|null $user The user that caused the deletion
*/
- public function doDeleteUpdates( $id, Content $content = null, Revision $revision = null ) {
+ public function doDeleteUpdates(
+ $id, Content $content = null, Revision $revision = null, User $user = null
+ ) {
try {
$countable = $this->isCountable();
} catch ( Exception $ex ) {
DeferredUpdates::addUpdate( $update );
}
+ $causeAgent = $user ? $user->getName() : 'unknown';
// Reparse any pages transcluding this page
- LinksUpdate::queueRecursiveJobsForTable( $this->mTitle, 'templatelinks' );
-
+ LinksUpdate::queueRecursiveJobsForTable(
+ $this->mTitle, 'templatelinks', 'delete-page', $causeAgent );
// Reparse any pages including this image
if ( $this->mTitle->getNamespace() == NS_FILE ) {
- LinksUpdate::queueRecursiveJobsForTable( $this->mTitle, 'imagelinks' );
+ LinksUpdate::queueRecursiveJobsForTable(
+ $this->mTitle, 'imagelinks', 'delete-page', $causeAgent );
}
// Clear caches
'tly' => 'толышә зывон', # Talysh
'tn' => 'Setswana', # Setswana
'to' => 'lea faka-Tonga', # Tonga (Tonga Islands)
- 'tokipona' => 'Toki Pona', # Toki Pona
'tpi' => 'Tok Pisin', # Tok Pisin
'tr' => 'Türkçe', # Turkish
'tru' => 'Ṫuroyo', # Turoyo
+++ /dev/null
-{
- "@metadata": {
- "authors": [
- "http://tokipona.wikia.com sysops"
- ]
- },
- "january": "tenpo mun pi nanpa wan",
- "february": "tenpo mun pi nanpa tu",
- "march": "tenpo mun pi nanpa tu wan",
- "april": "tenpo mun pi nanpa tu tu",
- "may_long": "tenpo mun pi nanpa luka",
- "june": "tenpo mun pi nanpa luka wan",
- "july": "tenpo mun pi nanpa luka tu",
- "august": "tenpo mun pi nanpa luka tu wan",
- "september": "tenpo mun pi nanpa luka tu tu",
- "october": "tenpo mun pi nanpa luka luka",
- "november": "tenpo mun pi nanpa luka luka wan",
- "december": "tenpo mun pi nanpa luka luka tu",
- "category_header": "lipu lon kulupu lipu \"$1\"",
- "subcategories": "kulupu lipu lili",
- "listingcontinuesabbrev": " li awen",
- "article": "lipu sona",
- "newwindow": "(ona li open e lupa sin)",
- "cancel": "ike",
- "mytalk": "toki mi",
- "navigation": "lipu suli",
- "help": "mi sona ala",
- "search": "o lukin jo",
- "go": "o tawa",
- "history": "o lukin e lipu ni pi tenpo pini",
- "history_short": "lipu ni pi tenpo pini",
- "printableversion": "lipu ni o kama lipu len",
- "permalink": "nimi open kiwen",
- "edit": "o ante",
- "editthispage": "o ante e lipu ni",
- "delete": "o weka",
- "deletethispage": "o weka e lipu ni",
- "protect": "mi taso o ken ante",
- "protectthispage": "mi taso o ken ante e lipu ni",
- "unprotect": "jan ali o ken ante",
- "unprotectthispage": "jan ale o ken ante e lipu ni",
- "talkpage": "Talk page",
- "specialpage": "lipu suli",
- "talk": "o toki",
- "toolbox": "ilo",
- "otherlanguages": "toki ante",
- "redirectedfrom": "(tan $1)",
- "aboutsite": "lipu sona pi toki pona li seme?",
- "aboutpage": "Project:lipu sona pi toki pona li seme?",
- "copyright": "lipu ken $1 li lawa e lipu ni.",
- "currentevents": "seme li sin lon ma?",
- "disclaimers": "wile ala",
- "edithelp": "mi sona ala e ante",
- "mainpage": "lipu lawa",
- "mainpage-description": "lipu lawa",
- "portal": "lipu pi kulupu ni",
- "privacy": "ken pi awen weka",
- "ok": "pona",
- "retrievedfrom": "tan $1",
- "editsection": "o ante",
- "toc": "poki lawa",
- "showtoc": "o suli e poki ni.",
- "hidetoc": "o lili e poki ni",
- "nstab-main": "lipu sona",
- "nstab-user": "lipu jan",
- "nstab-special": "suli",
- "nstab-image": "lipu nanpa",
- "nstab-mediawiki": "nimi",
- "nstab-template": "lipu mama",
- "nstab-help": "pana pona",
- "nstab-category": "kulupu lipu",
- "logout": "mi o tawa",
- "userlogout": "mi o tawa",
- "summary": "ante li seme:",
- "minoredit": "ante ni li lili taso",
- "watchthis": "mi wile sona e ante ale pi lipu ni lon tenpo kama",
- "savearticle": "o awen",
- "preview": "lukin taso",
- "showpreview": "mi wile lukin taso e ante",
- "editing": "mi ante e: $1",
- "editingcomment": "mi ante e lipu $1 (wan sin)",
- "copyrightwarning": "o sona e ni: ken $2 (o lukin e $1) li lawa tawa ante ali lon {{SITENAME}} li. jan li ken ante e toki sina li ken pana e ona tawa jan ante. sina wile ala e ni la, o sitelen ala lon lipu ni.<br />\nkin la sina toki e ni: toki sina ni li tan sina taso anu lipu pi ken ali.\n'''SINA KEN ALA LA, O PANA ALA E TOKI PI KEN LILI TAWA LIPU NI!'''",
- "templatesused": "{{PLURAL:$1|Template|Templates}} used on this page:",
- "histfirst": "pini taso",
- "histlast": "sin taso",
- "prevn": "nanpa {{PLURAL:$1|$1}} pini",
- "nextn": "nanpa {{PLURAL:$1|$1}} kama",
- "viewprevnext": "o lukin e ($1 {{int:pipe-separator}} $2) ($3).",
- "preferences": "seme li pona tawa mi",
- "recentchanges": "lipu seme li ante?",
- "minoreditletter": "ante lili",
- "newpageletter": "lipu sin",
- "recentchangeslinked": "ante sama",
- "recentchangeslinked-feed": "ante sama",
- "recentchangeslinked-toolbox": "ante sama",
- "upload": "o pana e lipu nanpa",
- "filedesc": "ante li seme",
- "fileuploadsummary": "ante li seme:",
- "file-anchor-link": "Lipu nanpa",
- "randompage": "mi wile lukin e lipu ante",
- "lonelypages": "lipu ni li jo ala e lipu sama",
- "move": "o tawa",
- "movethispage": "o pana e nimi sin",
- "allpages": "lipu ale",
- "categories": "kulupu lipu",
- "watchlist": "mi sona e ante pi lipu seme",
- "watch": "o sona e ante",
- "watchthispage": "mi wile sona e ante ale pi lipu ni lon tenpo kama",
- "unwatchthispage": "mi wile ala sona e ante ale pi lipu ni lon tenpo kama",
- "mycontris": "mi ante e lipu seme",
- "whatlinkshere": "lipu seme li tawa ni?",
- "specialpages": "lipu suli"
-}
// to $maintenance->mSelf. Keep that here for b/c
$self = $maintenance->getName();
-require_once "$IP/includes/PreConfigSetup.php";
-
-if ( defined( 'MW_CONFIG_CALLBACK' ) ) {
- # Use a callback function to configure MediaWiki
- call_user_func( MW_CONFIG_CALLBACK );
-} else {
- // Require the configuration (probably LocalSettings.php)
- require $maintenance->loadSettings();
+// Define how settings are loaded (e.g. LocalSettings.php)
+if ( !defined( 'MW_CONFIG_CALLBACK' ) && !defined( 'MW_CONFIG_FILE' ) ) {
+ define( 'MW_CONFIG_FILE', $maintenance->loadSettings() );
}
-if ( $maintenance->getDbType() === Maintenance::DB_NONE ) {
- if ( $wgLocalisationCacheConf['storeClass'] === false
- && ( $wgLocalisationCacheConf['store'] == 'db'
- || ( $wgLocalisationCacheConf['store'] == 'detect' && !$wgCacheDirectory ) )
- ) {
- $wgLocalisationCacheConf['storeClass'] = 'LCStoreNull';
+// Custom setup for Maintenance entry point
+if ( !defined( 'MW_SETUP_CALLBACK' ) ) {
+ function wfMaintenanceSetup() {
+ // @codingStandardsIgnoreLine MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
+ global $maintenance, $wgLocalisationCacheConf, $wgCacheDirectory;
+ if ( $maintenance->getDbType() === Maintenance::DB_NONE ) {
+ if ( $wgLocalisationCacheConf['storeClass'] === false
+ && ( $wgLocalisationCacheConf['store'] == 'db'
+ || ( $wgLocalisationCacheConf['store'] == 'detect' && !$wgCacheDirectory ) )
+ ) {
+ $wgLocalisationCacheConf['storeClass'] = 'LCStoreNull';
+ }
+ }
+
+ $maintenance->finalSetup();
}
+ define( 'MW_SETUP_CALLBACK', 'wfMaintenanceSetup' );
}
-$maintenance->finalSetup();
-// Some last includes
require_once "$IP/includes/Setup.php";
// Initialize main config instance
);
}
}
+
+ public function testSkinModules() {
+ $factory = new SkinFactory();
+ $factory->register( 'testing', 'Testing', function () {
+ $skin = $this->getMockBuilder( SkinFallback::class )
+ ->setMethods( [ 'getDefaultModules', 'setupSkinUserCss' ] )
+ ->getMock();
+ $skin->expects( $this->once() )->method( 'getDefaultModules' )
+ ->willReturn( [
+ 'core' => [ 'foo', 'bar' ],
+ 'content' => [ 'baz' ]
+ ] );
+ $skin->expects( $this->once() )->method( 'setupSkinUserCss' )
+ ->will( $this->returnCallback( function ( OutputPage $out ) {
+ $out->addModuleStyles( 'foo.styles' );
+ } ) );
+ return $skin;
+ } );
+ $this->setService( 'SkinFactory', $factory );
+
+ $res = $this->doApiRequest( [
+ 'action' => 'parse',
+ 'pageid' => self::$pageId,
+ 'useskin' => 'testing',
+ 'prop' => 'modules',
+ ] );
+ $this->assertSame(
+ [ 'foo', 'bar', 'baz' ],
+ $res[0]['parse']['modules'],
+ 'resp.parse.modules'
+ );
+ $this->assertSame(
+ [],
+ $res[0]['parse']['modulescripts'],
+ 'resp.parse.modulescripts'
+ );
+ $this->assertSame(
+ [ 'foo.styles' ],
+ $res[0]['parse']['modulestyles'],
+ 'resp.parse.modulestyles'
+ );
+ }
}
[ 'fr', true, 'Two letters, minor case' ],
[ 'EN', false, 'Two letters, upper case' ],
[ 'tyv', true, 'Three letters' ],
- [ 'tokipona', true, 'long language code' ],
[ 'be-tarask', true, 'With dash' ],
[ 'be-x-old', true, 'With extension (two dashes)' ],
[ 'be_tarask', false, 'Reject underscores' ],