*/
use MediaWiki\Auth\AuthManager;
use MediaWiki\Auth\PasswordAuthenticationRequest;
+use MediaWiki\MediaWikiServices;
/**
* We're now using the HTMLForm object with some customisation to generate the
/** @var array */
protected static $saveFilters = [
'timecorrection' => [ 'Preferences', 'filterTimezoneInput' ],
- 'cols' => [ 'Preferences', 'filterIntval' ],
- 'rows' => [ 'Preferences', 'filterIntval' ],
'rclimit' => [ 'Preferences', 'filterIntval' ],
'wllimit' => [ 'Preferences', 'filterIntval' ],
'searchlimit' => [ 'Preferences', 'filterIntval' ],
}
}
- # # Make sure that form fields have their parent set. See bug 41337.
+ # # Make sure that form fields have their parent set. See T43337.
$dummyForm = new HTMLForm( [], $context );
$disable = !$user->isAllowed( 'editmyoptions' );
'section' => 'personal/info',
];
+ $lang = $context->getLanguage();
+
# Get groups to which the user belongs
$userEffectiveGroups = $user->getEffectiveGroups();
- $userGroups = $userMembers = [];
+ $userGroupMemberships = $user->getGroupMemberships();
+ $userGroups = $userMembers = $userTempGroups = $userTempMembers = [];
foreach ( $userEffectiveGroups as $ueg ) {
if ( $ueg == '*' ) {
// Skip the default * group, seems useless here
continue;
}
- $groupName = User::getGroupName( $ueg );
- $userGroups[] = User::makeGroupLinkHTML( $ueg, $groupName );
- $memberName = User::getGroupMember( $ueg, $userName );
- $userMembers[] = User::makeGroupLinkHTML( $ueg, $memberName );
- }
- asort( $userGroups );
- asort( $userMembers );
+ if ( isset( $userGroupMemberships[$ueg] ) ) {
+ $groupStringOrObject = $userGroupMemberships[$ueg];
+ } else {
+ $groupStringOrObject = $ueg;
+ }
- $lang = $context->getLanguage();
+ $userG = UserGroupMembership::getLink( $groupStringOrObject, $context, 'html' );
+ $userM = UserGroupMembership::getLink( $groupStringOrObject, $context, 'html',
+ $userName );
+
+ // Store expiring groups separately, so we can place them before non-expiring
+ // groups in the list. This is to avoid the ambiguity of something like
+ // "administrator, bureaucrat (until X date)" -- users might wonder whether the
+ // expiry date applies to both groups, or just the last one
+ if ( $groupStringOrObject instanceof UserGroupMembership &&
+ $groupStringOrObject->getExpiry()
+ ) {
+ $userTempGroups[] = $userG;
+ $userTempMembers[] = $userM;
+ } else {
+ $userGroups[] = $userG;
+ $userMembers[] = $userM;
+ }
+ }
+ sort( $userGroups );
+ sort( $userMembers );
+ sort( $userTempGroups );
+ sort( $userTempMembers );
+ $userGroups = array_merge( $userTempGroups, $userGroups );
+ $userMembers = array_merge( $userTempMembers, $userMembers );
$defaultPreferences['usergroups'] = [
'type' => 'info',
'section' => 'personal/info',
];
- $editCount = Linker::link( SpecialPage::getTitleFor( "Contributions", $userName ),
+ $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+
+ $editCount = $linkRenderer->makeLink( SpecialPage::getTitleFor( "Contributions", $userName ),
$lang->formatNum( $user->getEditCount() ) );
$defaultPreferences['editcount'] = [
if ( $canEditPrivateInfo && $authManager->allowsAuthenticationDataChange(
new PasswordAuthenticationRequest(), false )->isGood()
) {
- $link = Linker::link( SpecialPage::getTitleFor( 'ChangePassword' ),
- $context->msg( 'prefs-resetpass' )->escaped(), [],
+ $link = $linkRenderer->makeLink( SpecialPage::getTitleFor( 'ChangePassword' ),
+ $context->msg( 'prefs-resetpass' )->text(), [],
[ 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ] );
$defaultPreferences['password'] = [
$emailAddress = $user->getEmail() ? htmlspecialchars( $user->getEmail() ) : '';
if ( $canEditPrivateInfo && $authManager->allowsPropertyChange( 'emailaddress' ) ) {
- $link = Linker::link(
+ $link = $linkRenderer->makeLink(
SpecialPage::getTitleFor( 'ChangeEmail' ),
- $context->msg( $user->getEmail() ? 'prefs-changeemail' : 'prefs-setemail' )->escaped(),
+ $context->msg( $user->getEmail() ? 'prefs-changeemail' : 'prefs-setemail' )->text(),
[],
[ 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ] );
} else {
$disableEmailPrefs = true;
$emailauthenticated = $context->msg( 'emailnotauthenticated' )->parse() . '<br />' .
- Linker::linkKnown(
+ $linkRenderer->makeKnownLink(
SpecialPage::getTitleFor( 'Confirmemail' ),
- $context->msg( 'emailconfirmlink' )->escaped()
+ $context->msg( 'emailconfirmlink' )->text()
) . '<br />';
$emailauthenticationclass = "mw-email-not-authenticated";
}
$linkTools = [];
$userName = $user->getName();
+ $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
if ( $allowUserCss ) {
$cssPage = Title::makeTitleSafe( NS_USER, $userName . '/common.css' );
- $linkTools[] = Linker::link( $cssPage, $context->msg( 'prefs-custom-css' )->escaped() );
+ $linkTools[] = $linkRenderer->makeLink( $cssPage, $context->msg( 'prefs-custom-css' )->text() );
}
if ( $allowUserJs ) {
$jsPage = Title::makeTitleSafe( NS_USER, $userName . '/common.js' );
- $linkTools[] = Linker::link( $jsPage, $context->msg( 'prefs-custom-js' )->escaped() );
+ $linkTools[] = $linkRenderer->makeLink( $jsPage, $context->msg( 'prefs-custom-js' )->text() );
}
$defaultPreferences['commoncssjs'] = [
$tzOptions = self::getTimezoneOptions( $context );
$tzSetting = $tzOffset;
- if ( count( $tz ) > 1 && $tz[0] == 'Offset' ) {
- $minDiff = $tz[1];
- $tzSetting = sprintf( '%+03d:%02d', floor( $minDiff / 60 ), abs( $minDiff ) % 60 );
- } elseif ( count( $tz ) > 1 && $tz[0] == 'ZoneInfo' &&
+ if ( count( $tz ) > 1 && $tz[0] == 'ZoneInfo' &&
!in_array( $tzOffset, HTMLFormField::flattenOptions( $tzOptions ) )
) {
- # Timezone offset can vary with DST
- $userTZ = timezone_open( $tz[2] );
- if ( $userTZ !== false ) {
- $minDiff = floor( timezone_offset_get( $userTZ, date_create( 'now' ) ) / 60 );
+ // Timezone offset can vary with DST
+ try {
+ $userTZ = new DateTimeZone( $tz[2] );
+ $minDiff = floor( $userTZ->getOffset( new DateTime( 'now' ) ) / 60 );
$tzSetting = "ZoneInfo|$minDiff|{$tz[2]}";
+ } catch ( Exception $e ) {
+ // User has an invalid time zone set. Fall back to just using the offset
+ $tz[0] = 'Offset';
}
}
+ if ( count( $tz ) > 1 && $tz[0] == 'Offset' ) {
+ $minDiff = $tz[1];
+ $tzSetting = sprintf( '%+03d:%02d', floor( $minDiff / 60 ), abs( $minDiff ) % 60 );
+ }
$defaultPreferences['timecorrection'] = [
'class' => 'HTMLSelectOrOtherField',
]
];
}
- $defaultPreferences['cols'] = [
- 'type' => 'int',
- 'label-message' => 'columns',
- 'section' => 'editing/editor',
- 'min' => 4,
- 'max' => 1000,
- ];
- $defaultPreferences['rows'] = [
- 'type' => 'int',
- 'label-message' => 'rows',
- 'section' => 'editing/editor',
- 'min' => 4,
- 'max' => 1000,
- ];
+
if ( $user->isAllowed( 'minoredit' ) ) {
$defaultPreferences['minordefault'] = [
'type' => 'toggle',
'label-message' => 'tog-minordefault',
];
}
+
$defaultPreferences['forceeditsummary'] = [
'type' => 'toggle',
'section' => 'editing/editor',
'raw' => [ 'EditWatchlist', 'raw' ],
'clear' => [ 'EditWatchlist', 'clear' ],
];
+ $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
foreach ( $editWatchlistModes as $editWatchlistMode => $mode ) {
// Messages: prefs-editwatchlist-edit, prefs-editwatchlist-raw, prefs-editwatchlist-clear
- $editWatchlistLinks[] = Linker::linkKnown(
+ $editWatchlistLinks[] = $linkRenderer->makeKnownLink(
SpecialPage::getTitleFor( $mode[0], $mode[1] ),
- $context->msg( "prefs-editwatchlist-{$editWatchlistMode}" )->parse()
+ new HtmlArmor( $context->msg( "prefs-editwatchlist-{$editWatchlistMode}" )->parse() )
);
}
$mptitle = Title::newMainPage();
$previewtext = $context->msg( 'skin-preview' )->escaped();
+ $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+
# Only show skins that aren't disabled in $wgSkipSkins
$validSkinNames = Skin::getAllowedSkins();
# Create links to user CSS/JS pages
if ( $allowUserCss ) {
$cssPage = Title::makeTitleSafe( NS_USER, $user->getName() . '/' . $skinkey . '.css' );
- $linkTools[] = Linker::link( $cssPage, $context->msg( 'prefs-custom-css' )->escaped() );
+ $linkTools[] = $linkRenderer->makeLink( $cssPage, $context->msg( 'prefs-custom-css' )->text() );
}
if ( $allowUserJs ) {
$jsPage = Title::makeTitleSafe( NS_USER, $user->getName() . '/' . $skinkey . '.js' );
- $linkTools[] = Linker::link( $jsPage, $context->msg( 'prefs-custom-js' )->escaped() );
+ $linkTools[] = $linkRenderer->makeLink( $jsPage, $context->msg( 'prefs-custom-js' )->text() );
}
$display = $sn . ' ' . $context->msg( 'parentheses' )
if ( $dateopts ) {
if ( !in_array( 'default', $dateopts ) ) {
- $dateopts[] = 'default'; // Make sure default is always valid
- // Bug 19237
+ $dateopts[] = 'default'; // Make sure default is always valid T21237
}
// FIXME KLUGE: site default might not be valid for user language
$pixels = $context->msg( 'unit-pixel' )->text();
foreach ( $context->getConfig()->get( 'ImageLimits' ) as $index => $limits ) {
- $display = "{$limits[0]}×{$limits[1]}" . $pixels;
+ // Note: A left-to-right marker (\u200e) is inserted, see T144386
+ $display = "{$limits[0]}" . json_decode( '"\u200e"' ) . "×{$limits[1]}" . $pixels;
$ret[$display] = $index;
}
$data = explode( '|', $tz, 3 );
switch ( $data[0] ) {
case 'ZoneInfo':
+ $valid = false;
+
+ if ( count( $data ) === 3 ) {
+ // Make sure this timezone exists
+ try {
+ new DateTimeZone( $data[2] );
+ // If the constructor didn't throw, we know it's valid
+ $valid = true;
+ } catch ( Exception $e ) {
+ // Not a valid timezone
+ }
+ }
+
+ if ( !$valid ) {
+ // If the supplied timezone doesn't exist, fall back to the encoded offset
+ return 'Offset|' . intval( $tz[1] );
+ }
+ return $tz;
case 'System':
return $tz;
default:
# Max is +14:00 and min is -12:00, see:
# https://en.wikipedia.org/wiki/Timezone
$minDiff = min( $minDiff, 840 ); # 14:00
- $minDiff = max( $minDiff, - 720 ); # -12:00
+ $minDiff = max( $minDiff, -720 ); # -12:00
return 'Offset|' . $minDiff;
}
}
if ( $this->getModifiedUser()->isAllowed( 'editmyoptions' ) ) {
$t = SpecialPage::getTitleFor( 'Preferences', 'reset' );
- $html .= "\n" . Linker::link( $t, $this->msg( 'restoreprefs' )->escaped(),
+ $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
+ $html .= "\n" . $linkRenderer->makeLink( $t, $this->msg( 'restoreprefs' )->text(),
Html::buttonAttributes( $attrs, [ 'mw-ui-quiet' ] ) );
$html = Xml::tags( 'div', [ 'class' => 'mw-prefs-buttons' ], $html );