'MediaWiki\\Logger\\Monolog\\WikiProcessor' => __DIR__ . '/includes/debug/logger/monolog/WikiProcessor.php',
'MediaWiki\\Logger\\NullSpi' => __DIR__ . '/includes/debug/logger/NullSpi.php',
'MediaWiki\\Logger\\Spi' => __DIR__ . '/includes/debug/logger/Spi.php',
+ 'MediaWiki\\Widget\\NamespaceInputWidget' => __DIR__ . '/includes/widget/NamespaceInputWidget.php',
'MediaWiki\\Widget\\TitleInputWidget' => __DIR__ . '/includes/widget/TitleInputWidget.php',
'MemCachedClientforWiki' => __DIR__ . '/includes/objectcache/MemcachedClient.php',
'MemcLockManager' => __DIR__ . '/includes/filebackend/lockmanager/MemcLockManager.php',
*/
$wgEnotifUseJobQ = false;
-/**
- * Use the job queue for user activity updates like updating "last visited"
- * fields for email notifications of page changes. This should only be enabled
- * if the jobs have a dedicated runner to avoid update lag.
- *
- * @since 1.26
- */
-$wgActivityUpdatesUseJobQueue = false;
-
/**
* Use real name instead of username in e-mail "from" field.
*/
*
* @since 1.17
*/
-class Message implements MessageSpecifier {
+class Message implements MessageSpecifier, Serializable {
/**
* In which language to get this message. True, which is the default,
$this->language = $language ?: $wgLang;
}
+ /**
+ * @see Serializable::serialize()
+ * @since 1.26
+ * @return string
+ */
+ public function serialize() {
+ return serialize( array(
+ 'interface' => $this->interface,
+ 'language' => $this->language->getCode(),
+ 'key' => $this->key,
+ 'keysToTry' => $this->keysToTry,
+ 'parameters' => $this->parameters,
+ 'format' => $this->format,
+ 'useDatabase' => $this->useDatabase,
+ 'title' => $this->title,
+ ) );
+ }
+
+ /**
+ * @see Serializable::unserialize()
+ * @since 1.26
+ * @param string $serialized
+ */
+ public function unserialize( $serialized ) {
+ $data = unserialize( $serialized );
+ $this->interface = $data['interface'];
+ $this->key = $data['key'];
+ $this->keysToTry = $data['keysToTry'];
+ $this->parameters = $data['parameters'];
+ $this->format = $data['format'];
+ $this->useDatabase = $data['useDatabase'];
+ $this->language = Language::factory( $data['language'] );
+ $this->title = $data['title'];
+ }
+
/**
* @since 1.24
*
'oojs-ui.styles.icons',
'oojs-ui.styles.indicators',
'oojs-ui.styles.textures',
+ 'mediawiki.widgets.styles',
) );
}
}
Hooks::run( 'TitleGetEditNotices', array( $this, $oldid, &$notices ) );
return $notices;
}
+
+ /**
+ * @return array
+ */
+ public function __sleep() {
+ return array(
+ 'mNamespace',
+ 'mDbkeyform',
+ 'mFragment',
+ 'mInterwiki',
+ 'mLocalInterwiki',
+ 'mUserCaseDBKey',
+ 'mDefaultNamespace',
+ );
+ }
+
+ public function __wakeup() {
+ $this->mArticleID = ( $this->mNamespace >= 0 ) ? -1 : 0;
+ $this->mUrlform = wfUrlencode( $this->mDbkeyform );
+ $this->mTextform = strtr( $this->mDbkeyform, '_', ' ' );
+ }
+
}
: wfGetDB( DB_SLAVE );
$options = ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING )
- ? array( 'FOR UPDATE' )
+ ? array( 'LOCK IN SHARE MODE' )
: array();
- $id = $db->selectField( 'user', 'user_id', array( 'user_name' => $s ), __METHOD__, $options );
- if ( $id === false ) {
- $id = 0;
- }
+ $id = $db->selectField( 'user',
+ 'user_id', array( 'user_name' => $s ), __METHOD__, $options );
- return $id;
+ return (int)$id;
}
/**
public function resetNotificationTimestamp(
$force = '', $oldid = 0, $mode = self::IMMEDIATE
) {
- global $wgActivityUpdatesUseJobQueue;
-
// Only loggedin user can have a watchlist
if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) {
return;
}
// If the page is watched by the user (or may be watched), update the timestamp
- if ( $mode === self::DEFERRED && $wgActivityUpdatesUseJobQueue ) {
- JobQueueGroup::singleton()->push(
- EnqueueJob::newFromLocalJobs( new JobSpecification(
- 'activityUpdateJob',
- array(
- 'type' => 'updateWatchlistNotification',
- 'userid' => $this->getUserId(),
- 'notifTime' => $notificationTimestamp,
- 'curTime' => time()
- ),
- array( 'removeDuplicates' => true ),
- $title
- ) )
+ if ( $mode === self::DEFERRED ) {
+ $job = new ActivityUpdateJob(
+ $title,
+ array(
+ 'type' => 'updateWatchlistNotification',
+ 'userid' => $this->getUserId(),
+ 'notifTime' => $notificationTimestamp,
+ 'curTime' => time()
+ )
);
+ // Try to run this post-send
+ DeferredUpdates::addCallableUpdate( function() use ( $job ) {
+ $job->run();
+ } );
} else {
$dbw = wfGetDB( DB_MASTER );
$dbw->update( 'watchlist',
$id = $title->getArticleID();
$config = $this->context->getConfig();
- $dbr = wfGetDB( DB_SLAVE );
+ $dbrWatchlist = wfGetDB( DB_SLAVE, 'watchlist' );
$result = array();
// Number of page watchers
- $watchers = (int)$dbr->selectField(
+ $watchers = (int)$dbrWatchlist->selectField(
'watchlist',
'COUNT(*)',
array(
// Threshold: last visited about 26 weeks before latest edit
$updated = wfTimestamp( TS_UNIX, $this->page->getTimestamp() );
$age = $config->get( 'WatchersMaxAge' );
- $threshold = $dbr->timestamp( $updated - $age );
+ $threshold = $dbrWatchlist->timestamp( $updated - $age );
// Number of page watchers who also visited a "recent" edit
- $visitingWatchers = (int)$dbr->selectField(
+ $visitingWatchers = (int)$dbrWatchlist->selectField(
'watchlist',
'COUNT(*)',
array(
'wl_namespace' => $title->getNamespace(),
'wl_title' => $title->getDBkey(),
- 'wl_notificationtimestamp >= ' . $dbr->addQuotes( $threshold ) .
+ 'wl_notificationtimestamp >= ' . $dbrWatchlist->addQuotes( $threshold ) .
' OR wl_notificationtimestamp IS NULL'
),
__METHOD__
$result['visitingWatchers'] = $visitingWatchers;
}
+ $dbr = wfGetDB( DB_SLAVE );
// Total number of edits
$edits = (int)$dbr->selectField(
'revision',
public function setApiData( array $data ) {
$this->apiData = $data;
}
+
+ public function serialize() {
+ return serialize( array(
+ 'parent' => parent::serialize(),
+ 'apiCode' => $this->apiCode,
+ 'apiData' => $this->apiData,
+ ) );
+ }
+
+ public function unserialize( $serialized ) {
+ $data = unserialize( $serialized );
+ parent::unserialize( $data['parent'] );
+ $this->apiCode = $data['apiCode'];
+ $this->apiData = $data['apiData'];
+ }
}
/**
public function setApiData( array $data ) {
$this->apiData = $data;
}
+
+ public function serialize() {
+ return serialize( array(
+ 'parent' => parent::serialize(),
+ 'apiCode' => $this->apiCode,
+ 'apiData' => $this->apiData,
+ ) );
+ }
+
+ public function unserialize( $serialized ) {
+ $data = unserialize( $serialized );
+ parent::unserialize( $data['parent'] );
+ $this->apiCode = $data['apiCode'];
+ $this->apiData = $data['apiData'];
+ }
}
if ( $user->pingLimiter( 'stashedit' ) ) {
$status = 'ratelimited';
} elseif ( $wgMemc->lock( $key, 0, 30 ) ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$unlocker = new ScopedCallback( function() use ( $key ) {
global $wgMemc;
$wgMemc->unlock( $key );
if ( $this->mainCache->lock( $key, 0, 10 ) ) {
# Let this process alone update the cache value
$cache = $this->mainCache;
+ /** @noinspection PhpUnusedLocalVariableInspection */
$unlocker = new ScopedCallback( function () use ( $cache, $key ) {
$cache->unlock( $key );
} );
} elseif ( $staleValue ) {
# Could not acquire lock but an old cache exists, so use it
- return $value['lagTimes'];
+ return $staleValue['lagTimes'];
}
$lagTimes = array();
$op['headers']['Content-Disposition'] = $op['disposition'];
}
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
return $this->doOperationsInternal( $ops, $opts );
}
$op['headers']['Content-Disposition'] = $op['disposition'];
}
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
return $this->doQuickOperationsInternal( $ops );
}
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
return $this->doPrepare( $params );
}
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
return $this->doSecure( $params );
}
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
return $this->doPublish( $params );
}
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
return $this->doClean( $params );
}
public function getLocalRefPath() {
$this->assertRepoDefined();
if ( !isset( $this->fsFile ) ) {
+ $starttime = microtime( true );
$this->fsFile = $this->repo->getLocalReference( $this->getPath() );
+ RequestContext::getMain()->getStats()->timing( 'media.thumbnail.generate.fetchoriginal', microtime( true ) - $starttime );
+
if ( !$this->fsFile ) {
$this->fsFile = false; // null => false; cache negative hits
}
public function generateAndSaveThumb( $tmpFile, $transformParams, $flags ) {
global $wgUseSquid, $wgIgnoreImageErrors;
+ $stats = RequestContext::getMain()->getStats();
+
$handler = $this->getHandler();
$normalisedParams = $transformParams;
$this->generateBucketsIfNeeded( $normalisedParams, $flags );
}
+ $starttime = microtime( true );
+
// Actually render the thumbnail...
$thumb = $handler->doTransform( $this, $tmpThumbPath, $thumbUrl, $transformParams );
$tmpFile->bind( $thumb ); // keep alive with $thumb
+ $stats->timing( 'media.thumbnail.generate.transform', microtime( true ) - $starttime );
+
if ( !$thumb ) { // bad params?
$thumb = false;
} elseif ( $thumb->isError() ) { // transform error
}
} elseif ( $this->repo && $thumb->hasFile() && !$thumb->fileIsSource() ) {
// Copy the thumbnail from the file system into storage...
+
+ $starttime = microtime( true );
+
$disposition = $this->getThumbDisposition( $thumbName );
$status = $this->repo->quickImport( $tmpThumbPath, $thumbPath, $disposition );
if ( $status->isOK() ) {
} else {
$thumb = $this->transformErrorOutput( $thumbPath, $thumbUrl, $transformParams, $flags );
}
+
+ $stats->timing( 'media.thumbnail.generate.store', microtime( true ) - $starttime );
+
// Give extensions a chance to do something with this thumbnail...
Hooks::run( 'FileTransformed', array( $this, $thumb, $tmpThumbPath, $thumbPath ) );
}
// "thumbs" which have the main image URL though (bug 13776)
if ( $wgUseSquid ) {
if ( !$thumb || $thumb->isError() || $thumb->getUrl() != $this->getURL() ) {
+ $starttime = microtime( true );
+
SquidUpdate::purge( array( $thumbUrl ) );
+
+ $stats->timing( 'media.thumbnail.generate.purge', microtime( true ) - $starttime );
}
}
+
+
return $thumb;
}
return false;
}
+ $starttime = microtime( true );
+
$params['physicalWidth'] = $bucket;
$params['width'] = $bucket;
$thumb = $this->generateAndSaveThumb( $tmpFile, $params, $flags );
+ $buckettime = microtime( true ) - $starttime;
+
if ( !$thumb || $thumb->isError() ) {
return false;
}
// this object exists
$tmpFile->bind( $this );
+ RequestContext::getMain()->getStats()->timing( 'media.thumbnail.generate.bucket', $buckettime );
+
return true;
}
}
public function getInputOOUI( $value ) {
- $namespaceOptions = Html::namespaceSelectorOptions( array( 'all' => $this->mAllValue ) );
-
- $options = array();
- foreach( $namespaceOptions as $id => $name ) {
- $options[] = array(
- 'data' => (string)$id,
- 'label' => $name,
- );
- };
-
- return new OOUI\DropdownInputWidget( array(
- 'options' => $options,
- 'value' => $value,
- 'name' => $this->mName,
+ return new MediaWiki\Widget\NamespaceInputWidget( array(
+ 'valueNamespace' => $value,
+ 'nameNamespace' => $this->mName,
'id' => $this->mID,
+ 'includeAllValue' => $this->mAllValue,
+ // Disable additional checkboxes
+ 'nameInvert' => null,
+ 'nameAssociated' => null,
) );
}
}
public function submitConnectForm() {
// Get variables from the request.
- $newValues = $this->setVarsFromRequest( array(
- 'wgDBserver', 'wgDBname', 'wgDBprefix', '_InstallUser', '_InstallPassword'
- ) );
+ $newValues = $this->setVarsFromRequest( array( 'wgDBserver', 'wgDBname', 'wgDBprefix' ) );
// Validate them.
$status = Status::newGood();
if ( !preg_match( '/^[a-z0-9_-]*$/i', $newValues['wgDBprefix'] ) ) {
$status->fatal( 'config-invalid-db-prefix', $newValues['wgDBprefix'] );
}
- if ( !strlen( $newValues['_InstallUser'] ) ) {
- $status->fatal( 'config-db-username-empty' );
- }
- if ( !strlen( $newValues['_InstallPassword'] ) ) {
- $status->fatal( 'config-db-password-empty', $newValues['_InstallUser'] );
- }
if ( !$status->isOK() ) {
return $status;
}
function submitConnectForm() {
// Get variables from the request
- $newValues = $this->setVarsFromRequest( array(
- 'wgDBserver', 'wgDBport', 'wgDBname', 'wgDBmwschema',
- '_InstallUser', '_InstallPassword'
- ) );
+ $newValues = $this->setVarsFromRequest( array( 'wgDBserver', 'wgDBport', 'wgDBname', 'wgDBmwschema' ) );
// Validate them
$status = Status::newGood();
if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBmwschema'] ) ) {
$status->fatal( 'config-invalid-schema', $newValues['wgDBmwschema'] );
}
- if ( !strlen( $newValues['_InstallUser'] ) ) {
- $status->fatal( 'config-db-username-empty' );
- }
- if ( !strlen( $newValues['_InstallPassword'] ) ) {
- $status->fatal( 'config-db-password-empty', $newValues['_InstallUser'] );
- }
// Submit user box
if ( $status->isOK() ) {
"config-db-install-account": "User account for installation",
"config-db-username": "Database username:",
"config-db-password": "Database password:",
- "config-db-password-empty": "Please enter a password for the new database user: $1.\nWhile it may be possible to create users with no passwords, it is not secure.",
- "config-db-username-empty": "You must enter a value for \"{{int:config-db-username}}\".",
"config-db-install-username": "Enter the username that will be used to connect to the database during the installation process.\nThis is not the username of the MediaWiki account; this is the username for your database.",
"config-db-install-password": "Enter the password that will be used to connect to the database during the installation process.\nThis is not the password for the MediaWiki account; this is the password for your database.",
"config-db-install-help": "Enter the username and password that will be used to connect to the database during the installation process.",
"config-db-name-oracle": "Field label in the MediaWiki installer where an Oracle database schema can be specified.",
"config-db-account-oracle-warn": "A \"[[:wikipedia:Front and back ends|backend]]\" is a system or component that ordinary users don't interact with directly and don't need to know about, and that is responsible for a distinct task or service - for example, a storage back-end is a generic system for storing data which other applications can use. Possible alternatives for back-end are \"system\" or \"service\", or (depending on context and language) even leave it untranslated.",
"config-db-install-account": "Legend in the MediaWiki installer for the section where database username and password have to be provided.",
- "config-db-username": "Used as label.\n\nAlso used in {{msg-mw|Config-db-username-empty}}.",
+ "config-db-username": "Used as label.",
"config-db-password": "Field label in the MediaWiki installer where database password has to be provided.",
- "config-db-password-empty": "Used as error message. Parameters:\n* $1 - database username",
- "config-db-username-empty": "Used as error message. Shown when the database username is not entered by the user.\n\nRefers to {{msg-mw|Config-db-username}}.",
"config-db-install-username": "Help box text in the MediaWiki installer clarifying the requirement for database username.",
"config-db-install-password": "Help box text in the MediaWiki installer clarifying the requirement for database password.",
"config-db-install-help": "Help text in MediaWiki installer.",
$tmpDir = wfTempDir() . '/svg_' . wfRandomString( 24 );
$lnPath = "$tmpDir/" . basename( $srcPath );
$ok = mkdir( $tmpDir, 0771 ) && symlink( $srcPath, $lnPath );
+ /** @noinspection PhpUnusedLocalVariableInspection */
$cleaner = new ScopedCallback( function () use ( $tmpDir, $lnPath ) {
MediaWiki\suppressWarnings();
unlink( $lnPath );
);
$oldDisable = libxml_disable_entity_loader( true );
+ /** @noinspection PhpUnusedLocalVariableInspection */
$reset = new ScopedCallback(
'libxml_disable_entity_loader',
array( $oldDisable )
Alex Monk <krenair@wikimedia.org>
Bartosz Dziewoński <bdziewonski@wikimedia.org>
Ed Sanders <esanders@wikimedia.org>
+Florian Schmidt <florian.schmidt.welzow@t-online.de>
James D. Forrester <jforrester@wikimedia.org>
Roan Kattouw <roan@wikimedia.org>
Sucheta Ghoshal <sghoshal@wikimedia.org>
--- /dev/null
+<?php
+/**
+ * MediaWiki Widgets – NamespaceInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+namespace MediaWiki\Widget;
+
+/**
+ * Namespace input widget. Displays a dropdown box with the choice of available namespaces, plus two
+ * checkboxes to include associated namespace or to invert selection.
+ */
+class NamespaceInputWidget extends \OOUI\Widget {
+
+ protected $namespace = null;
+ protected $associated = null;
+ protected $invert = null;
+ protected $allValue = null;
+
+ /**
+ * @param array $config Configuration options
+ * @param string $config['nameNamespace'] HTML input name for the namespace dropdown box (default:
+ * 'namespace')
+ * @param string $config['nameInvert'] HTML input name for the "invert selection" checkbox. If
+ * null, the checkbox will not be generated. (default: 'invert')
+ * @param string $config['nameAssociated'] HTML input name for the "include associated namespace"
+ * checkbox. If null, the checkbox will not be generated. (default: 'associated')
+ * @param string $config['includeAllValue'] If specified, add a "all namespaces" option to the
+ * namespace dropdown, and use this as the input value for it
+ * @param int|string $config['valueNamespace'] Input value of the namespace dropdown box. May be a
+ * string only if 'includeAllValue' is set.
+ * @param boolean $config['valueInvert'] Input value of the "invert selection" checkbox (default:
+ * false)
+ * @param boolean $config['valueAssociated'] Input value of the "include associated namespace"
+ * checkbox (default: false)
+ * @param string $config['labelInvert'] Text of label to use for "invert selection" checkbox
+ * @param string $config['labelAssociated'] Text of label to use for "include associated
+ * namespace" checkbox
+ */
+ public function __construct( array $config = array() ) {
+ // Configuration initialization
+
+ $config = array_merge(
+ array(
+ 'nameNamespace' => 'namespace',
+ 'nameInvert' => 'invert',
+ 'nameAssociated' => 'associated',
+ // Choose first available: either main namespace or the "all namespaces" option
+ 'valueNamespace' => null,
+ 'valueInvert' => false,
+ 'valueAssociated' => false,
+ ),
+ $config
+ );
+
+ // Parent constructor
+ parent::__construct( $config );
+
+ // Properties
+ $this->allValue = isset( $config['includeAllValue'] ) ? $config['includeAllValue'] : null;
+ $this->namespace = new \OOUI\DropdownInputWidget( array(
+ 'name' => $config['nameNamespace'],
+ 'value' => $config['valueNamespace'],
+ 'options' => $this->getNamespaceDropdownOptions( $config ),
+ ) );
+ if ( $config['nameAssociated'] !== null ) {
+ // FIXME Should use a LabelWidget? But they don't work like HTML <label>s yet
+ $this->associated = new \OOUI\FieldLayout(
+ new \OOUI\CheckboxInputWidget( array(
+ 'name' => $config['nameAssociated'],
+ 'selected' => $config['valueAssociated'],
+ 'value' => '1',
+ ) ),
+ array(
+ 'align' => 'inline',
+ 'label' => $config['labelAssociated'],
+ )
+ );
+ }
+ if ( $config['nameInvert'] !== null ) {
+ $this->invert = new \OOUI\FieldLayout(
+ new \OOUI\CheckboxInputWidget( array(
+ 'name' => $config['nameInvert'],
+ 'selected' => $config['valueInvert'],
+ 'value' => '1',
+ ) ),
+ array(
+ 'align' => 'inline',
+ 'label' => $config['labelInvert'],
+ )
+ );
+ }
+
+ // Initialization
+ $this
+ ->addClasses( array( 'mw-widget-namespaceInputWidget' ) )
+ ->appendContent( $this->namespace, $this->associated, $this->invert );
+ }
+
+ protected function getNamespaceDropdownOptions( array $config ) {
+ $namespaceOptionsParams = isset( $config['includeAllValue'] ) ?
+ array( 'all' => $config['includeAllValue'] ) : array();
+ $namespaceOptions = \Html::namespaceSelectorOptions( $namespaceOptionsParams );
+
+ $options = array();
+ foreach( $namespaceOptions as $id => $name ) {
+ $options[] = array(
+ 'data' => (string)$id,
+ 'label' => $name,
+ );
+ }
+
+ return $options;
+ }
+
+ protected function getJavaScriptClassName() {
+ return 'mw.widgets.NamespaceInputWidget';
+ }
+
+ public function getConfig( &$config ) {
+ $config['namespace'] = $this->namespace;
+ $config['associated'] = $this->associated;
+ $config['invert'] = $this->invert;
+ $config['allValue'] = $this->allValue;
+ return parent::getConfig( $config );
+ }
+}
/**
* @param array $config Configuration options
* @param int|null $config['namespace'] Namespace to prepend to queries
- * @param bool|null $config['relative'] If a namespace is set, return a title relative to it (default; true)
+ * @param bool|null $config['relative'] If a namespace is set, return a title relative to it (default: true)
*/
public function __construct( array $config = array() ) {
// Parent constructor
$rtl = true;
+$namespaceNames = array(
+ NS_MEDIA => 'میڈیا',
+ NS_SPECIAL => 'خاص',
+ NS_TALK => 'گل_بات',
+ NS_USER => 'ورتنوالا',
+ NS_USER_TALK => 'ورتن_گل_بات',
+ NS_PROJECT_TALK => 'ویونت_گل_بات',
+ NS_FILE => 'فائل',
+ NS_FILE_TALK => 'فائل_گل_بات',
+ NS_MEDIAWIKI => 'میڈیا_وکی',
+ NS_MEDIAWIKI_TALK => 'میڈیاوکی_گل_بات',
+ NS_TEMPLATE => 'سانچہ',
+ NS_TEMPLATE_TALK => 'سانچہ_گل_بات',
+ NS_HELP => 'ہتھونڈائی',
+ NS_HELP_TALK => 'ہتھونڈائی_گل_بات',
+ NS_CATEGORY => 'گٹھ',
+ NS_CATEGORY_TALK => 'گٹھ_گل_بات',
+);
'mediawiki.widgets' => array(
'scripts' => array(
'resources/src/mediawiki.widgets/mw.widgets.js',
+ 'resources/src/mediawiki.widgets/mw.widgets.NamespaceInputWidget.js',
'resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js',
'resources/src/mediawiki.widgets/mw.widgets.TitleOptionWidget.js',
),
'skinStyles' => array(
- 'default' => 'resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css',
+ 'default' => array(
+ 'resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css',
+ ),
),
'dependencies' => array(
+ 'mediawiki.widgets.styles',
'jquery.autoEllipsis',
'mediawiki.Title',
'mediawiki.api',
),
'targets' => array( 'desktop', 'mobile' ),
),
+ 'mediawiki.widgets.styles' => array(
+ 'skinStyles' => array(
+ 'default' => array(
+ 'resources/src/mediawiki.widgets/mw.widgets.NamespaceInputWidget.base.css',
+ ),
+ ),
+ 'position' => 'top',
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
/* es5-shim */
'es5-shim' => array(
--- /dev/null
+/*!
+ * MediaWiki Widgets - base NamespaceInputWidget styles.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+.mw-widget-namespaceInputWidget .oo-ui-dropdownInputWidget,
+.mw-widget-namespaceInputWidget .oo-ui-fieldLayout {
+ display: inline-block;
+ margin-right: 1em;
+}
+
+/* FIXME FieldLayout is not supposed to be used the way we use it here */
+.mw-widget-namespaceInputWidget .oo-ui-fieldLayout {
+ vertical-align: middle;
+ margin-bottom: 0;
+}
+
+.mw-widget-namespaceInputWidget .oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+ padding-left: 0.5em;
+}
+
+.mw-widget-namespaceInputWidget .oo-ui-dropdownInputWidget {
+ width: 20em;
+}
--- /dev/null
+/*!
+ * MediaWiki Widgets - NamespaceInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+ /**
+ * Creates a mw.widgets.NamespaceInputWidget object.
+ *
+ * This is not a complete implementation and is not intended for public usage. It only exists
+ * because of HTMLForm shenanigans.
+ *
+ * @class
+ * @private
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {OO.ui.DropdownInputWidget} namespace Widget to include
+ * @cfg {OO.ui.CheckboxInputWidget|null} invert Widget to include
+ * @cfg {OO.ui.CheckboxInputWidget|null} associated Widget to include
+ * @cfg {string|null} allValue Value for "all namespaces" option, if any
+ */
+ mw.widgets.NamespaceInputWidget = function MwWidgetsNamespaceInputWidget( config ) {
+ // Parent constructor
+ OO.ui.Widget.call( this, config );
+
+ // Properties
+ this.namespace = config.namespace;
+ this.invert = config.invert;
+ this.associated = config.associated;
+ this.allValue = config.allValue;
+
+ // Events
+ config.namespace.connect( this, { change: 'updateCheckboxesState' } );
+
+ // Initialization
+ this.$element
+ .addClass( 'mw-widget-namespaceInputWidget' )
+ .append(
+ config.namespace.$element,
+ config.invert ? config.invert.$element : '',
+ config.associated ? config.associated.$element : ''
+ );
+ this.updateCheckboxesState();
+ };
+
+ /* Inheritance */
+
+ OO.inheritClass( mw.widgets.NamespaceInputWidget, OO.ui.Widget );
+
+ /* Methods */
+
+ /**
+ * Update the disabled state of checkboxes when the value of namespace dropdown changes.
+ */
+ mw.widgets.NamespaceInputWidget.prototype.updateCheckboxesState = function () {
+ if ( this.invert ) {
+ this.invert.getField().setDisabled( this.namespace.getValue() === this.allValue );
+ }
+ if ( this.associated ) {
+ this.associated.getField().setDisabled( this.namespace.getValue() === this.allValue );
+ }
+ };
+
+}( jQuery, mediaWiki ) );
data: this.namespace !== null && this.relative
? mwTitle.getRelativeText( this.namespace )
: title,
+ title: mwTitle,
imageUrl: this.showImages ? data.imageUrl : null,
description: this.showDescriptions ? data.description : null,
missing: data.missing,
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {string} [data] Page title
+ * @cfg {string} [data] Label to display
+ * @cfg {mw.Title} [title] Page title object
* @cfg {string} [imageUrl] Thumbnail image URL with URL encoding
* @cfg {string} [description] Page description
* @cfg {boolean} [missing] Page doesn't exist
* @cfg {string} [query] Matching query string
*/
mw.widgets.TitleOptionWidget = function MwWidgetsTitleOptionWidget( config ) {
- var icon, title = config.data;
+ var icon;
if ( config.missing ) {
icon = 'page-not-found';
// Config initialization
config = $.extend( {
icon: icon,
- label: title,
- href: mw.util.getUrl( title ),
+ label: config.data,
+ href: config.title.getUrl(),
autoFitLabel: false
}, config );
public function testInLanguageThrows() {
wfMessage( 'foo' )->inLanguage( 123 );
}
+
+ /**
+ * @covers Message::serialize
+ * @covers Message::unserialize
+ */
+ public function testSerialization() {
+ $msg = new Message( 'parentheses' );
+ $msg->rawParams( '<a>foo</a>' );
+ $msg->title( Title::newFromText( 'Testing' ) );
+ $this->assertEquals( '(<a>foo</a>)', $msg->parse(), 'Sanity check' );
+ $msg = unserialize( serialize( $msg ) );
+ $this->assertEquals( '(<a>foo</a>)', $msg->parse() );
+ $title = TestingAccessWrapper::newFromObject( $msg )->title;
+ $this->assertInstanceOf( 'Title', $title );
+ $this->assertEquals( 'Testing', $title->getFullText() );
+
+ $msg = new Message( 'mainpage' );
+ $msg->inLanguage( 'de' );
+ $this->assertEquals( 'Hauptseite', $msg->plain(), 'Sanity check' );
+ $msg = unserialize( serialize( $msg ) );
+ $this->assertEquals( 'Hauptseite', $msg->plain() );
+ }
}
$msg = TestingAccessWrapper::newFromObject( $msg );
$msg2 = TestingAccessWrapper::newFromObject( $msg2 );
- foreach ( array( 'interface', 'useDatabase', 'title' ) as $key ) {
- $this->assertSame( $msg->$key, $msg2->$key, $key );
- }
+ $this->assertSame( $msg->interface, $msg2->interface, 'interface' );
+ $this->assertSame( $msg->useDatabase, $msg2->useDatabase, 'useDatabase' );
+ $this->assertSame(
+ $msg->title ? $msg->title->getFullText() : null,
+ $msg2->title ? $msg2->title->getFullText() : null,
+ 'title'
+ );
}
/**
$this->assertEquals( 'code', $msg2->getApiCode() );
$this->assertEquals( array( 'data' ), $msg2->getApiData() );
+ $msg2 = unserialize( serialize( $msg2 ) );
+ $this->compareMessages( $msg, $msg2 );
+ $this->assertEquals( 'code', $msg2->getApiCode() );
+ $this->assertEquals( array( 'data' ), $msg2->getApiData() );
+
$msg = new Message( array( 'foo', 'bar' ), array( 'baz' ) );
$msg2 = new ApiMessage( array( array( 'foo', 'bar' ), 'baz' ), 'code', array( 'data' ) );
$this->compareMessages( $msg, $msg2 );
$this->assertEquals( 'code', $msg2->getApiCode() );
$this->assertEquals( array( 'data' ), $msg2->getApiData() );
+ $msg2 = unserialize( serialize( $msg2 ) );
+ $this->compareMessages( $msg, $msg2 );
+ $this->assertEquals( 'code', $msg2->getApiCode() );
+ $this->assertEquals( array( 'data' ), $msg2->getApiData() );
+
$msg = new RawMessage( 'foo', array( 'baz' ) );
$msg2 = new ApiRawMessage( array( 'foo', 'baz' ), 'code', array( 'data' ) );
$this->compareMessages( $msg, $msg2 );
$headers[] = 'Vary: ' . implode( ', ', $varyHeader );
}
- $stats = RequestContext::getMain()->getStats();
-
// Stream the file if it exists already...
$thumbPath = $img->getThumbPath( $thumbName );
if ( $img->getRepo()->fileExists( $thumbPath ) ) {
if ( !$success ) {
wfThumbError( 500, 'Could not stream the file' );
} else {
- $stats->timing( 'media.thumbnail.stream', $streamtime );
+ RequestContext::getMain()->getStats()->timing( 'media.thumbnail.stream', $streamtime );
}
return;
}
return;
}
- // Actually generate a new thumbnail
- $starttime = microtime( true );
list( $thumb, $errorMsg ) = wfGenerateThumbnail( $img, $params, $thumbName, $thumbPath );
- $generatetime = microtime( true ) - $starttime;
+
/** @var MediaTransformOutput|bool $thumb */
// Check for thumbnail generation errors...
if ( $errorMsg !== false ) {
wfThumbError( $errorCode, $errorMsg );
} else {
- $stats->timing( 'media.thumbnail.generate', $generatetime );
-
// Stream the file if there were no errors
$success = $thumb->streamFile( $headers );
if ( !$success ) {