* OutputPage::enableSectionEditLinks()
* OutputPage::sectionEditLinksEnabled()
* The public ParserOutput state fields $mTOCEnabled and $mEditSectionTokens are also deprecated.
+* The following methods and constants from the WatchedItem class were deprecated in
+ 1.27 have been removed.
+ * WatchedItem::getTitle()
+ * WatchedItem::fromUserTitle()
+ * WatchedItem::addWatch()
+ * WatchedItem::removeWatch()
+ * WatchedItem::isWatched()
+ * WatchedItem::duplicateEntries()
+ * WatchedItem::IGNORE_USER_RIGHTS
+ * WatchedItem::CHECK_USER_RIGHTS
+ * WatchedItem::DEPRECATED_USAGE_TIMESTAMP
== Compatibility ==
MediaWiki 1.31 requires PHP 5.5.9 or later. There is experimental support for
Return false to stop further processing of the tag
$reader: XMLReader object
-'ImportHandleUnknownUser': When a user does exist locally, this hook is called
+'ImportHandleUnknownUser': When a user doesn't exist locally, this hook is called
to give extensions an opportunity to auto-create it. If the auto-creation is
successful, return false.
$name: User name
}
}
-Autoloader::$psr4Namespaces = AutoLoader::getAutoloadNamespaces();
+AutoLoader::$psr4Namespaces = AutoLoader::getAutoloadNamespaces();
spl_autoload_register( [ 'AutoLoader', 'autoload' ] );
*
* @file
*/
+use MediaWiki\MediaWikiServices;
use Wikimedia\Timestamp\TimestampException;
use Wikimedia\Rdbms\IDatabase;
}
$this->dest->invalidateCache(); // update histories
+ // Duplicate watchers of the old article to the new article on history merge
+ $store = MediaWikiServices::getInstance()->getWatchedItemStore();
+ $store->duplicateAllAssociatedEntries( $this->source, $this->dest );
+
// Update our logs
$logEntry = new ManualLogEntry( 'merge', 'merge' );
$logEntry->setPerformer( $user );
"api-help-param-direction": "En que dirección enumerar:\n;newer:Lista os máis antigos primeiro. Nota: $1start ten que estar antes que $1end.\n;older:Lista os máis novos primeiro (por defecto). Nota: $1start ten que estar despois que $1end.",
"api-help-param-continue": "Cando estean dispoñibles máis resultados, use isto para continuar.",
"api-help-param-no-description": "<span class=\"apihelp-empty\">(sen descrición)</span>",
+ "api-help-param-maxbytes": "Non pode ser máis longo que $1 {{PLURAL:$1|byte|bytes}}.",
+ "api-help-param-maxchars": "Non pode ser máis longo que $1 {{PLURAL:$1|carácter|caracteres}}.",
"api-help-examples": "{{PLURAL:$1|Exemplo|Exemplos}}:",
"api-help-permissions": "{{PLURAL:$1|Permiso|Permisos}}:",
"api-help-permissions-granted-to": "{{PLURAL:$1|Concedida a|Concedidas a}}: $2",
* @param FormOptions $opts
* @return bool
*/
- public function activelyInConflictWithFilter( ChangeslistFilter $filter, FormOptions $opts ) {
+ public function activelyInConflictWithFilter( ChangesListFilter $filter, FormOptions $opts ) {
if ( $this->isSelected( $opts ) && $filter->isSelected( $opts ) ) {
/** @var ChangesListFilter $siblingFilter */
foreach ( $this->getSiblings() as $siblingFilter ) {
return false;
}
- private function hasConflictWithFilter( ChangeslistFilter $filter ) {
+ private function hasConflictWithFilter( ChangesListFilter $filter ) {
return in_array( $filter, $this->getConflictingFilters() );
}
}
// New page created
- if ( $flags & EDIT_NEW && $newContent && $newContent->getSize() > 0 ) {
- return 'newpage';
- }
-
- // New blank page
- if ( $flags & EDIT_NEW && $newContent && $newContent->getSize() === 0 ) {
- return 'newblank';
+ if ( $flags & EDIT_NEW && $newContent ) {
+ if ( $newContent->getSize() === 0 ) {
+ // New blank page
+ return 'newblank';
+ } else {
+ return 'newpage';
+ }
}
// Removing more than 90% of the page
"config-email-auth-help": "Si esta opción está habilitada, los usuarios tienen que confirmar su dirección de correo electrónico mediante un enlace que se les envía a ellos cuando éstos lo establecen o lo cambian.\nSolo las direcciones de correo electrónico autenticadas pueden recibir correos electrónicos de otros usuarios o correos electrónicos de notificación de cambios.\nEsta opción está '''recomendada''' para wikis públicos debido a posibles abusos de las características del correo electrónico.",
"config-email-sender": "Dirección de correo electrónico de retorno:",
"config-email-sender-help": "Escribe la dirección de correo electrónico que se usará como dirección de retorno en los mensajes electrónicos de salida.\nAquí llegarán los correos electrónicos que no lleguen a su destino.\nMuchos servidores de correo electrónico exigen que por lo menos la parte del nombre del dominio sea válida.",
- "config-upload-settings": "Subidas de imágenes y archivos",
+ "config-upload-settings": "Cargas de imágenes y archivos",
"config-upload-enable": "Habilitar la subida de archivos",
"config-upload-help": "La subida de archivos potencialmente expone tu servidor a riesgos de seguridad.\nPara obtener más información, consulta la [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security sección de seguridad] en el manual.\n\nPara activar la subida de archivos, cambia el modo en el subdirectorio <code>images</code> bajo el directorio raíz de MediaWiki para que el servidor web pueda escribir en él.\nLuego, activa esta opción.",
"config-upload-deleted": "Directorio para los archivos eliminados:",
"config-install-mainpage-failed": "Non se puido inserir a páxina principal: $1",
"config-install-done": "<strong>Parabéns!</strong>\nInstalou MediaWiki.\n\nO programa de instalación xerou un ficheiro <code>LocalSettings.php</code>.\nEste ficheiro contén toda a súa configuración.\n\nTerá que descargalo e poñelo na base da instalación do seu wiki (no mesmo directorio ca index.php). A descarga debería comezar automaticamente.\n\nSe non comezou a descarga ou se a cancelou, pode facer que comece de novo premendo na ligazón que aparece a continuación:\n\n$3\n\n<strong>Nota:</strong> Se non fai iso agora, este ficheiro de configuración xerado non estará dispoñible máis adiante se sae da instalación sen descargalo.\n\nCando faga todo isto, xa poderá <strong>[$2 entrar no seu wiki]</strong>.",
"config-install-done-path": "<strong>Parabéns!</strong>\nInstalou MediaWiki.\n\nO instalador xerou un ficheiro <code>LocalSettings.php</code>.\nEste contén toda a súa configuración.\n\nDeberá descargalo e poñerlo en <code>$4</code>. A descarga debería ter comezado automaticamente.\n\nSe non comenzou a descarga, ou se a cancelou, podes reiniciala descarga premendo na seguinte ligazón:\n\n$3\n\n<strong>Nota</strong>: se non fai isto agora, este ficheiro de configuración xerado non estará dispoñible máis tarde se sae da instalación sen descargarlo.\n\nCando o teña feito, poderá <strong>[$2 entrar na súa wiki]</strong>.",
+ "config-install-success": "MediaWiki instalouse con éxito. Agora podes \nvisitar <$1$2> para ver a túa wiki.\nSe tes dúbidas, revisa a nosa lista de preguntas frecuentes:\n<https://www.mediawiki.org/wiki/Manual:FAQ> ou usa un dos\nforos de axuda ligados nesa páxina.",
"config-download-localsettings": "Descargar o <code>LocalSettings.php</code>",
"config-help": "axuda",
"config-help-tooltip": "prema para expandir",
*/
private $logger;
+ /**
+ * @var string
+ */
+ private $filename;
+
/**
* Primary job is to initialize the XMLParser
* @param LoggerInterface|null $logger
+ * @param string $filename
*/
- function __construct( LoggerInterface $logger = null ) {
+ function __construct( LoggerInterface $logger = null, $filename = 'unknown' ) {
if ( !function_exists( 'xml_parser_create_ns' ) ) {
// this should already be checked by this point
throw new RuntimeException( 'XMP support requires XML Parser' );
} else {
$this->setLogger( new NullLogger() );
}
+ $this->filename = $filename;
$this->items = XMPInfo::getItems();
$this->logger->info(
'{method} : Error reading XMP content: {error} ' .
- '(line: {line} column: {column} byte offset: {offset})',
+ '(file: {file}, line: {line} column: {column} ' .
+ 'byte offset: {offset})',
[
'method' => __METHOD__,
'error_code' => $code,
'error' => $error,
+ 'file' => $this->filename,
'line' => $line,
'column' => $col,
'offset' => $offset,
[
'method' => __METHOD__,
'exception' => $e,
+ 'file' => $this->filename,
'content' => $content,
]
);
) {
$this->logger->info( __METHOD__ .
" Ignoring XMPExtended block due to wrong guid (guid= '{guid}')",
- [ 'guid' => 'guid' ] );
+ [
+ 'guid' => $guid,
+ 'file' => $this->filename,
+ ]
+ );
return false;
}
$len['offset'] > $len['length']
) {
$this->logger->info(
- __METHOD__ . 'Error reading extended XMP block, invalid length or offset.'
+ __METHOD__ . 'Error reading extended XMP block, invalid length or offset.',
+ [ 'file' => $this->filename ]
);
return false;
if ( $len['offset'] !== $this->extendedXMPOffset ) {
$this->logger->info( __METHOD__ . 'Ignoring XMPExtended block due to wrong order. (Offset was '
- . $len['offset'] . ' but expected ' . $this->extendedXMPOffset . ')' );
+ . $len['offset'] . ' but expected ' . $this->extendedXMPOffset . ')',
+ [ 'file' => $this->filename ]
+ );
return false;
}
$atEnd = false;
}
- $this->logger->debug( __METHOD__ . 'Parsing a XMPExtended block' );
+ $this->logger->debug(
+ __METHOD__ . 'Parsing a XMPExtended block',
+ [ 'file' => $this->filename ]
+ );
return $this->parse( $actualContent, $atEnd );
}
if ( !isset( $this->results['xmp-' . $info['map_group']][$finalName] ) ) {
// This can happen if all the members of the struct failed validation.
- $this->logger->debug( __METHOD__ . " <$ns:$tag> has no valid members." );
+ $this->logger->debug(
+ __METHOD__ . " <$ns:$tag> has no valid members.",
+ [ 'file' => $this->filename ]
+ );
} elseif ( is_callable( $validate ) ) {
$val =& $this->results['xmp-' . $info['map_group']][$finalName];
call_user_func_array( $validate, [ $info, &$val, false ] );
if ( is_null( $val ) ) {
// the idea being the validation function will unset the variable if
// its invalid.
- $this->logger->info( __METHOD__ . " <$ns:$tag> failed validation." );
+ $this->logger->info(
+ __METHOD__ . " <$ns:$tag> failed validation.",
+ [ 'file' => $this->filename ]
+ );
unset( $this->results['xmp-' . $info['map_group']][$finalName] );
}
} else {
- $this->logger->warning( __METHOD__ . " Validation function for $finalName ("
- . $validate[0] . '::' . $validate[1] . '()) is not callable.' );
+ $this->logger->warning(
+ __METHOD__ . " Validation function for $finalName (" .
+ $validate[0] . '::' . $validate[1] . '()) is not callable.',
+ [ 'file' => $this->filename ]
+ );
}
}
array_shift( $this->mode );
if ( !isset( $this->results['xmp-' . $info['map_group']][$finalName] ) ) {
- $this->logger->debug( __METHOD__ . " Empty compund element $finalName." );
+ $this->logger->debug(
+ __METHOD__ . " Empty compund element $finalName.",
+ [ 'file' => $this->filename ]
+ );
return;
}
if ( $elm === self::NS_RDF . ' type' ) {
// these aren't really supported properly yet.
// However, it appears they almost never used.
- $this->logger->info( __METHOD__ . ' encountered <rdf:type>' );
+ $this->logger->info(
+ __METHOD__ . ' encountered <rdf:type>',
+ [ 'file' => $this->filename ]
+ );
}
if ( strpos( $elm, ' ' ) === false ) {
// However, there is a bug in an adobe product
// that forgets the namespace on some things.
// (Luckily they are unimportant things).
- $this->logger->info( __METHOD__ . " Encountered </$elm> which has no namespace. Skipping." );
+ $this->logger->info(
+ __METHOD__ . " Encountered </$elm> which has no namespace. Skipping.",
+ [ 'file' => $this->filename ]
+ );
return;
}
$this->endElementModeQDesc( $elm );
break;
default:
- $this->logger->warning( __METHOD__ . " no mode (elm = $elm)" );
+ $this->logger->info(
+ __METHOD__ . " no mode (elm = $elm)",
+ [ 'file' => $this->filename ]
+ );
break;
}
}
array_unshift( $this->mode, self::MODE_LI );
} elseif ( $elm === self::NS_RDF . ' Bag' ) {
# T29105
- $this->logger->info( __METHOD__ . ' Expected an rdf:Seq, but got an rdf:Bag. Pretending'
- . ' it is a Seq, since some buggy software is known to screw this up.' );
+ $this->logger->info(
+ __METHOD__ . ' Expected an rdf:Seq, but got an rdf:Bag. Pretending' .
+ ' it is a Seq, since some buggy software is known to screw this up.',
+ [ 'file' => $this->filename ]
+ );
array_unshift( $this->mode, self::MODE_LI );
} else {
throw new RuntimeException( "Expected <rdf:Seq> but got $elm." );
// something else we don't recognize, like a qualifier maybe.
$this->logger->info( __METHOD__ .
" Encountered element <{element}> where only expecting character data as value of {curitem}",
- [ 'element' => $elm, 'curitem' => $this->curItem[0] ] );
+ [
+ 'element' => $elm,
+ 'curitem' => $this->curItem[0],
+ 'file' => $this->filename,
+ ]
+ );
array_unshift( $this->mode, self::MODE_IGNORE );
array_unshift( $this->curItem, $elm );
}
// a child of a struct), then something weird is
// happening, so ignore this element and its children.
- $this->logger->warning(
+ $this->logger->info(
'Encountered <{element}> outside of its expected parent. Ignoring.',
- [ 'element' => "$ns:$tag" ]
+ [ 'element' => "$ns:$tag", 'file' => $this->filename ]
);
array_unshift( $this->mode, self::MODE_IGNORE );
} else {
// This element is not on our list of allowed elements so ignore.
$this->logger->debug( __METHOD__ . ' Ignoring unrecognized element <{element}>.',
- [ 'element' => "$ns:$tag" ] );
+ [ 'element' => "$ns:$tag", 'file' => $this->filename ] );
array_unshift( $this->mode, self::MODE_IGNORE );
array_unshift( $this->curItem, $ns . ' ' . $tag );
// on page 25 of part 1 of the xmp standard.
// Also it seems as if exiv2 and exiftool do not support
// this either (That or I misunderstand the standard)
- $this->logger->info( __METHOD__ . ' Encountered <rdf:type> which isn\'t currently supported' );
+ $this->logger->info(
+ __METHOD__ . ' Encountered <rdf:type> which isn\'t currently supported',
+ [ 'file' => $this->filename ]
+ );
}
if ( strpos( $elm, ' ' ) === false ) {
// This probably shouldn't happen.
- $this->logger->info( __METHOD__ . " Encountered <$elm> which has no namespace. Skipping." );
+ $this->logger->info(
+ __METHOD__ . " Encountered <$elm> which has no namespace. Skipping.",
+ [ 'file' => $this->filename ]
+ );
return;
}
if ( strpos( $name, ' ' ) === false ) {
// This shouldn't happen, but so far some old software forgets namespace
// on rdf:about.
- $this->logger->info( __METHOD__ . ' Encountered non-namespaced attribute: '
- . " $name=\"$val\". Skipping. " );
+ $this->logger->info(
+ __METHOD__ . ' Encountered non-namespaced attribute: ' .
+ " $name=\"$val\". Skipping. ",
+ [ 'file' => $this->filename ]
+ );
continue;
}
list( $ns, $tag ) = explode( ' ', $name, 2 );
}
$this->saveValue( $ns, $tag, $val );
} else {
- $this->logger->debug( __METHOD__ . " Ignoring unrecognized element <$ns:$tag>." );
+ $this->logger->debug(
+ __METHOD__ . " Ignoring unrecognized element <$ns:$tag>.",
+ [ 'file' => $this->filename ]
+ );
}
}
}
// the reasoning behind using &$val instead of using the return value
// is to be consistent between here and validating structures.
if ( is_null( $val ) ) {
- $this->logger->info( __METHOD__ . " <$ns:$tag> failed validation." );
+ $this->logger->info(
+ __METHOD__ . " <$ns:$tag> failed validation.",
+ [ 'file' => $this->filename ]
+ );
return;
}
} else {
- $this->logger->warning( __METHOD__ . " Validation function for $finalName ("
- . $validate[0] . '::' . $validate[1] . '()) is not callable.' );
+ $this->logger->warning(
+ __METHOD__ . " Validation function for $finalName (" .
+ $validate[0] . '::' . $validate[1] . '()) is not callable.',
+ [ 'file' => $this->filename ]
+ );
}
}
}
}
if ( isset( $seg['XMP'] ) && $showXMP ) {
- $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ) );
+ $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ), $filename );
$xmp->parse( $seg['XMP'] );
foreach ( $seg['XMP_ext'] as $xmpExt ) {
/* Support for extended xmp in jpeg files
if ( isset( $array['text']['xmp']['x-default'] )
&& $array['text']['xmp']['x-default'] !== '' && $showXMP
) {
- $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ) );
+ $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ), $filename );
$xmp->parse( $array['text']['xmp']['x-default'] );
$xmpRes = $xmp->getResults();
foreach ( $xmpRes as $type => $xmpSection ) {
}
if ( $baseArray['xmp'] !== '' && XMPReader::isSupported() ) {
- $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ) );
+ $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ), $filename );
$xmp->parse( $baseArray['xmp'] );
$xmpRes = $xmp->getResults();
foreach ( $xmpRes as $type => $xmpSection ) {
$text, Title $title, ParserOptions $options,
$linestart = true, $clearState = true, $revid = null
) {
- /**
- * First pass--just handle <nowiki> sections, pass the rest off
- * to internalParse() which does all the real work.
- */
-
- global $wgShowHostnames;
-
if ( $clearState ) {
// We use U+007F DELETE to construct strip markers, so we have to make
// sure that this character does not occur in the input text.
}
}
- # Done parsing! Compute runtime adaptive expiry if set
+ # Compute runtime adaptive expiry if set
$this->mOutput->finalizeAdaptiveCacheExpiry();
# Warn if too many heavyweight parser functions were used
);
}
- # Information on include size limits, for the benefit of users who try to skirt them
+ # Information on limits, for the benefit of users who try to skirt them
if ( $this->mOptions->getEnableLimitReport() ) {
- $max = $this->mOptions->getMaxIncludeSize();
-
- $cpuTime = $this->mOutput->getTimeSinceStart( 'cpu' );
- if ( $cpuTime !== null ) {
- $this->mOutput->setLimitReportData( 'limitreport-cputime',
- sprintf( "%.3f", $cpuTime )
- );
- }
-
- $wallTime = $this->mOutput->getTimeSinceStart( 'wall' );
- $this->mOutput->setLimitReportData( 'limitreport-walltime',
- sprintf( "%.3f", $wallTime )
- );
-
- $this->mOutput->setLimitReportData( 'limitreport-ppvisitednodes',
- [ $this->mPPNodeCount, $this->mOptions->getMaxPPNodeCount() ]
- );
- $this->mOutput->setLimitReportData( 'limitreport-ppgeneratednodes',
- [ $this->mGeneratedPPNodeCount, $this->mOptions->getMaxGeneratedPPNodeCount() ]
- );
- $this->mOutput->setLimitReportData( 'limitreport-postexpandincludesize',
- [ $this->mIncludeSizes['post-expand'], $max ]
- );
- $this->mOutput->setLimitReportData( 'limitreport-templateargumentsize',
- [ $this->mIncludeSizes['arg'], $max ]
- );
- $this->mOutput->setLimitReportData( 'limitreport-expansiondepth',
- [ $this->mHighestExpansionDepth, $this->mOptions->getMaxPPExpandDepth() ]
- );
- $this->mOutput->setLimitReportData( 'limitreport-expensivefunctioncount',
- [ $this->mExpensiveFunctionCount, $this->mOptions->getExpensiveParserFunctionLimit() ]
- );
- Hooks::run( 'ParserLimitReportPrepare', [ $this, $this->mOutput ] );
-
- $limitReport = "NewPP limit report\n";
- if ( $wgShowHostnames ) {
- $limitReport .= 'Parsed by ' . wfHostname() . "\n";
- }
- $limitReport .= 'Cached time: ' . $this->mOutput->getCacheTime() . "\n";
- $limitReport .= 'Cache expiry: ' . $this->mOutput->getCacheExpiry() . "\n";
- $limitReport .= 'Dynamic content: ' .
- ( $this->mOutput->hasDynamicContent() ? 'true' : 'false' ) .
- "\n";
-
- foreach ( $this->mOutput->getLimitReportData() as $key => $value ) {
- if ( Hooks::run( 'ParserLimitReportFormat',
- [ $key, &$value, &$limitReport, false, false ]
- ) ) {
- $keyMsg = wfMessage( $key )->inLanguage( 'en' )->useDatabase( false );
- $valueMsg = wfMessage( [ "$key-value-text", "$key-value" ] )
- ->inLanguage( 'en' )->useDatabase( false );
- if ( !$valueMsg->exists() ) {
- $valueMsg = new RawMessage( '$1' );
- }
- if ( !$keyMsg->isDisabled() && !$valueMsg->isDisabled() ) {
- $valueMsg->params( $value );
- $limitReport .= "{$keyMsg->text()}: {$valueMsg->text()}\n";
- }
- }
- }
- // Since we're not really outputting HTML, decode the entities and
- // then re-encode the things that need hiding inside HTML comments.
- $limitReport = htmlspecialchars_decode( $limitReport );
- // Run deprecated hook
- Hooks::run( 'ParserLimitReport', [ $this, &$limitReport ], '1.22' );
-
- // Sanitize for comment. Note '‐' in the replacement is U+2010,
- // which looks much like the problematic '-'.
- $limitReport = str_replace( [ '-', '&' ], [ '‐', '&' ], $limitReport );
- $text .= "\n<!-- \n$limitReport-->\n";
-
- // Add on template profiling data in human/machine readable way
- $dataByFunc = $this->mProfiler->getFunctionStats();
- uasort( $dataByFunc, function ( $a, $b ) {
- return $a['real'] < $b['real']; // descending order
- } );
- $profileReport = [];
- foreach ( array_slice( $dataByFunc, 0, 10 ) as $item ) {
- $profileReport[] = sprintf( "%6.2f%% %8.3f %6d %s",
- $item['%real'], $item['real'], $item['calls'],
- htmlspecialchars( $item['name'] ) );
- }
- $text .= "<!--\nTransclusion expansion time report (%,ms,calls,template)\n";
- $text .= implode( "\n", $profileReport ) . "\n-->\n";
-
- $this->mOutput->setLimitReportData( 'limitreport-timingprofile', $profileReport );
-
- // Add other cache related metadata
- if ( $wgShowHostnames ) {
- $this->mOutput->setLimitReportData( 'cachereport-origin', wfHostname() );
- }
- $this->mOutput->setLimitReportData( 'cachereport-timestamp',
- $this->mOutput->getCacheTime() );
- $this->mOutput->setLimitReportData( 'cachereport-ttl',
- $this->mOutput->getCacheExpiry() );
- $this->mOutput->setLimitReportData( 'cachereport-transientcontent',
- $this->mOutput->hasDynamicContent() );
-
- if ( $this->mGeneratedPPNodeCount > $this->mOptions->getMaxGeneratedPPNodeCount() / 10 ) {
- wfDebugLog( 'generated-pp-node-count', $this->mGeneratedPPNodeCount . ' ' .
- $this->mTitle->getPrefixedDBkey() );
- }
+ $text .= $this->makeLimitReport();
}
# Wrap non-interface parser output in a <div> so it can be targeted
return $this->mOutput;
}
+ /**
+ * Set the limit report data in the current ParserOutput, and return the
+ * limit report HTML comment.
+ *
+ * @return string
+ */
+ protected function makeLimitReport() {
+ global $wgShowHostnames;
+
+ $maxIncludeSize = $this->mOptions->getMaxIncludeSize();
+
+ $cpuTime = $this->mOutput->getTimeSinceStart( 'cpu' );
+ if ( $cpuTime !== null ) {
+ $this->mOutput->setLimitReportData( 'limitreport-cputime',
+ sprintf( "%.3f", $cpuTime )
+ );
+ }
+
+ $wallTime = $this->mOutput->getTimeSinceStart( 'wall' );
+ $this->mOutput->setLimitReportData( 'limitreport-walltime',
+ sprintf( "%.3f", $wallTime )
+ );
+
+ $this->mOutput->setLimitReportData( 'limitreport-ppvisitednodes',
+ [ $this->mPPNodeCount, $this->mOptions->getMaxPPNodeCount() ]
+ );
+ $this->mOutput->setLimitReportData( 'limitreport-ppgeneratednodes',
+ [ $this->mGeneratedPPNodeCount, $this->mOptions->getMaxGeneratedPPNodeCount() ]
+ );
+ $this->mOutput->setLimitReportData( 'limitreport-postexpandincludesize',
+ [ $this->mIncludeSizes['post-expand'], $maxIncludeSize ]
+ );
+ $this->mOutput->setLimitReportData( 'limitreport-templateargumentsize',
+ [ $this->mIncludeSizes['arg'], $maxIncludeSize ]
+ );
+ $this->mOutput->setLimitReportData( 'limitreport-expansiondepth',
+ [ $this->mHighestExpansionDepth, $this->mOptions->getMaxPPExpandDepth() ]
+ );
+ $this->mOutput->setLimitReportData( 'limitreport-expensivefunctioncount',
+ [ $this->mExpensiveFunctionCount, $this->mOptions->getExpensiveParserFunctionLimit() ]
+ );
+ Hooks::run( 'ParserLimitReportPrepare', [ $this, $this->mOutput ] );
+
+ $limitReport = "NewPP limit report\n";
+ if ( $wgShowHostnames ) {
+ $limitReport .= 'Parsed by ' . wfHostname() . "\n";
+ }
+ $limitReport .= 'Cached time: ' . $this->mOutput->getCacheTime() . "\n";
+ $limitReport .= 'Cache expiry: ' . $this->mOutput->getCacheExpiry() . "\n";
+ $limitReport .= 'Dynamic content: ' .
+ ( $this->mOutput->hasDynamicContent() ? 'true' : 'false' ) .
+ "\n";
+
+ foreach ( $this->mOutput->getLimitReportData() as $key => $value ) {
+ if ( Hooks::run( 'ParserLimitReportFormat',
+ [ $key, &$value, &$limitReport, false, false ]
+ ) ) {
+ $keyMsg = wfMessage( $key )->inLanguage( 'en' )->useDatabase( false );
+ $valueMsg = wfMessage( [ "$key-value-text", "$key-value" ] )
+ ->inLanguage( 'en' )->useDatabase( false );
+ if ( !$valueMsg->exists() ) {
+ $valueMsg = new RawMessage( '$1' );
+ }
+ if ( !$keyMsg->isDisabled() && !$valueMsg->isDisabled() ) {
+ $valueMsg->params( $value );
+ $limitReport .= "{$keyMsg->text()}: {$valueMsg->text()}\n";
+ }
+ }
+ }
+ // Since we're not really outputting HTML, decode the entities and
+ // then re-encode the things that need hiding inside HTML comments.
+ $limitReport = htmlspecialchars_decode( $limitReport );
+ // Run deprecated hook
+ Hooks::run( 'ParserLimitReport', [ $this, &$limitReport ], '1.22' );
+
+ // Sanitize for comment. Note '‐' in the replacement is U+2010,
+ // which looks much like the problematic '-'.
+ $limitReport = str_replace( [ '-', '&' ], [ '‐', '&' ], $limitReport );
+ $text = "\n<!-- \n$limitReport-->\n";
+
+ // Add on template profiling data in human/machine readable way
+ $dataByFunc = $this->mProfiler->getFunctionStats();
+ uasort( $dataByFunc, function ( $a, $b ) {
+ return $a['real'] < $b['real']; // descending order
+ } );
+ $profileReport = [];
+ foreach ( array_slice( $dataByFunc, 0, 10 ) as $item ) {
+ $profileReport[] = sprintf( "%6.2f%% %8.3f %6d %s",
+ $item['%real'], $item['real'], $item['calls'],
+ htmlspecialchars( $item['name'] ) );
+ }
+ $text .= "<!--\nTransclusion expansion time report (%,ms,calls,template)\n";
+ $text .= implode( "\n", $profileReport ) . "\n-->\n";
+
+ $this->mOutput->setLimitReportData( 'limitreport-timingprofile', $profileReport );
+
+ // Add other cache related metadata
+ if ( $wgShowHostnames ) {
+ $this->mOutput->setLimitReportData( 'cachereport-origin', wfHostname() );
+ }
+ $this->mOutput->setLimitReportData( 'cachereport-timestamp',
+ $this->mOutput->getCacheTime() );
+ $this->mOutput->setLimitReportData( 'cachereport-ttl',
+ $this->mOutput->getCacheExpiry() );
+ $this->mOutput->setLimitReportData( 'cachereport-transientcontent',
+ $this->mOutput->hasDynamicContent() );
+
+ if ( $this->mGeneratedPPNodeCount > $this->mOptions->getMaxGeneratedPPNodeCount() / 10 ) {
+ wfDebugLog( 'generated-pp-node-count', $this->mGeneratedPPNodeCount . ' ' .
+ $this->mTitle->getPrefixedDBkey() );
+ }
+ return $text;
+ }
+
/**
* Half-parse wikitext to half-parsed HTML. This recursive parser entry point
* can be called from an extension tag hook.
# Replace unnecessary URL escape codes with the referenced character
# This prevents spammers from hiding links from the filters
- $url = parser::normalizeLinkUrl( $url );
+ $url = Parser::normalizeLinkUrl( $url );
$registerExternalLink = true;
if ( !$wgRegisterInternalExternals ) {
}
if ( isset( $info['autoloaderNS'] ) ) {
- Autoloader::$psr4Namespaces += $info['autoloaderNS'];
+ AutoLoader::$psr4Namespaces += $info['autoloaderNS'];
}
foreach ( $info['defines'] as $name => $val ) {
* @param string[] $paths
*/
public function setExcludePaths( array $paths ) {
- $this->excludePaths = $paths;
+ foreach ( $paths as $path ) {
+ $this->excludePaths[] = self::normalizePathSeparator( $path );
+ }
}
/**
* @file
* @ingroup Watchlist
*/
-use MediaWiki\MediaWikiServices;
+
use MediaWiki\Linker\LinkTarget;
/**
* @ingroup Watchlist
*/
class WatchedItem {
-
- /**
- * @deprecated since 1.27, see User::IGNORE_USER_RIGHTS
- */
- const IGNORE_USER_RIGHTS = User::IGNORE_USER_RIGHTS;
-
- /**
- * @deprecated since 1.27, see User::CHECK_USER_RIGHTS
- */
- const CHECK_USER_RIGHTS = User::CHECK_USER_RIGHTS;
-
- /**
- * @deprecated Internal class use only
- */
- const DEPRECATED_USAGE_TIMESTAMP = -100;
-
- /**
- * @var bool
- * @deprecated Internal class use only
- */
- public $checkRights = User::CHECK_USER_RIGHTS;
-
- /**
- * @var Title
- * @deprecated Internal class use only
- */
- private $title;
-
/**
* @var LinkTarget
*/
* @param User $user
* @param LinkTarget $linkTarget
* @param null|string $notificationTimestamp the value of the wl_notificationtimestamp field
- * @param bool|null $checkRights DO NOT USE - used internally for backward compatibility
*/
public function __construct(
User $user,
LinkTarget $linkTarget,
- $notificationTimestamp,
- $checkRights = null
+ $notificationTimestamp
) {
$this->user = $user;
$this->linkTarget = $linkTarget;
$this->notificationTimestamp = $notificationTimestamp;
- if ( $checkRights !== null ) {
- $this->checkRights = $checkRights;
- }
}
/**
* @return bool|null|string
*/
public function getNotificationTimestamp() {
- // Back compat for objects constructed using self::fromUserTitle
- if ( $this->notificationTimestamp === self::DEPRECATED_USAGE_TIMESTAMP ) {
- // wfDeprecated( __METHOD__, '1.27' );
- if ( $this->checkRights && !$this->user->isAllowed( 'viewmywatchlist' ) ) {
- return false;
- }
- $item = MediaWikiServices::getInstance()->getWatchedItemStore()
- ->loadWatchedItem( $this->user, $this->linkTarget );
- if ( $item ) {
- $this->notificationTimestamp = $item->getNotificationTimestamp();
- } else {
- $this->notificationTimestamp = false;
- }
- }
return $this->notificationTimestamp;
}
-
- /**
- * Back compat pre 1.27 with the WatchedItemStore introduction
- * @todo remove in 1.28/9
- * -------------------------------------------------
- */
-
- /**
- * @return Title
- * @deprecated Internal class use only
- */
- public function getTitle() {
- if ( !$this->title ) {
- $this->title = Title::newFromLinkTarget( $this->linkTarget );
- }
- return $this->title;
- }
-
- /**
- * @deprecated since 1.27 Use the constructor, WatchedItemStore::getWatchedItem()
- * or WatchedItemStore::loadWatchedItem()
- */
- public static function fromUserTitle( $user, $title, $checkRights = User::CHECK_USER_RIGHTS ) {
- wfDeprecated( __METHOD__, '1.27' );
- return new self( $user, $title, self::DEPRECATED_USAGE_TIMESTAMP, (bool)$checkRights );
- }
-
- /**
- * @deprecated since 1.27 Use User::addWatch()
- * @return bool
- */
- public function addWatch() {
- wfDeprecated( __METHOD__, '1.27' );
- $this->user->addWatch( $this->getTitle(), $this->checkRights );
- return true;
- }
-
- /**
- * @deprecated since 1.27 Use User::removeWatch()
- * @return bool
- */
- public function removeWatch() {
- wfDeprecated( __METHOD__, '1.27' );
- if ( $this->checkRights && !$this->user->isAllowed( 'editmywatchlist' ) ) {
- return false;
- }
- $this->user->removeWatch( $this->getTitle(), $this->checkRights );
- return true;
- }
-
- /**
- * @deprecated since 1.27 Use User::isWatched()
- * @return bool
- */
- public function isWatched() {
- wfDeprecated( __METHOD__, '1.27' );
- return $this->user->isWatched( $this->getTitle(), $this->checkRights );
- }
-
- /**
- * @deprecated since 1.27 Use WatchedItemStore::duplicateAllAssociatedEntries()
- */
- public static function duplicateEntries( Title $oldTitle, Title $newTitle ) {
- wfDeprecated( __METHOD__, '1.27' );
- $store = MediaWikiServices::getInstance()->getWatchedItemStore();
- $store->duplicateAllAssociatedEntries( $oldTitle, $newTitle );
- }
-
}
"right-siteadmin": "غلق ورفع غلق قاعدة البيانات",
"right-override-export-depth": "تصدير الصفحات متضمنة الصفحات الموصولة حتى عمق 5",
"right-sendemail": "إرسال رسائل بريد إلكتروني إلى مستخدمين آخرين",
+ "right-sendemail-new-users": "إرسال رسالة بريد إلكتروني للمستخدمين الذين ليس لديهم أفعال في السجلات",
"right-managechangetags": "إنشاء وتعطيل [[Special:Tags|الوسوم]]",
"right-applychangetags": "تطبيق [[Special:Tags|الوسوم]] مع التغييرات التي أجريتها.",
"right-changetags": "إضافة وإزالة [[Special:Tags|وسوم]] في مراجعات ومدخلات سجل فردية",
"rcfilters-preference-label": "أخف النسخة المحسنة من أحدث التغييرات",
"rcfilters-preference-help": "يسترجع عملية إعادة تصميم الواجهة لعام 2017 وكل الأدوات التي أضيفت منذ ذلك الوقت.",
"rcfilters-filter-showlinkedfrom-label": "عرض التغييرات في الصفحات الموصولة من",
- "rcfilters-filter-showlinkedfrom-option-label": "أظÙ\87ر اÙ\84تغÙ\8aÙ\8aرات Ù\81Ù\8a اÙ\84صÙ\81Øات اÙ\84Ù\85رتبطة <strong>من</strong> صفحة",
+ "rcfilters-filter-showlinkedfrom-option-label": "عرض اÙ\84تغÙ\8aÙ\8aرات Ù\81Ù\8a اÙ\84صÙ\81Øات اÙ\84Ù\85Ù\88صÙ\88Ù\84ة <strong>من</strong> صفحة",
"rcfilters-filter-showlinkedto-label": "أظهر التغييرات في الصفحات الموصولة بصفحة",
- "rcfilters-filter-showlinkedto-option-label": "اظÙ\87ر اÙ\84تغÙ\8aÙ\8aرات Ù\81Ù\8a اÙ\84صÙ\81Øات اÙ\84Ù\85رتبطة <strong>Ø¥Ù\84Ù\89</strong> اÙ\84صفحة",
+ "rcfilters-filter-showlinkedto-option-label": "عرض اÙ\84تغÙ\8aÙ\8aرات Ù\81Ù\8a اÙ\84صÙ\81Øات اÙ\84Ù\85Ù\88صÙ\88Ù\84Ø© <strong>Ø¥Ù\84Ù\89</strong> صفحة",
"rcfilters-target-page-placeholder": "أدخل اسم صفحة",
"rcnotefrom": "بالأسفل {{PLURAL:$5|التغيير|التغييرات}} منذ <strong>$2</strong> (إلى <strong>$1</strong> معروضة).",
"rclistfromreset": "إعادة ضبط خيار التاريخ",
"uploadstash-not-logged-in": "Удзельнік не ўвайшоў у сыстэму, файлы мусяць належаць удзельнікам.",
"uploadstash-wrong-owner": "Гэты файл ($1) не належыць цяперашняму ўдзельніку.",
"uploadstash-no-such-key": "Няма такога ключа ($1), немагчыма выдаліць.",
+ "uploadstash-no-extension": "Пустое пашырэньне.",
"invalid-chunk-offset": "Няслушнае зрушэньне фрагмэнту",
"img-auth-accessdenied": "Доступ забаронены",
"img-auth-nopathinfo": "Адсутнічае PATH_INFO.\nВаш сэрвэр не ўстаноўлены на пропуск гэтай інфармацыі.\nМагчма, ён працуе праз CGI і не падтрымлівае img_auth.\nГлядзіце https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
"tog-shownumberswatching": "Показване на броя на потребителите, наблюдаващи дадена страница",
"tog-oldsig": "Вашият текущ подпис:",
"tog-fancysig": "Без превръщане на подписа в препратка към потребителската страница",
- "tog-uselivepreview": "Ð\98зползване на бÑ\8aÑ\80з пÑ\80едваÑ\80иÑ\82елен пÑ\80еглед",
+ "tog-uselivepreview": "Ð\9fоказване на пÑ\80едваÑ\80иÑ\82елен пÑ\80еглед без пÑ\80езаÑ\80еждане на Ñ\81Ñ\82Ñ\80аниÑ\86аÑ\82а",
"tog-forceeditsummary": "Предупреждаване при празно поле за резюме на редакцията",
"tog-watchlisthideown": "Скриване на моите редакции в списъка ми за наблюдение",
"tog-watchlisthidebots": "Скриване на редакциите на ботове в списъка ми за наблюдение",
"anoneditwarning": "<strong>Внимание:</strong> Не сте влезли в системата. Ако направите редакция IP-адресът Ви ще бъде публично видим. Ако <strong>[$1 влезете]</strong> или си <strong>[$2 създадете акаунт]</strong>, редакциите Ви ще бъдат свързани с потребителското Ви име, заедно с други преимущества.",
"anonpreviewwarning": "<em>Не сте влезли в системата. Ако съхраните редакцията си, тя ще бъде записана в историята на страницата с вашия IP-адрес.</em>",
"missingsummary": "<strong>Напомняне:</strong> Не е въведено кратко описание на промените.\nПри повторно натискане на бутона „$1“, редакцията ще бъде съхранена без резюме.",
- "missingcommenttext": "Ð\9fо-долÑ\83 вÑ\8aведеÑ\82е ваÑ\88еÑ\82о Ñ\81Ñ\8aобÑ\89ение.",
+ "missingcommenttext": "Ð\9cолÑ\8f, вÑ\8aведеÑ\82е коменÑ\82аÑ\80.",
"missingcommentheader": "<strong>Напомняне:</strong> Не е въведено заглавие на коментара.\nПри повторно натискане на „$1“, редакцията ще бъде записана без коментар.",
"summary-preview": "Предварителен преглед на резюмето:",
"subject-preview": "Предварителен преглед на заглавието:",
"prefs-editwatchlist-clear": "Изчистване на списъка за наблюдение",
"prefs-watchlist-days": "Брой дни, които да се показват в списъка за наблюдение:",
"prefs-watchlist-days-max": "Най-много $1 {{PLURAL:$1|ден|дни}}",
- "prefs-watchlist-edits": "Ð\91Ñ\80ой Ñ\80едакÑ\86ии, коиÑ\82о Ñ\81е показваÑ\82 в Ñ\80азÑ\88иÑ\80ениÑ\8f Ñ\81пиÑ\81Ñ\8aк за наблюдение:",
+ "prefs-watchlist-edits": "Ð\9cакÑ\81имален бÑ\80ой Ñ\80едакÑ\86ии в Ñ\81пиÑ\81Ñ\8aка за наблюдение:",
"prefs-watchlist-edits-max": "Максимален брой: 1000",
"prefs-watchlist-token": "Уникален идентификатор на списъка за наблюдение:",
"prefs-misc": "Други",
"recentchangeslinked-feed": "Свързани промени",
"recentchangeslinked-toolbox": "Свързани промени",
"recentchangeslinked-title": "Промени, свързани с „$1“",
- "recentchangeslinked-summary": "Тук се показват последните промени на страниците, към които се препраща от дадена страница. При избиране на категория, се показват промените по страниците, влизащи в нея. ''Пример:'' Ако изберете страницата '''А''', която съдържа препратки към '''Б''' и '''В''', тогава ще можете да прегледате промените по '''Б''' и '''В'''.\n\nАко пък сложите отметка пред '''Обръщане на релацията''', ще можете да прегледате промените в обратна посока: ще се включат тези страници, които съдържат препратки към посочената страница.\n\nСтраниците от списъка ви за наблюдение се показват в '''получер'''.",
+ "recentchangeslinked-summary": "Тук се показват последните промени на страниците, към които се препраща от дадена страница. При избиране на категория, се показват промените по страниците, влизащи в нея. ''Пример:'' Ако изберете страницата '''А''', която съдържа препратки към '''Б''' и '''В''', тогава ще можете да прегледате промените по '''Б''' и '''В'''.\n\nАко пък сложите отметка пред '''Обръщане на релацията''', ще можете да прегледате промените в обратна посока: ще се включат тези страници, които съдържат препратки към посочената страница.\n\nСтраниците от [[Special:Watchlist|списъка ви за наблюдение]] се показват в <strong>получер</strong>.",
"recentchangeslinked-page": "Име на страницата:",
"recentchangeslinked-to": "Обръщане на релацията, така че да се показват промените на страниците, сочещи към избраната страница",
"recentchanges-page-added-to-category": "[[:$1]] е добавена към категория",
"timezoneregion-indian": "Indický oceán",
"timezoneregion-pacific": "Tichý oceán",
"allowemail": "Dovolit ostatním uživatelům posílat mi e-maily",
+ "email-allow-new-users-label": "Povolit e-maily od zcela nových uživatelů",
"email-blacklist-label": "Znemožnit těmto uživatelům posílat mi e-maily:",
"prefs-searchoptions": "Vyhledávání",
"prefs-namespaces": "Jmenné prostory",
"right-siteadmin": "Zamykání a odemykání databáze",
"right-override-export-depth": "Exportovat stránky včetně odkazovaných stránek až do hloubky 5",
"right-sendemail": "Odesílání e-mailů ostatním uživatelům",
+ "right-sendemail-new-users": "Posílat e-maily uživatelům bez zaznamenaných činností",
"right-managechangetags": "Vytváření a (de)aktivace [[Special:Tags|značek]]",
"right-applychangetags": "Přidávání [[Special:Tags|značek]] k vlastním změnám",
"right-changetags": "Přidávání libovolných [[Special:Tags|značek]] na jednotlivé revize a protokolovací záznamy a jejich odebírání",
"recentchangeslinked-feed": "Související změny",
"recentchangeslinked-toolbox": "Související změny",
"recentchangeslinked-title": "Související změny pro stránku „$1“",
- "recentchangeslinked-summary": "Níže je seznam nedávných změn stránek odkazovaných ze zadané stránky (nebo patřících do dané kategorie). Vaše [[Special:Watchlist|sledované stránky]] jsou '''zvýrazněny'''.",
+ "recentchangeslinked-summary": "Vložením názvu stránky uvidíte změny stránek, které na stránku odkazují nebo na které stránka odkazuje. (Pro stránky zařazené do kategorie vložte Kategorie:Název kategorie.) Vámi [[Special:Watchlist|sledované stránky]] jsou <strong>zvýrazněny</strong>.",
"recentchangeslinked-page": "Název stránky:",
"recentchangeslinked-to": "Zobrazit změny na stránkách odkazujících na zadanou stránku",
"recentchanges-page-added-to-category": "Stránka [[:$1]] zařazena do kategorie",
"tag-mw-replace": "Nahrazeno",
"tag-mw-replace-description": "Editace, které odstraňují více než 90 % obsahu stránky",
"tag-mw-rollback": "Rychlý revert",
+ "tag-mw-rollback-description": "Editace, jimiž byly předchozí editace vráceny zpět pomocí rychlého revertu",
"tags-title": "Značky",
"tags-intro": "Tato stránka obsahuje seznam značek, kterými může software označovat jednotlivé editace, a jejich významy.",
"tags-tag": "Název značky",
"rcfilters-filter-categorization-description": "Optegnelser af at sider bliver tilføjet til eller fjernet fra kategorier.",
"rcfilters-filter-logactions-label": "Loggede handlinger",
"rcfilters-filter-logactions-description": "Administrative handlinger, kontooprettelser, sidesletninger, uploads...",
- "rcfilters-filtergroup-lastRevision": "Sidste revision",
+ "rcfilters-filtergroup-lastRevision": "Seneste revisioner",
"rcfilters-filter-lastrevision-label": "Seneste revision",
- "rcfilters-filter-lastrevision-description": "Den nyeste ændring af en side.",
- "rcfilters-filter-previousrevision-label": "Tidligere revisioner",
+ "rcfilters-filter-lastrevision-description": "Kun den seneste ændring af en side.",
+ "rcfilters-filter-previousrevision-label": "Ikke den seneste revision",
"rcfilters-filter-previousrevision-description": "Alle ændringer som ikke er »seneste revision«.",
"rcfilters-filter-excluded": "Ekskluderet",
"rcfilters-view-tags": "Mærkede redigeringer",
"rcfilters-watchlist-markseen-button": "Marker alle ændringer som set",
"rcfilters-watchlist-edit-watchlist-button": "Rediger din liste med overvågede sider",
"rcfilters-preference-label": "Skjul den forbedrede verson af Seneste ændringer",
+ "rcfilters-target-page-placeholder": "Indtast et sidenavn",
"rcnotefrom": "Nedenfor er op til '''$1''' {{PLURAL:$5|ændring|ændringer}} siden '''$2''' vist.",
"rclistfromreset": "Nulstil datovalg",
"rclistfrom": "Vis nye ændringer startende fra den $3 kl. $2",
"uploaddisabledtext": "Oplægning af filer er deaktiveret.",
"php-uploaddisabledtext": "Oplægning af filer er forhindret i PHP. Tjek indstillingen for file_uploads.",
"uploadscripted": "Denne fil indeholder HTML eller script-kode, der i visse tilfælde can fejlfortolkes af en browser.",
+ "uploaded-href-unsafe-target-svg": "Fandt href til usikre data: URI-mål <code><$1 $2=\"$3\"></code> i den overførte SVG-fil.",
"uploadscriptednamespace": "Denne SVG-fil indeholder et ulovligt navnerum \"<nowiki>$1</nowiki>\"",
"uploadinvalidxml": "XML i den uploadede fil kunne ikke tolkes.",
"uploadvirus": "Denne fil indeholder en virus! Virusnavn: $1",
"rcfilters-restore-default-filters": "Restaurar filtros predeterminados",
"rcfilters-clear-all-filters": "Borrar todos los filtros",
"rcfilters-show-new-changes": "Ver cambios más recientes",
- "rcfilters-search-placeholder": "Filtrar cambios (usa el menú o buscar para aplicar filtro)",
+ "rcfilters-search-placeholder": "Filtrar cambios (utiliza el menú o busca el nombre de un filtro)",
"rcfilters-invalid-filter": "Filtro no válido",
"rcfilters-empty-filter": "No hay filtros activos. Se muestran todas las contribuciones.",
"rcfilters-filterlist-title": "Filtros",
"autosumm-blank": "صفحه را خالی کرد",
"autosumm-replace": "جایگزینی صفحه با '$1'",
"autoredircomment": "تغییرمسیر به [[$1]]",
+ "autosumm-removed-redirect": "تغییرمسیر به [[$1]] حذف شد",
"autosumm-new": "صفحهای تازه حاوی «$1» ایجاد کرد",
"autosumm-newblank": "ایجاد صفحه خالی",
"size-bytes": "$1 بایت",
"tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|برچسب|برچسبها}}]]: $2)",
"tag-mw-contentmodelchange": "تغییر مدل محتوا",
"tag-mw-contentmodelchange-description": "ویرایشهایی که [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel مدل محتوای صفحه را تغییر میدهند]",
+ "tag-mw-removed-redirect": "تغییرمسیر حذف شد",
"tags-title": "برچسبها",
"tags-intro": "این صفحه فهرستیاست از برچسبهایی که نرمافزار با آنها ویرایشها را علامتگذری میکند، به همراه معانی آنها.",
"tags-tag": "نام برچسب",
"logentry-delete-delete": "$1 a supprimé la page $3",
"logentry-delete-delete_redir": "$1 a {{GENDER:$2|supprimé}} la redirection vers $3 par écrasement",
"logentry-delete-restore": "$1 a restauré la page $3 ($4)",
- "logentry-delete-restore-nocount": "$1 {{GENDER:$2|a restauré}} la page $3",
+ "logentry-delete-restore-nocount": "$1 a restauré la page $3",
"restore-count-revisions": "{{PLURAL:$1|1 révision|$1 révisions}}",
"restore-count-files": "{{PLURAL:$1|1 fichier|$1 fichiers}}",
"logentry-delete-event": "$1 {{GENDER:$2|a modifié}} la visibilité {{PLURAL:$5|d'un événement du journal|de $5 événements du journal}} sur $3: $4",
"timezoneregion-indian": "Océano Índico",
"timezoneregion-pacific": "Océano Pacífico",
"allowemail": "Admitir mensaxes de correo electrónico doutros usuarios",
+ "email-allow-new-users-label": "Permite correos electrónicos de usuarios novos",
"email-blacklist-label": "Prohibir a eses usuarios enviarme correos electrónicosː",
"prefs-searchoptions": "Procura",
"prefs-namespaces": "Espazos de nomes",
"recentchangeslinked-feed": "Cambios relacionados",
"recentchangeslinked-toolbox": "Cambios relacionados",
"recentchangeslinked-title": "Cambios relacionados con \"$1\"",
- "recentchangeslinked-summary": "Esta é unha lista dos cambios que se realizaron recentemente nas páxinas vinculadas a esta (ou nos membros da categoría especificada).\nAs páxinas da súa [[Special:Watchlist|lista de vixilancia]] aparecen en '''negra'''.",
+ "recentchangeslinked-summary": "Introduce un nome de páxina para ver os cambios en páxinas ligadas dende ou ata esa páxina. (Para ver os membros dunha categoría, introduce Categoría:Nome da categoría). Os cambios na túa [[Special:Watchlist|lista de vixiancia]] están en <strong>negra</strong>.",
"recentchangeslinked-page": "Nome da páxina:",
"recentchangeslinked-to": "Mostrar os cambios relacionados das páxinas que ligan coa dada",
"recentchanges-page-added-to-category": "\"[[:$1]]\" engadiuse á categoría",
"चक्रपाणी",
"Anamdas",
"Sachinkatiyar",
- "Rishi.Singh"
+ "Rishi.Singh",
+ "Clockery"
]
},
"tog-underline": "कड़ियाँ अधोरेखन:",
"watcherrortext": "\"$1\" के लिये आपकी ध्यानसूची सेटिंग बदलते समय त्रुटि हुई।",
"enotif_reset": "सभी पृष्ठ देखे हुए दर्शाएँ",
"enotif_impersonal_salutation": "{{SITENAME}} सदस्य",
- "enotif_subject_deleted": "{{SITENAME}} पृष्ठ $1 को {{gender:$2|$2}} ने हटा दिया है",
- "enotif_subject_created": "{{SITENAME}} पृष्ठ $1 को {{gender:$2|$2}} ने बना दिया है",
- "enotif_subject_moved": "{{SITENAME}} पृष्ठ $1 को {{gender:$2|$2}} ने स्थानांतरित कर दिया है",
- "enotif_subject_restored": "{{SITENAME}} पृष्ठ $1 को {{gender:$2|$2}} ने पुनर्स्थापित कर दिया है",
- "enotif_subject_changed": "{{SITENAME}} पृष्ठ $1 को {{gender:$2|$2}} ने परिवर्तित किया है",
- "enotif_body_intro_deleted": "{{SITENAME}} पृष्ठ $1 को {{gender:$2|$2}} ने $PAGEEDITDATE को हटा दिया है, देखें <$3>।",
- "enotif_body_intro_created": "{{SITENAME}} पृष्ठ $1 को {{gender:$2|$2}} ने $PAGEEDITDATE को बनाया है, वर्तमान अवतरण के लिए $3 देखें।",
- "enotif_body_intro_moved": "{{SITENAME}} पृष्ठ $1 को {{gender:$2|$2}} ने $PAGEEDITDATE को स्थानांतरित किया है, वर्तमान अवतरण के लिए $3 देखें।",
- "enotif_body_intro_restored": "{{SITENAME}} पृष्ठ $1 को {{gender:$2|$2}} ने $PAGEEDITDATE को पुनर्स्थापित किया है, वर्तमान अवतरण के लिए $3 देखें।",
- "enotif_body_intro_changed": "{{SITENAME}} पृष्ठ $1 को {{gender:$2|$2}} ने $PAGEEDITDATE को परिवर्तित किया है, वर्तमान अवतरण के लिए $3 देखें।",
+ "enotif_subject_deleted": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने हटा दिया है",
+ "enotif_subject_created": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने बना दिया है",
+ "enotif_subject_moved": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने स्थानांतरित कर दिया है",
+ "enotif_subject_restored": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने पुनर्स्थापित कर दिया है",
+ "enotif_subject_changed": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने परिवर्तित किया है",
+ "enotif_body_intro_deleted": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने $PAGEEDITDATE को हटा दिया है, देखें $3।",
+ "enotif_body_intro_created": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने $PAGEEDITDATE को बनाया है, वर्तमान अवतरण के लिए $3 देखें।",
+ "enotif_body_intro_moved": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने $PAGEEDITDATE को स्थानांतरित किया है, वर्तमान अवतरण के लिए $3 देखें।",
+ "enotif_body_intro_restored": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने $PAGEEDITDATE को पुनर्स्थापित किया है, वर्तमान अवतरण के लिए $3 देखें।",
+ "enotif_body_intro_changed": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने $PAGEEDITDATE को परिवर्तित किया है, वर्तमान अवतरण के लिए $3 देखें।",
"enotif_lastvisited": "आपकी आखिरी भेंट के बाद हुए बदलाव देखने के लिये $1 देखें।",
"enotif_lastdiff": "इस बदलाव को देखने के लिये $1 देखें।",
"enotif_anon_editor": "अनामक सदस्य $1",
"autosumm-blank": "uklonjen cjelokupni sadržaj stranice",
"autosumm-replace": "Zamijenjen sadržaj stranice s »$1«",
"autoredircomment": "Preusmjeravanje stranice na [[$1]]",
+ "autosumm-removed-redirect": "Uklonjeno preusmjeravanje na [[$1]]",
"autosumm-new": "Stvorena nova stranica sa sadržajem: »$1«.",
"autosumm-newblank": "Stvorena prazna stranica.",
"size-bytes": "$1 {{PLURAL:$1|bajt|bajta|bajtova}}",
"year": "No gada (un senāki):",
"sp-contributions-newbies": "Rādīt jauno lietotāju devumu",
"sp-contributions-newbies-sub": "Jaunie lietotāji",
+ "sp-contributions-newbies-title": "Jauno dalībnieku devums",
"sp-contributions-blocklog": "bloķēšanas reģistrs",
"sp-contributions-suppresslog": "cenzēja {{GENDER:$1|dalībnieka|dalībnieces}} devumu",
"sp-contributions-deleted": "dzēstais {{GENDER:$1|dalībnieka|dalībnieces}} devums",
"ipb_blocked_as_range": "Kļūda: IP $1 nav bloķēta tieši, tāpēc to nevar atbloķēt.\nTā ir bloķēta kā daļa no IP adrešu diapazona $2, kuru var atbloķēt.",
"ip_range_invalid": "Nederīgs IP diapazons",
"proxyblocker": "Starpniekservera bloķētājs",
+ "softblockrangesreason": "No tavas IP adreses ($1) nav atļauts anonīms devums. Lūdzu, pieslēdzies.",
"ipbblocked": "Tu nevar bloķēt vai atbloķēt lietotājus, jo Tu pats esi bloķēts",
"ipbnounblockself": "Tev nav atļauts sevi atbloķēt",
"lockdb": "Bloķēt datubāzi",
"newimages-legend": "Filtrs",
"newimages-label": "Faila nosaukums (vai tā daļa):",
"newimages-user": "IP adrese vai lietotājvārds",
+ "newimages-newbies": "Rādīt tikai jaunu dalībnieku devumu",
"newimages-showbots": "Parādīt botu augšupielādētos failus",
"newimages-hidepatrolled": "Paslēpt pārbaudītās augšupielādes",
"noimages": "Nav nekā ko redzēt.",
"blankarticle": "<strong>خبرتیا:</strong> تاسو د یو خالي مخ جوړلو په حال کي ياست.\nکه «$1» دوهم ځلي کښي کاږي، نو مخ به د معلوماتو بغير جوړ سي.",
"anoneditwarning": "<strong>گواښنه:</strong> تاسې غونډال کې نه ياست ننوتي. که تاسې کوم سمونونه ترسره کوۍ نو ستاسې IP پته به ټولو ته د دې مخ د سمونونو په پېښليک کې ښکاري. که تاسې په خپل نوم <strong>[$1 کې ننوځئ]</strong> يا <strong>[$2 يو گڼون جوړ کړئ]</strong>، نو ستاسې سمونونه به ستاسې کارن-نوم اړونده ثبت شي چې ډېرې نورې گټې هم لري.",
"anonpreviewwarning": "''تاسې غونډال ته نه ياست ننوتي. خوندي کولو سره به ستاسې IP پته به د دې مخ د سمونونو په پېښليک کې ثبت شي.''",
- "missingsummary": "<strong>یادونه:</strong> تاسو د سمون لنډیز ندی چمتو کړی.\nکه تاسو \"$1\" ټک وکړئبیا به ستاسو بدلون پرته له دې چې يو وي خوندي شي.",
+ "missingsummary": "<strong>یادونه:</strong> تاسو د سمون لنډیز ندی چمتو کړی.\nکه تاسو \"$1\" کليک کړي نو بیا به ستاسو بدلون پرته له کوم انتظاره خوندي شي.",
"selfredirect": "<strong>خبرداری:</strong> تاسو دا پاڼه دپاڼي خپل مخ ته استوي.ښایي تاسو د ګرځولو لپاره ناسم هدف مشخص کړی وي، یا تاسو ممکن په غلطه پاڼه سمونه کوي.\nکه تاسو \"$1\" بيا کلیک کړي، د مخ ورګرځونه به په هر دليل جوړه شي.",
"missingcommenttext": "لطفاً کمينټ لاندې وليکۍ.",
- "missingcommentheader": "<strong>یادونه:</strong> تاسو د سمون لنډیز ندی چمتو کړی.\nکه تاسو \"$1\" ټک وکړئبیا به ستاسو بدلون پرته له دې چې يو وي خوندي شي.",
+ "missingcommentheader": "<strong>یادونه:</strong> تاسو د سمون لنډیز ندی چمتو کړی.\nکه تاسو \"$1\" کليک کړي نو بیا به ستاسو بدلون پرته له کوم انتظاره خوندي شي.",
"summary-preview": "د لنډيز مخليدنه:",
"subject-preview": "د پروژې بيا ليدنه:",
"previewerrortext": "د بدلونونو د مخليدنو په وخت کې مو يوه ستونزه رامېنځ ته شوه.",
"tag-mw-changed-redirect-target-description": "Правки, которые изменяют цель перенаправления",
"tag-mw-blank": "Очистка",
"tag-mw-blank-description": "Правки, которые очищают страницу",
- "tag-mw-replace": "Ð\97аменено",
+ "tag-mw-replace": "заменено",
"tag-mw-replace-description": "Правки, которые удаляют более 90 % содержимого страницы",
"tag-mw-rollback": "откат",
"tag-mw-rollback-description": "Правки, которые откатывают предыдущие правки по нажатию ссылки отката",
"timezoneregion-indian": "Indiska oceanen",
"timezoneregion-pacific": "Stilla havet",
"allowemail": "Låt andra användare skicka e-post till mig",
+ "email-allow-new-users-label": "Tillåt e-post från nyregistrerade användare",
"email-blacklist-label": "Förhindra följande användare att skicka e-post till mig:",
"prefs-searchoptions": "Sök",
"prefs-namespaces": "Namnrymder",
'Blankpage' => [ '빈문서' ],
'Block' => [ '차단', 'IP차단', '사용자차단' ],
'Booksources' => [ '책찾기' ],
+ 'BotPasswords' => [ '봇비밀번호' ],
'BrokenRedirects' => [ '끊긴넘겨주기' ],
'Categories' => [ '분류' ],
+ 'ChangeContentModel' => [ '콘텐츠모델바꾸기', '콘텐츠모델변경' ],
+ 'ChangeCredentials' => [ '자격증명바꾸기', '자격증명변경' ],
'ChangeEmail' => [ '이메일바꾸기', '이메일변경' ],
'ChangePassword' => [ '비밀번호바꾸기', '비밀번호변경' ],
'ComparePages' => [ '문서비교' ],
'DeletedContributions' => [ '삭제된기여' ],
'Diff' => [ '차이' ],
'DoubleRedirects' => [ '이중넘겨주기' ],
+ 'EditTags' => [ '태그편집' ],
'EditWatchlist' => [ '주시문서목록편집' ],
'Emailuser' => [ '이메일보내기', '이메일' ],
'ExpandTemplates' => [ '틀전개' ],
'Fewestrevisions' => [ '역사짧은문서' ],
'FileDuplicateSearch' => [ '중복파일검색', '중복파일찾기' ],
'Filepath' => [ '파일경로', '그림경로' ],
+ 'GoToInterwiki' => [ '인터위키가기' ],
'Import' => [ '가져오기' ],
'Invalidateemail' => [ '이메일인증취소', '이메일인증해제' ],
'JavaScriptTest' => [ '자바스크립트시험', '자바스크립트테스트' ],
'Listadmins' => [ '관리자', '관리자목록' ],
'Listbots' => [ '봇', '봇목록' ],
'Listfiles' => [ '파일', '그림', '파일목록', '그림목록' ],
- 'Listgrouprights' => [ '사용자권한', '권한목록' ],
+ 'Listgrouprights' => [ '사용자권한목록', '사용자권한', '권한목록' ],
+ 'Listgrants' => [ '권한부여목록' ],
'Listredirects' => [ '넘겨주기목록' ],
'ListDuplicatedFiles' => [ '중복된파일목록' ],
'Listusers' => [ '사용자', '사용자목록' ],
mw.rcfilters.ui.MenuSelectWidget.prototype.toggle = function ( show ) {
this.lazyMenuCreation();
mw.rcfilters.ui.MenuSelectWidget.parent.prototype.toggle.call( this, show );
+ // Always open this menu downwards. FilterTagMultiselectWidget scrolls it into view.
+ this.setVerticalPosition( 'below' );
};
/**
];
yield '(ISO-8859-1 encoding), string in string out' => [
'ISO-8859-1',
- iconv( 'utf8', 'ISO-8859-1', "1®Àþ1" ),
+ iconv( 'utf-8', 'ISO-8859-1', "1®Àþ1" ),
[],
'1®Àþ1',
];
yield '(ISO-8859-1 encoding), serialized object in with gzip flags returns string' => [
'ISO-8859-1',
- gzdeflate( iconv( 'utf8', 'ISO-8859-1', "4®Àþ4" ) ),
+ gzdeflate( iconv( 'utf-8', 'ISO-8859-1', "4®Àþ4" ) ),
[ 'gzip' ],
'4®Àþ4',
];
yield '(ISO-8859-1 encoding), serialized object in with object flags returns string' => [
'ISO-8859-1',
- serialize( new TitleValue( 0, iconv( 'utf8', 'ISO-8859-1', "3®Àþ3" ) ) ),
+ serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "3®Àþ3" ) ) ),
[ 'object' ],
'3®Àþ3',
];
yield '(ISO-8859-1 encoding), serialized object in with object & gzip flags returns string' => [
'ISO-8859-1',
- gzdeflate( serialize( new TitleValue( 0, iconv( 'utf8', 'ISO-8859-1', "2®Àþ2" ) ) ) ),
+ gzdeflate( serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "2®Àþ2" ) ) ) ),
[ 'gzip', 'object' ],
'2®Àþ2',
];
class RevisionSlotsTest extends MediaWikiTestCase {
/**
- * @covers RevisionSlots::getSlot
+ * @covers \MediaWiki\Storage\RevisionSlots::getSlot
*/
public function testGetSlot() {
$mainSlot = SlotRecord::newUnsaved( 'main', new WikitextContent( 'A' ) );
}
/**
- * @covers RevisionSlots::getContent
+ * @covers \MediaWiki\Storage\RevisionSlots::getContent
*/
public function testGetContent() {
$mainContent = new WikitextContent( 'A' );
}
/**
- * @covers RevisionSlots::getSlotRoles
+ * @covers \MediaWiki\Storage\RevisionSlots::getSlotRoles
*/
public function testGetSlotRoles_someSlots() {
$mainSlot = SlotRecord::newUnsaved( 'main', new WikitextContent( 'A' ) );
}
/**
- * @covers RevisionSlots::getSlotRoles
+ * @covers \MediaWiki\Storage\RevisionSlots::getSlotRoles
*/
public function testGetSlotRoles_noSlots() {
$slots = new RevisionSlots( [] );
}
/**
- * @covers RevisionSlots::getSlots
+ * @covers \MediaWiki\Storage\RevisionSlots::getSlots
*/
public function testGetSlots() {
$mainSlot = SlotRecord::newUnsaved( 'main', new WikitextContent( 'A' ) );
/**
* @dataProvider provideComputeSize
- * @covers RevisionSlots::computeSize
+ * @covers \MediaWiki\Storage\RevisionSlots::computeSize
*/
public function testComputeSize( $expected, $contentStrings ) {
$slotsArray = [];
/**
* @dataProvider provideComputeSha1
- * @covers RevisionSlots::computeSha1
+ * @covers \MediaWiki\Storage\RevisionSlots::computeSha1
* @note this test is a bit brittle as the hashes are hardcoded, perhaps just check that strings
* are returned and different Slots objects return different strings?
*/
/**
* @dataProvider provideInsertRevisionOn_successes
- * @covers RevisionStore::insertRevisionOn
+ * @covers \MediaWiki\Storage\RevisionStore::insertRevisionOn
*/
public function testInsertRevisionOn_successes( Title $title, array $revDetails = [] ) {
$rev = $this->getRevisionRecordFromDetailsArray( $title, $revDetails );
}
/**
- * @covers RevisionStore::insertRevisionOn
+ * @covers \MediaWiki\Storage\RevisionStore::insertRevisionOn
*/
public function testInsertRevisionOn_blobAddressExists() {
$title = Title::newFromText( 'UTPage' );
/**
* @dataProvider provideInsertRevisionOn_failures
- * @covers RevisionStore::insertRevisionOn
+ * @covers \MediaWiki\Storage\RevisionStore::insertRevisionOn
*/
public function testInsertRevisionOn_failures(
Title $title,
/**
* @dataProvider provideNewNullRevision
- * @covers RevisionStore::newNullRevision
+ * @covers \MediaWiki\Storage\RevisionStore::newNullRevision
*/
public function testNewNullRevision( Title $title, $comment, $minor ) {
$store = MediaWikiServices::getInstance()->getRevisionStore();
}
/**
- * @covers RevisionStore::newNullRevision
+ * @covers \MediaWiki\Storage\RevisionStore::newNullRevision
*/
public function testNewNullRevision_nonExistingTitle() {
$store = MediaWikiServices::getInstance()->getRevisionStore();
}
/**
- * @covers RevisionStore::isUnpatrolled
+ * @covers \MediaWiki\Storage\RevisionStore::isUnpatrolled
*/
public function testIsUnpatrolled_returnsRecentChangesId() {
$page = WikiPage::factory( Title::newFromText( 'UTPage' ) );
}
/**
- * @covers RevisionStore::isUnpatrolled
+ * @covers \MediaWiki\Storage\RevisionStore::isUnpatrolled
*/
public function testIsUnpatrolled_returnsZeroIfPatrolled() {
// This assumes that sysops are auto patrolled
}
/**
- * @covers RevisionStore::getRevisionById
+ * @covers \MediaWiki\Storage\RevisionStore::getRevisionById
*/
public function testGetRevisionById() {
$page = WikiPage::factory( Title::newFromText( 'UTPage' ) );
}
/**
- * @covers RevisionStore::getRevisionByTitle
+ * @covers \MediaWiki\Storage\RevisionStore::getRevisionByTitle
*/
public function testGetRevisionByTitle() {
$page = WikiPage::factory( Title::newFromText( 'UTPage' ) );
}
/**
- * @covers RevisionStore::getRevisionByPageId
+ * @covers \MediaWiki\Storage\RevisionStore::getRevisionByPageId
*/
public function testGetRevisionByPageId() {
$page = WikiPage::factory( Title::newFromText( 'UTPage' ) );
}
/**
- * @covers RevisionStore::getRevisionFromTimestamp
+ * @covers \MediaWiki\Storage\RevisionStore::getRevisionFromTimestamp
*/
public function testGetRevisionFromTimestamp() {
// Make sure there is 1 second between the last revision and the rev we create...
}
/**
- * @covers RevisionStore::newRevisionFromRow
- * @covers RevisionStore::newRevisionFromRow_1_29
+ * @covers \MediaWiki\Storage\RevisionStore::newRevisionFromRow
+ * @covers \MediaWiki\Storage\RevisionStore::newRevisionFromRow_1_29
*/
public function testNewRevisionFromRow_anonEdit() {
$page = WikiPage::factory( Title::newFromText( 'UTPage' ) );
}
/**
- * @covers RevisionStore::newRevisionFromRow
- * @covers RevisionStore::newRevisionFromRow_1_29
+ * @covers \MediaWiki\Storage\RevisionStore::newRevisionFromRow
+ * @covers \MediaWiki\Storage\RevisionStore::newRevisionFromRow_1_29
*/
public function testNewRevisionFromRow_userEdit() {
$page = WikiPage::factory( Title::newFromText( 'UTPage' ) );
}
/**
- * @covers RevisionStore::newRevisionFromArchiveRow
+ * @covers \MediaWiki\Storage\RevisionStore::newRevisionFromArchiveRow
*/
public function testNewRevisionFromArchiveRow() {
$store = MediaWikiServices::getInstance()->getRevisionStore();
}
/**
- * @covers RevisionStore::loadRevisionFromId
+ * @covers \MediaWiki\Storage\RevisionStore::loadRevisionFromId
*/
public function testLoadRevisionFromId() {
$title = Title::newFromText( __METHOD__ );
}
/**
- * @covers RevisionStore::loadRevisionFromPageId
+ * @covers \MediaWiki\Storage\RevisionStore::loadRevisionFromPageId
*/
public function testLoadRevisionFromPageId() {
$title = Title::newFromText( __METHOD__ );
}
/**
- * @covers RevisionStore::loadRevisionFromTitle
+ * @covers \MediaWiki\Storage\RevisionStore::loadRevisionFromTitle
*/
public function testLoadRevisionFromTitle() {
$title = Title::newFromText( __METHOD__ );
}
/**
- * @covers RevisionStore::loadRevisionFromTimestamp
+ * @covers \MediaWiki\Storage\RevisionStore::loadRevisionFromTimestamp
*/
public function testLoadRevisionFromTimestamp() {
$title = Title::newFromText( __METHOD__ );
}
/**
- * @covers RevisionStore::listRevisionSizes
+ * @covers \MediaWiki\Storage\RevisionStore::listRevisionSizes
*/
public function testGetParentLengths() {
$page = WikiPage::factory( Title::newFromText( __METHOD__ ) );
}
/**
- * @covers RevisionStore::getPreviousRevision
+ * @covers \MediaWiki\Storage\RevisionStore::getPreviousRevision
*/
public function testGetPreviousRevision() {
$page = WikiPage::factory( Title::newFromText( __METHOD__ ) );
}
/**
- * @covers RevisionStore::getNextRevision
+ * @covers \MediaWiki\Storage\RevisionStore::getNextRevision
*/
public function testGetNextRevision() {
$page = WikiPage::factory( Title::newFromText( __METHOD__ ) );
}
/**
- * @covers RevisionStore::getTimestampFromId
+ * @covers \MediaWiki\Storage\RevisionStore::getTimestampFromId
*/
public function testGetTimestampFromId_found() {
$page = WikiPage::factory( Title::newFromText( 'UTPage' ) );
}
/**
- * @covers RevisionStore::getTimestampFromId
+ * @covers \MediaWiki\Storage\RevisionStore::getTimestampFromId
*/
public function testGetTimestampFromId_notFound() {
$page = WikiPage::factory( Title::newFromText( 'UTPage' ) );
}
/**
- * @covers RevisionStore::countRevisionsByPageId
+ * @covers \MediaWiki\Storage\RevisionStore::countRevisionsByPageId
*/
public function testCountRevisionsByPageId() {
$store = MediaWikiServices::getInstance()->getRevisionStore();
}
/**
- * @covers RevisionStore::countRevisionsByTitle
+ * @covers \MediaWiki\Storage\RevisionStore::countRevisionsByTitle
*/
public function testCountRevisionsByTitle() {
$store = MediaWikiServices::getInstance()->getRevisionStore();
}
/**
- * @covers RevisionStore::userWasLastToEdit
+ * @covers \MediaWiki\Storage\RevisionStore::userWasLastToEdit
*/
public function testUserWasLastToEdit_false() {
$sysop = $this->getTestSysop()->getUser();
}
/**
- * @covers RevisionStore::userWasLastToEdit
+ * @covers \MediaWiki\Storage\RevisionStore::userWasLastToEdit
*/
public function testUserWasLastToEdit_true() {
$startTime = wfTimestampNow();
}
/**
- * @covers RevisionStore::getKnownCurrentRevision
+ * @covers \MediaWiki\Storage\RevisionStore::getKnownCurrentRevision
*/
public function testGetKnownCurrentRevision() {
$page = WikiPage::factory( Title::newFromText( 'UTPage' ) );
/**
* @dataProvider provideNewMutableRevisionFromArray
- * @covers RevisionStore::newMutableRevisionFromArray
+ * @covers \MediaWiki\Storage\RevisionStore::newMutableRevisionFromArray
*/
public function testNewMutableRevisionFromArray( array $array ) {
$store = MediaWikiServices::getInstance()->getRevisionStore();
private function provideAudienceCheckData( $field ) {
yield 'field accessible for oversighter (ALL)' => [
- Revisionrecord::SUPPRESSED_ALL,
+ RevisionRecord::SUPPRESSED_ALL,
[ 'oversight' ],
true,
false
];
yield 'field accessible for oversighter' => [
- Revisionrecord::DELETED_RESTRICTED | $field,
+ RevisionRecord::DELETED_RESTRICTED | $field,
[ 'oversight' ],
true,
false
];
yield 'field not accessible for sysops (ALL)' => [
- Revisionrecord::SUPPRESSED_ALL,
+ RevisionRecord::SUPPRESSED_ALL,
[ 'sysop' ],
false,
false
];
yield 'field not accessible for sysops' => [
- Revisionrecord::DELETED_RESTRICTED | $field,
+ RevisionRecord::DELETED_RESTRICTED | $field,
[ 'sysop' ],
false,
false
];
yield 'unrelated field suppressed' => [
- $field === Revisionrecord::DELETED_COMMENT
- ? Revisionrecord::DELETED_USER
- : Revisionrecord::DELETED_COMMENT,
+ $field === RevisionRecord::DELETED_COMMENT
+ ? RevisionRecord::DELETED_USER
+ : RevisionRecord::DELETED_COMMENT,
[ 'user' ],
true,
true
/**
* @dataProvider provideUserCanBitfield
- * @covers RevisionRecord::userCanBitfield
+ * @covers \MediaWiki\Storage\RevisionRecord::userCanBitfield
*/
public function testUserCanBitfield( $bitField, $field, $userGroups, $title, $expected ) {
$this->forceStandardPermissions();
/**
* @dataProvider provideHasSameContent
- * @covers RevisionRecord::hasSameContent
+ * @covers \MediaWiki\Storage\RevisionRecord::hasSameContent
* @group Database
*/
public function testHasSameContent(
/**
* @dataProvider provideIsDeleted
- * @covers RevisionRecord::isDeleted
+ * @covers \MediaWiki\Storage\RevisionRecord::isDeleted
*/
public function testIsDeleted( $revDeleted, $assertionMap ) {
$rev = $this->newRevision( [ 'rev_deleted' => $revDeleted ] );
}
/**
- * @covers SqlBlobStore::getCompressBlobs()
- * @covers SqlBlobStore::setCompressBlobs()
+ * @covers \MediaWiki\Storage\SqlBlobStore::getCompressBlobs()
+ * @covers \MediaWiki\Storage\SqlBlobStore::setCompressBlobs()
*/
public function testGetSetCompressRevisions() {
$store = $this->getBlobStore();
}
/**
- * @covers SqlBlobStore::getLegacyEncoding()
- * @covers SqlBlobStore::getLegacyEncodingConversionLang()
- * @covers SqlBlobStore::setLegacyEncoding()
+ * @covers \MediaWiki\Storage\SqlBlobStore::getLegacyEncoding()
+ * @covers \MediaWiki\Storage\SqlBlobStore::getLegacyEncodingConversionLang()
+ * @covers \MediaWiki\Storage\SqlBlobStore::setLegacyEncoding()
*/
public function testGetSetLegacyEncoding() {
$store = $this->getBlobStore();
}
/**
- * @covers SqlBlobStore::getCacheExpiry()
- * @covers SqlBlobStore::setCacheExpiry()
+ * @covers \MediaWiki\Storage\SqlBlobStore::getCacheExpiry()
+ * @covers \MediaWiki\Storage\SqlBlobStore::setCacheExpiry()
*/
public function testGetSetCacheExpiry() {
$store = $this->getBlobStore();
}
/**
- * @covers SqlBlobStore::getUseExternalStore()
- * @covers SqlBlobStore::setUseExternalStore()
+ * @covers \MediaWiki\Storage\SqlBlobStore::getUseExternalStore()
+ * @covers \MediaWiki\Storage\SqlBlobStore::setUseExternalStore()
*/
public function testGetSetUseExternalStore() {
$store = $this->getBlobStore();
];
yield '(ISO-8859-1 encoding), string in string out' => [
'ISO-8859-1',
- iconv( 'utf8', 'ISO-8859-1', "1®Àþ1" ),
+ iconv( 'utf-8', 'ISO-8859-1', "1®Àþ1" ),
[],
'1®Àþ1',
];
yield '(ISO-8859-1 encoding), serialized object in with gzip flags returns string' => [
'ISO-8859-1',
- gzdeflate( iconv( 'utf8', 'ISO-8859-1', "4®Àþ4" ) ),
+ gzdeflate( iconv( 'utf-8', 'ISO-8859-1', "4®Àþ4" ) ),
[ 'gzip' ],
'4®Àþ4',
];
yield '(ISO-8859-1 encoding), serialized object in with object flags returns string' => [
'ISO-8859-1',
- serialize( new TitleValue( 0, iconv( 'utf8', 'ISO-8859-1', "3®Àþ3" ) ) ),
+ serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "3®Àþ3" ) ) ),
[ 'object' ],
'3®Àþ3',
];
yield '(ISO-8859-1 encoding), serialized object in with object & gzip flags returns string' => [
'ISO-8859-1',
- gzdeflate( serialize( new TitleValue( 0, iconv( 'utf8', 'ISO-8859-1', "2®Àþ2" ) ) ) ),
+ gzdeflate( serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "2®Àþ2" ) ) ) ),
[ 'gzip', 'object' ],
'2®Àþ2',
];
/**
* @dataProvider provideDecompress
- * @covers SqlBlobStore::decompressData
+ * @covers \MediaWiki\Storage\SqlBlobStore::decompressData
*
* @param string|bool $legacyEncoding
* @param mixed $data
}
/**
- * @covers SqlBlobStore::compressData
+ * @covers \MediaWiki\Storage\SqlBlobStore::compressData
*/
public function testCompressRevisionTextUtf8() {
$store = $this->getBlobStore();
}
/**
- * @covers SqlBlobStore::compressData
+ * @covers \MediaWiki\Storage\SqlBlobStore::compressData
*/
public function testCompressRevisionTextUtf8Gzip() {
$store = $this->getBlobStore( false, true );
/**
* @dataProvider provideBlobs
- * @covers SqlBlobStore::storeBlob
- * @covers SqlBlobStore::getBlob
+ * @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
+ * @covers \MediaWiki\Storage\SqlBlobStore::getBlob
*/
public function testSimpleStoreGetBlobSimpleRoundtrip( $blob ) {
$store = $this->getBlobStore();
* @covers Job::factory
*/
public function testJobFactory( $handler ) {
- $this->mergeMWGlobalArrayValue( 'wgJobClasses', [ 'testdummy' => $handler ] );
+ $this->mergeMwGlobalArrayValue( 'wgJobClasses', [ 'testdummy' => $handler ] );
$job = Job::factory( 'testdummy', Title::newMainPage(), [] );
$this->assertInstanceOf( NullJob::class, $job );
+++ /dev/null
-<?php
-use MediaWiki\MediaWikiServices;
-
-/**
- * @author Addshore
- *
- * @group Database
- *
- * @covers WatchedItem
- */
-class WatchedItemIntegrationTest extends MediaWikiTestCase {
-
- public function setUp() {
- parent::setUp();
- self::$users['WatchedItemIntegrationTestUser']
- = new TestUser( 'WatchedItemIntegrationTestUser' );
-
- $this->hideDeprecated( 'WatchedItem::fromUserTitle' );
- $this->hideDeprecated( 'WatchedItem::addWatch' );
- $this->hideDeprecated( 'WatchedItem::removeWatch' );
- $this->hideDeprecated( 'WatchedItem::isWatched' );
- $this->hideDeprecated( 'WatchedItem::duplicateEntries' );
- $this->hideDeprecated( 'WatchedItem::batchAddWatch' );
- }
-
- private function getUser() {
- return self::$users['WatchedItemIntegrationTestUser']->getUser();
- }
-
- public function testWatchAndUnWatchItem() {
- $user = $this->getUser();
- $title = Title::newFromText( 'WatchedItemIntegrationTestPage' );
- // Cleanup after previous tests
- WatchedItem::fromUserTitle( $user, $title )->removeWatch();
-
- $this->assertFalse(
- WatchedItem::fromUserTitle( $user, $title )->isWatched(),
- 'Page should not initially be watched'
- );
- WatchedItem::fromUserTitle( $user, $title )->addWatch();
- $this->assertTrue(
- WatchedItem::fromUserTitle( $user, $title )->isWatched(),
- 'Page should be watched'
- );
- WatchedItem::fromUserTitle( $user, $title )->removeWatch();
- $this->assertFalse(
- WatchedItem::fromUserTitle( $user, $title )->isWatched(),
- 'Page should be unwatched'
- );
- }
-
- public function testUpdateAndResetNotificationTimestamp() {
- $user = $this->getUser();
- $otherUser = ( new TestUser( 'WatchedItemIntegrationTestUser_otherUser' ) )->getUser();
- $title = Title::newFromText( 'WatchedItemIntegrationTestPage' );
- WatchedItem::fromUserTitle( $user, $title )->addWatch();
- $this->assertNull( WatchedItem::fromUserTitle( $user, $title )->getNotificationTimestamp() );
-
- EmailNotification::updateWatchlistTimestamp( $otherUser, $title, '20150202010101' );
- $this->assertEquals(
- '20150202010101',
- WatchedItem::fromUserTitle( $user, $title )->getNotificationTimestamp()
- );
-
- MediaWikiServices::getInstance()->getWatchedItemStore()->resetNotificationTimestamp(
- $user, $title
- );
- $this->assertNull( WatchedItem::fromUserTitle( $user, $title )->getNotificationTimestamp() );
- }
-
- public function testDuplicateAllAssociatedEntries() {
- $user = $this->getUser();
- $titleOld = Title::newFromText( 'WatchedItemIntegrationTestPageOld' );
- $titleNew = Title::newFromText( 'WatchedItemIntegrationTestPageNew' );
- WatchedItem::fromUserTitle( $user, $titleOld->getSubjectPage() )->addWatch();
- WatchedItem::fromUserTitle( $user, $titleOld->getTalkPage() )->addWatch();
- // Cleanup after previous tests
- WatchedItem::fromUserTitle( $user, $titleNew->getSubjectPage() )->removeWatch();
- WatchedItem::fromUserTitle( $user, $titleNew->getTalkPage() )->removeWatch();
-
- WatchedItem::duplicateEntries( $titleOld, $titleNew );
-
- $this->assertTrue(
- WatchedItem::fromUserTitle( $user, $titleOld->getSubjectPage() )->isWatched()
- );
- $this->assertTrue(
- WatchedItem::fromUserTitle( $user, $titleOld->getTalkPage() )->isWatched()
- );
- $this->assertTrue(
- WatchedItem::fromUserTitle( $user, $titleNew->getSubjectPage() )->isWatched()
- );
- $this->assertTrue(
- WatchedItem::fromUserTitle( $user, $titleNew->getTalkPage() )->isWatched()
- );
- }
-
- public function testIsWatched_falseOnNotAllowed() {
- $user = $this->getUser();
- $title = Title::newFromText( 'WatchedItemIntegrationTestPage' );
- WatchedItem::fromUserTitle( $user, $title )->addWatch();
-
- $this->assertTrue( WatchedItem::fromUserTitle( $user, $title )->isWatched() );
- $user->mRights = [];
- $this->assertFalse( WatchedItem::fromUserTitle( $user, $title )->isWatched() );
- }
-
- public function testGetNotificationTimestamp_falseOnNotAllowed() {
- $user = $this->getUser();
- $title = Title::newFromText( 'WatchedItemIntegrationTestPage' );
- WatchedItem::fromUserTitle( $user, $title )->addWatch();
- MediaWikiServices::getInstance()->getWatchedItemStore()->resetNotificationTimestamp(
- $user, $title
- );
-
- $this->assertEquals(
- null,
- WatchedItem::fromUserTitle( $user, $title )->getNotificationTimestamp()
- );
- $user->mRights = [];
- $this->assertFalse( WatchedItem::fromUserTitle( $user, $title )->getNotificationTimestamp() );
- }
-
- public function testRemoveWatch_falseOnNotAllowed() {
- $user = $this->getUser();
- $title = Title::newFromText( 'WatchedItemIntegrationTestPage' );
- WatchedItem::fromUserTitle( $user, $title )->addWatch();
-
- $previousRights = $user->mRights;
- $user->mRights = [];
- $this->assertFalse( WatchedItem::fromUserTitle( $user, $title )->removeWatch() );
- $user->mRights = $previousRights;
- $this->assertTrue( WatchedItem::fromUserTitle( $user, $title )->removeWatch() );
- }
-
- public function testGetNotificationTimestamp_falseOnNotWatched() {
- $user = $this->getUser();
- $title = Title::newFromText( 'WatchedItemIntegrationTestPage' );
-
- WatchedItem::fromUserTitle( $user, $title )->removeWatch();
- $this->assertFalse( WatchedItem::fromUserTitle( $user, $title )->isWatched() );
-
- $this->assertFalse( WatchedItem::fromUserTitle( $user, $title )->getNotificationTimestamp() );
- }
-
-}
+++ /dev/null
-<?php
-use MediaWiki\Linker\LinkTarget;
-
-/**
- * @author Addshore
- *
- * @covers WatchedItem
- */
-class WatchedItemUnitTest extends MediaWikiTestCase {
-
- /**
- * @param int $id
- *
- * @return PHPUnit_Framework_MockObject_MockObject|User
- */
- private function getMockUser( $id ) {
- $user = $this->createMock( User::class );
- $user->expects( $this->any() )
- ->method( 'getId' )
- ->will( $this->returnValue( $id ) );
- $user->expects( $this->any() )
- ->method( 'isAllowed' )
- ->will( $this->returnValue( true ) );
- return $user;
- }
-
- public function provideUserTitleTimestamp() {
- $user = $this->getMockUser( 111 );
- return [
- [ $user, Title::newFromText( 'SomeTitle' ), null ],
- [ $user, Title::newFromText( 'SomeTitle' ), '20150101010101' ],
- [ $user, new TitleValue( 0, 'TVTitle', 'frag' ), '20150101010101' ],
- ];
- }
-
- /**
- * @return PHPUnit_Framework_MockObject_MockObject|WatchedItemStore
- */
- private function getMockWatchedItemStore() {
- return $this->getMockBuilder( WatchedItemStore::class )
- ->disableOriginalConstructor()
- ->getMock();
- }
-
- /**
- * @dataProvider provideUserTitleTimestamp
- */
- public function testConstruction( $user, LinkTarget $linkTarget, $notifTimestamp ) {
- $item = new WatchedItem( $user, $linkTarget, $notifTimestamp );
-
- $this->assertSame( $user, $item->getUser() );
- $this->assertSame( $linkTarget, $item->getLinkTarget() );
- $this->assertSame( $notifTimestamp, $item->getNotificationTimestamp() );
-
- // The below tests the internal WatchedItem::getTitle method
- $this->assertInstanceOf( 'Title', $item->getTitle() );
- $this->assertSame( $linkTarget->getDBkey(), $item->getTitle()->getDBkey() );
- $this->assertSame( $linkTarget->getFragment(), $item->getTitle()->getFragment() );
- $this->assertSame( $linkTarget->getNamespace(), $item->getTitle()->getNamespace() );
- $this->assertSame( $linkTarget->getText(), $item->getTitle()->getText() );
- }
-
- /**
- * @dataProvider provideUserTitleTimestamp
- */
- public function testFromUserTitle( $user, $linkTarget, $timestamp ) {
- $store = $this->getMockWatchedItemStore();
- $store->expects( $this->once() )
- ->method( 'loadWatchedItem' )
- ->with( $user, $linkTarget )
- ->will( $this->returnValue( new WatchedItem( $user, $linkTarget, $timestamp ) ) );
- $this->setService( 'WatchedItemStore', $store );
-
- $item = WatchedItem::fromUserTitle( $user, $linkTarget, User::IGNORE_USER_RIGHTS );
-
- $this->assertEquals( $user, $item->getUser() );
- $this->assertEquals( $linkTarget, $item->getLinkTarget() );
- $this->assertEquals( $timestamp, $item->getNotificationTimestamp() );
- }
-
- public function testAddWatch() {
- $title = Title::newFromText( 'SomeTitle' );
- $timestamp = null;
- $checkRights = 0;
-
- /** @var User|PHPUnit_Framework_MockObject_MockObject $user */
- $user = $this->createMock( User::class );
- $user->expects( $this->once() )
- ->method( 'addWatch' )
- ->with( $title, $checkRights );
-
- $item = new WatchedItem( $user, $title, $timestamp, $checkRights );
- $this->assertTrue( $item->addWatch() );
- }
-
- public function testRemoveWatch() {
- $title = Title::newFromText( 'SomeTitle' );
- $timestamp = null;
- $checkRights = 0;
-
- /** @var User|PHPUnit_Framework_MockObject_MockObject $user */
- $user = $this->createMock( User::class );
- $user->expects( $this->once() )
- ->method( 'removeWatch' )
- ->with( $title, $checkRights );
-
- $item = new WatchedItem( $user, $title, $timestamp, $checkRights );
- $this->assertTrue( $item->removeWatch() );
- }
-
- public function provideBooleans() {
- return [
- [ true ],
- [ false ],
- ];
- }
-
- /**
- * @dataProvider provideBooleans
- */
- public function testIsWatched( $returnValue ) {
- $title = Title::newFromText( 'SomeTitle' );
- $timestamp = null;
- $checkRights = 0;
-
- /** @var User|PHPUnit_Framework_MockObject_MockObject $user */
- $user = $this->createMock( User::class );
- $user->expects( $this->once() )
- ->method( 'isWatched' )
- ->with( $title, $checkRights )
- ->will( $this->returnValue( $returnValue ) );
-
- $item = new WatchedItem( $user, $title, $timestamp, $checkRights );
- $this->assertEquals( $returnValue, $item->isWatched() );
- }
-
- public function testDuplicateEntries() {
- $oldTitle = Title::newFromText( 'OldTitle' );
- $newTitle = Title::newFromText( 'NewTitle' );
-
- $store = $this->getMockWatchedItemStore();
- $store->expects( $this->once() )
- ->method( 'duplicateAllAssociatedEntries' )
- ->with( $oldTitle, $newTitle );
- $this->setService( 'WatchedItemStore', $store );
-
- WatchedItem::duplicateEntries( $oldTitle, $newTitle );
- }
-
-}
public function testIllegalDependencies() {
$data = self::getAllModules();
- $illegalDeps = ResourceLoaderStartupModule::getStartupModules();
+ $illegalDeps = ResourceLoaderStartUpModule::getStartupModules();
foreach ( $data['modules'] as $moduleName => $module ) {
if ( $module->isRaw() ) {
$illegalDeps[] = $moduleName;