* wfArrayFilter() and wfArrayFilterByKey(), deprecated in 1.32, have been
removed.
* wfMakeUrlIndexes() function, deprecated in 1.33, have been removed.
+* Method signatures in WatchedItemQueryServiceExtension have changed from taking
+ User objects to taking UserIdentity objects. Extensions implementing this
+ interface need to be changed accordingly.
* User::getGroupPage() and ::makeGroupLinkHTML(), deprecated in 1.29, have been
removed. Use UserGroupMembership::getGroupPage and ::getLink instead.
* User::makeGroupLinkWiki(), deprecated in 1.29, has been removed. Use
if ( $block->getType() == self::TYPE_RANGE ) {
# This is the number of bits that are allowed to vary in the block, give
# or take some floating point errors
- $end = Wikimedia\base_convert( $block->getRangeEnd(), 16, 10 );
- $start = Wikimedia\base_convert( $block->getRangeStart(), 16, 10 );
+ $prefix = 'v6-';
+ $end = Wikimedia\base_convert( ltrim( $block->getRangeEnd(), $prefix ), 16, 10 );
+ $start = Wikimedia\base_convert( ltrim( $block->getRangeStart(), $prefix ), 16, 10 );
$size = log( $end - $start + 1, 2 );
# Rank a range block covering a single IP equally with a single-IP block
$search->setFeatureData( 'rewrite', (bool)$params['enablerewrites'] );
$search->setFeatureData( 'interwiki', (bool)$interwiki );
- $nquery = $search->transformSearchTerm( $query );
- if ( $nquery !== $query ) {
- $query = $nquery;
- wfDeprecated( 'SearchEngine::transformSearchTerm() (overridden by ' .
- get_class( $search ) . ')', '1.32' );
- }
-
$nquery = $search->replacePrefixes( $query );
if ( $nquery !== $query ) {
$query = $nquery;
$this->wanCache->touchCheckKey( $this->getCheckKey( $code ) );
// Purge the messages in the message blob store and fire any hook handlers
- $resourceloader = RequestContext::getMain()->getOutput()->getResourceLoader();
- $blobStore = $resourceloader->getMessageBlobStore();
+ $blobStore = MediaWikiServices::getInstance()->getResourceLoader()->getMessageBlobStore();
foreach ( $replacements as list( $title, $msg ) ) {
$blobStore->updateMessage( $this->contLang->lcfirst( $msg ) );
Hooks::run( 'MessageCacheReplace', [ $title, $newTextByTitle[$title] ] );
# HACK: If using a null (i.e. disabled) storage backend, we
# can't write to the MessageBlobStore either
if ( $purgeBlobs && !$this->store instanceof LCStoreNull ) {
- $blobStore = new MessageBlobStore(
- MediaWikiServices::getInstance()->getResourceLoader()
- );
+ $blobStore = MediaWikiServices::getInstance()->getResourceLoader()->getMessageBlobStore();
$blobStore->clear();
}
}
* Install handlers with PHP.
*/
public static function installHandler() {
+ // This catches:
+ // * Exception objects that were explicitly thrown but not
+ // caught anywhere in the application. This is rare given those
+ // would normally be caught at a high-level like MediaWiki::run (index.php),
+ // api.php, or ResourceLoader::respond (load.php). These high-level
+ // catch clauses would then call MWExceptionHandler::logException
+ // or MWExceptionHandler::handleException.
+ // If they are not caught, then they are handled here.
+ // * Error objects (on PHP 7+), for issues that would historically
+ // cause fatal errors but may now be caught as Throwable (not Exception).
+ // Same as previous case, but more common to bubble to here instead of
+ // caught locally because they tend to not be safe to recover from.
+ // (e.g. argument TypeErorr, devision by zero, etc.)
set_exception_handler( 'MWExceptionHandler::handleUncaughtException' );
+
+ // This catches:
+ // * Non-fatal errors (e.g. PHP Notice, PHP Warning, PHP Error) that do not
+ // interrupt execution in any way. We log these in the background and then
+ // continue execution.
+ // * Fatal errors (on HHVM in PHP5 mode) where PHP 7 would throw Throwable.
set_error_handler( 'MWExceptionHandler::handleError' );
+ // This catches:
+ // * Fatal error for which no Throwable is thrown (PHP 7), and no Error emitted (HHVM).
+ // This includes Out-Of-Memory and Timeout fatals.
+ //
// Reserve 16k of memory so we can report OOM fatals
self::$reservedMemory = str_repeat( ' ', 16384 );
register_shutdown_function( 'MWExceptionHandler::handleFatalError' );
* search engine
*/
public function transformSearchTerm( $term ) {
+ wfDeprecated( __METHOD__, '1.34' );
return $term;
}
$showSuggestion = $title === null || !$title->isKnown();
$search->setShowSuggestion( $showSuggestion );
- $rewritten = $search->transformSearchTerm( $term );
- if ( $rewritten !== $term ) {
- $term = $rewritten;
- wfDeprecated( 'SearchEngine::transformSearchTerm() (overridden by ' .
- get_class( $search ) . ')', '1.32' );
- }
-
$rewritten = $search->replacePrefixes( $term );
if ( $rewritten !== $term ) {
wfDeprecated( 'SearchEngine::replacePrefixes() (overridden by ' .
#pagehistory li.selected {
background-color: #f8f9fa;
color: #222;
- border: 1px dashed #a2a9b1;
+ border-color: #f8f9fa;
+ outline: 1px dashed #a2a9b1;
}
.mw-history-revisionactions {
--- /dev/null
+// Common button mixins for MediaWiki
+//
+// Helper mixins used to create button styles. this file is importable
+// by all less files via `@import 'mediawiki.mixins.buttons';`.
+
+/* stylelint-disable selector-class-pattern */
+
+// Primary buttons mixin
+.button-colors-primary( @bgColor, @highlightColor, @activeColor ) {
+ background-color: @bgColor;
+ color: #fff;
+ // border of the same color as background so that light background and
+ // dark background buttons are the same height and width
+ border: 1px solid @bgColor;
+
+ &:hover {
+ background-color: @highlightColor;
+ border-color: @highlightColor;
+ }
+
+ &:focus {
+ box-shadow: inset 0 0 0 1px @bgColor, inset 0 0 0 2px #fff;
+ }
+
+ &:active,
+ &.is-on {
+ background-color: @activeColor;
+ border-color: @activeColor;
+ box-shadow: none;
+ }
+
+ &:disabled {
+ background-color: @colorGray12;
+ color: #fff;
+ border-color: @colorGray12;
+
+ // Make sure disabled buttons don't have hover and active states
+ &:hover,
+ &:active {
+ background-color: @colorGray12;
+ color: #fff;
+ border-color: @colorGray12;
+ box-shadow: none;
+ }
+ }
+}
@import 'mediawiki.mixins';
+@import 'mediawiki.ui/mixins.buttons';
@import 'mediawiki.ui/variables';
/* stylelint-disable selector-class-pattern */
-// Buttons
-// Helper mixins
-// Primary buttons mixin
-.button-colors-primary( @bgColor, @highlightColor, @activeColor ) {
- background-color: @bgColor;
- color: #fff;
- // border of the same color as background so that light background and
- // dark background buttons are the same height and width
- border: 1px solid @bgColor;
-
- &:hover {
- background-color: @highlightColor;
- border-color: @highlightColor;
- }
-
- &:focus {
- box-shadow: inset 0 0 0 1px @bgColor, inset 0 0 0 2px #fff;
- }
-
- &:active,
- &.is-on {
- background-color: @activeColor;
- border-color: @activeColor;
- box-shadow: none;
- }
-
- &:disabled {
- background-color: @colorGray12;
- color: #fff;
- border-color: @colorGray12;
-
- // Make sure disabled buttons don't have hover and active states
- &:hover,
- &:active {
- background-color: @colorGray12;
- color: #fff;
- border-color: @colorGray12;
- box-shadow: none;
- }
- }
-}
-
// All buttons start with `.mw-ui-button` class, modified by other classes.
// It can be any element. Due to a lack of a CSS reset, the exact styling of
// the button depends on what type of element is used.
];
}
+ /**
+ * @dataProvider provideNewFromTargetRangeBlocks
+ * @covers Block::newFromTarget
+ */
+ public function testNewFromTargetRangeBlocks( $targets, $ip, $expectedTarget ) {
+ $blocker = $this->getTestSysop()->getUser();
+
+ foreach ( $targets as $target ) {
+ $block = new Block();
+ $block->setTarget( $target );
+ $block->setBlocker( $blocker );
+ $block->insert();
+ }
+
+ // Should find the block with the narrowest range
+ $blockTarget = Block::newFromTarget( $this->getTestUser()->getUser(), $ip )->getTarget();
+ $this->assertSame(
+ $blockTarget instanceof User ? $blockTarget->getName() : $blockTarget,
+ $expectedTarget
+ );
+
+ foreach ( $targets as $target ) {
+ $block = Block::newFromTarget( $target );
+ $block->delete();
+ }
+ }
+
+ function provideNewFromTargetRangeBlocks() {
+ return [
+ 'Blocks to IPv4 ranges' => [
+ [ '0.0.0.0/20', '0.0.0.0/30', '0.0.0.0/25' ],
+ '0.0.0.0',
+ '0.0.0.0/30'
+ ],
+ 'Blocks to IPv6 ranges' => [
+ [ '0:0:0:0:0:0:0:0/20', '0:0:0:0:0:0:0:0/30', '0:0:0:0:0:0:0:0/25' ],
+ '0:0:0:0:0:0:0:0',
+ '0:0:0:0:0:0:0:0/30'
+ ],
+ 'Blocks to wide IPv4 range and IP' => [
+ [ '0.0.0.0/16', '0.0.0.0' ],
+ '0.0.0.0',
+ '0.0.0.0'
+ ],
+ 'Blocks to wide IPv6 range and IP' => [
+ [ '0:0:0:0:0:0:0:0/19', '0:0:0:0:0:0:0:0' ],
+ '0:0:0:0:0:0:0:0',
+ '0:0:0:0:0:0:0:0'
+ ],
+ 'Blocks to narrow IPv4 range and IP' => [
+ [ '0.0.0.0/31', '0.0.0.0' ],
+ '0.0.0.0',
+ '0.0.0.0'
+ ],
+ 'Blocks to narrow IPv6 range and IP' => [
+ [ '0:0:0:0:0:0:0:0/127', '0:0:0:0:0:0:0:0' ],
+ '0:0:0:0:0:0:0:0',
+ '0:0:0:0:0:0:0:0'
+ ],
+ ];
+ }
+
/**
* @covers Block::appliesToRight
*/
// ==================
// Test Files
+ // FIXME: The non-core patterns to be removed once T199116 is fixed.
// ==================
specs: [
relPath( './tests/selenium/wdio-mediawiki/specs/*.js' ),
],
// Patterns to exclude
exclude: [
- relPath( './extensions/CirrusSearch/tests/selenium/specs/**/*.js' )
+ relPath( './extensions/CirrusSearch/tests/selenium/specs/**/*.js' ),
+ // Disabled per T222517
+ relPath( './skins/MinervaNeue/tests/selenium/specs/**/*.js' )
],
// ============