MediaWiki  master
Preferences.php
Go to the documentation of this file.
00001 <?php
00048 class Preferences {
00049         static $defaultPreferences = null;
00050         static $saveFilters = array(
00051                         'timecorrection' => array( 'Preferences', 'filterTimezoneInput' ),
00052                         'cols' => array( 'Preferences', 'filterIntval' ),
00053                         'rows' => array( 'Preferences', 'filterIntval' ),
00054                         'rclimit' => array( 'Preferences', 'filterIntval' ),
00055                         'wllimit' => array( 'Preferences', 'filterIntval' ),
00056                         'searchlimit' => array( 'Preferences', 'filterIntval' ),
00057         );
00058 
00065         static function getPreferences( $user, IContextSource $context ) {
00066                 if ( self::$defaultPreferences ) {
00067                         return self::$defaultPreferences;
00068                 }
00069 
00070                 $defaultPreferences = array();
00071 
00072                 self::profilePreferences( $user, $context, $defaultPreferences );
00073                 self::skinPreferences( $user, $context, $defaultPreferences );
00074                 self::filesPreferences( $user, $context, $defaultPreferences );
00075                 self::datetimePreferences( $user, $context, $defaultPreferences );
00076                 self::renderingPreferences( $user, $context, $defaultPreferences );
00077                 self::editingPreferences( $user, $context, $defaultPreferences );
00078                 self::rcPreferences( $user, $context, $defaultPreferences );
00079                 self::watchlistPreferences( $user, $context, $defaultPreferences );
00080                 self::searchPreferences( $user, $context, $defaultPreferences );
00081                 self::miscPreferences( $user, $context, $defaultPreferences );
00082 
00083                 wfRunHooks( 'GetPreferences', array( $user, &$defaultPreferences ) );
00084 
00085                 ## Remove preferences that wikis don't want to use
00086                 global $wgHiddenPrefs;
00087                 foreach ( $wgHiddenPrefs as $pref ) {
00088                         if ( isset( $defaultPreferences[$pref] ) ) {
00089                                 unset( $defaultPreferences[$pref] );
00090                         }
00091                 }
00092 
00093                 ## Prod in defaults from the user
00094                 foreach ( $defaultPreferences as $name => &$info ) {
00095                         $prefFromUser = self::getOptionFromUser( $name, $info, $user );
00096                         $field = HTMLForm::loadInputFromParameters( $name, $info ); // For validation
00097                         $defaultOptions = User::getDefaultOptions();
00098                         $globalDefault = isset( $defaultOptions[$name] )
00099                                 ? $defaultOptions[$name]
00100                                 : null;
00101 
00102                         // If it validates, set it as the default
00103                         if ( isset( $info['default'] ) ) {
00104                                 // Already set, no problem
00105                                 continue;
00106                         } elseif ( !is_null( $prefFromUser ) && // Make sure we're not just pulling nothing
00107                                         $field->validate( $prefFromUser, $user->getOptions() ) === true ) {
00108                                 $info['default'] = $prefFromUser;
00109                         } elseif ( $field->validate( $globalDefault, $user->getOptions() ) === true ) {
00110                                 $info['default'] = $globalDefault;
00111                         } else {
00112                                 throw new MWException( "Global default '$globalDefault' is invalid for field $name" );
00113                         }
00114                 }
00115 
00116                 self::$defaultPreferences = $defaultPreferences;
00117 
00118                 return $defaultPreferences;
00119         }
00120 
00129         static function getOptionFromUser( $name, $info, $user ) {
00130                 $val = $user->getOption( $name );
00131 
00132                 // Handling for array-type preferences
00133                 if ( ( isset( $info['type'] ) && $info['type'] == 'multiselect' ) ||
00134                                 ( isset( $info['class'] ) && $info['class'] == 'HTMLMultiSelectField' ) ) {
00135                         $options = HTMLFormField::flattenOptions( $info['options'] );
00136                         $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
00137                         $val = array();
00138 
00139                         foreach ( $options as $value ) {
00140                                 if ( $user->getOption( "$prefix$value" ) ) {
00141                                         $val[] = $value;
00142                                 }
00143                         }
00144                 }
00145 
00146                 return $val;
00147         }
00148 
00155         static function profilePreferences( $user, IContextSource $context, &$defaultPreferences ) {
00156                 global $wgAuth, $wgContLang, $wgParser, $wgCookieExpiration, $wgLanguageCode,
00157                         $wgDisableTitleConversion, $wgDisableLangConversion, $wgMaxSigChars,
00158                         $wgEnableEmail, $wgEmailConfirmToEdit, $wgEnableUserEmail, $wgEmailAuthentication,
00159                         $wgEnotifWatchlist, $wgEnotifUserTalk, $wgEnotifRevealEditorAddress;
00160 
00161                 // retrieving user name for GENDER and misc.
00162                 $userName = $user->getName();
00163 
00164                 ## User info #####################################
00165                 // Information panel
00166                 $defaultPreferences['username'] = array(
00167                         'type' => 'info',
00168                         'label-message' => array( 'username', $userName ),
00169                         'default' => $userName,
00170                         'section' => 'personal/info',
00171                 );
00172 
00173                 $defaultPreferences['userid'] = array(
00174                         'type' => 'info',
00175                         'label-message' => array( 'uid', $userName ),
00176                         'default' => $user->getId(),
00177                         'section' => 'personal/info',
00178                 );
00179 
00180                 # Get groups to which the user belongs
00181                 $userEffectiveGroups = $user->getEffectiveGroups();
00182                 $userGroups = $userMembers = array();
00183                 foreach ( $userEffectiveGroups as $ueg ) {
00184                         if ( $ueg == '*' ) {
00185                                 // Skip the default * group, seems useless here
00186                                 continue;
00187                         }
00188                         $groupName  = User::getGroupName( $ueg );
00189                         $userGroups[] = User::makeGroupLinkHTML( $ueg, $groupName );
00190 
00191                         $memberName = User::getGroupMember( $ueg, $userName );
00192                         $userMembers[] = User::makeGroupLinkHTML( $ueg, $memberName );
00193                 }
00194                 asort( $userGroups );
00195                 asort( $userMembers );
00196 
00197                 $lang = $context->getLanguage();
00198 
00199                 $defaultPreferences['usergroups'] = array(
00200                         'type' => 'info',
00201                         'label' => $context->msg( 'prefs-memberingroups' )->numParams(
00202                                 count( $userGroups ) )->params( $userName )->parse(),
00203                         'default' => $context->msg( 'prefs-memberingroups-type',
00204                                 $lang->commaList( $userGroups ),
00205                                 $lang->commaList( $userMembers )
00206                         )->plain(),
00207                         'raw' => true,
00208                         'section' => 'personal/info',
00209                 );
00210 
00211                 $defaultPreferences['editcount'] = array(
00212                         'type' => 'info',
00213                         'label-message' => 'prefs-edits',
00214                         'default' => $lang->formatNum( $user->getEditCount() ),
00215                         'section' => 'personal/info',
00216                 );
00217 
00218                 if ( $user->getRegistration() ) {
00219                         $displayUser = $context->getUser();
00220                         $userRegistration = $user->getRegistration();
00221                         $defaultPreferences['registrationdate'] = array(
00222                                 'type' => 'info',
00223                                 'label-message' => 'prefs-registration',
00224                                 'default' => $context->msg(
00225                                         'prefs-registration-date-time',
00226                                         $lang->userTimeAndDate( $userRegistration, $displayUser ),
00227                                         $lang->userDate( $userRegistration, $displayUser ),
00228                                         $lang->userTime( $userRegistration, $displayUser )
00229                                 )->parse(),
00230                                 'section' => 'personal/info',
00231                         );
00232                 }
00233 
00234                 // Actually changeable stuff
00235                 $defaultPreferences['realname'] = array(
00236                         'type' => $wgAuth->allowPropChange( 'realname' ) ? 'text' : 'info',
00237                         'default' => $user->getRealName(),
00238                         'section' => 'personal/info',
00239                         'label-message' => 'yourrealname',
00240                         'help-message' => 'prefs-help-realname',
00241                 );
00242 
00243                 $defaultPreferences['gender'] = array(
00244                         'type' => 'select',
00245                         'section' => 'personal/info',
00246                         'options' => array(
00247                                 $context->msg( 'gender-male' )->text() => 'male',
00248                                 $context->msg( 'gender-female' )->text() => 'female',
00249                                 $context->msg( 'gender-unknown' )->text() => 'unknown',
00250                         ),
00251                         'label-message' => 'yourgender',
00252                         'help-message' => 'prefs-help-gender',
00253                 );
00254 
00255                 if ( $wgAuth->allowPasswordChange() ) {
00256                         $link = Linker::link( SpecialPage::getTitleFor( 'ChangePassword' ),
00257                                 $context->msg( 'prefs-resetpass' )->escaped(), array(),
00258                                 array( 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ) );
00259 
00260                         $defaultPreferences['password'] = array(
00261                                 'type' => 'info',
00262                                 'raw' => true,
00263                                 'default' => $link,
00264                                 'label-message' => 'yourpassword',
00265                                 'section' => 'personal/info',
00266                         );
00267                 }
00268                 if ( $wgCookieExpiration > 0 ) {
00269                         $defaultPreferences['rememberpassword'] = array(
00270                                 'type' => 'toggle',
00271                                 'label' => $context->msg( 'tog-rememberpassword' )->numParams(
00272                                         ceil( $wgCookieExpiration / ( 3600 * 24 ) ) )->text(),
00273                                 'section' => 'personal/info',
00274                         );
00275                 }
00276 
00277                 // Language
00278                 $languages = Language::fetchLanguageNames( null, 'mw' );
00279                 if ( !array_key_exists( $wgLanguageCode, $languages ) ) {
00280                         $languages[$wgLanguageCode] = $wgLanguageCode;
00281                 }
00282                 ksort( $languages );
00283 
00284                 $options = array();
00285                 foreach ( $languages as $code => $name ) {
00286                         $display = wfBCP47( $code ) . ' - ' . $name;
00287                         $options[$display] = $code;
00288                 }
00289                 $defaultPreferences['language'] = array(
00290                         'type' => 'select',
00291                         'section' => 'personal/i18n',
00292                         'options' => $options,
00293                         'label-message' => 'yourlanguage',
00294                 );
00295 
00296                 /* see if there are multiple language variants to choose from*/
00297                 $variantArray = array();
00298                 if ( !$wgDisableLangConversion ) {
00299                         $variants = $wgContLang->getVariants();
00300 
00301                         foreach ( $variants as $v ) {
00302                                 $v = str_replace( '_', '-', strtolower( $v ) );
00303                                 $variantArray[$v] = $wgContLang->getVariantname( $v, false );
00304                         }
00305 
00306                         $options = array();
00307                         foreach ( $variantArray as $code => $name ) {
00308                                 $display = wfBCP47( $code ) . ' - ' . $name;
00309                                 $options[$display] = $code;
00310                         }
00311 
00312                         if ( count( $variantArray ) > 1 ) {
00313                                 $defaultPreferences['variant'] = array(
00314                                         'label-message' => 'yourvariant',
00315                                         'type' => 'select',
00316                                         'options' => $options,
00317                                         'section' => 'personal/i18n',
00318                                         'help-message' => 'prefs-help-variant',
00319                                 );
00320                         }
00321                 }
00322 
00323                 if ( count( $variantArray ) > 1 && !$wgDisableLangConversion && !$wgDisableTitleConversion ) {
00324                         $defaultPreferences['noconvertlink'] =
00325                                 array(
00326                                 'type' => 'toggle',
00327                                 'section' => 'personal/i18n',
00328                                 'label-message' => 'tog-noconvertlink',
00329                         );
00330                 }
00331 
00332                 // show a preview of the old signature first
00333                 $oldsigWikiText = $wgParser->preSaveTransform( "~~~", $context->getTitle(), $user, ParserOptions::newFromContext( $context ) );
00334                 $oldsigHTML = $context->getOutput()->parseInline( $oldsigWikiText, true, true );
00335                 $defaultPreferences['oldsig'] = array(
00336                         'type' => 'info',
00337                         'raw' => true,
00338                         'label-message' => 'tog-oldsig',
00339                         'default' => $oldsigHTML,
00340                         'section' => 'personal/signature',
00341                 );
00342                 $defaultPreferences['nickname'] = array(
00343                         'type' => $wgAuth->allowPropChange( 'nickname' ) ? 'text' : 'info',
00344                         'maxlength' => $wgMaxSigChars,
00345                         'label-message' => 'yournick',
00346                         'validation-callback' => array( 'Preferences', 'validateSignature' ),
00347                         'section' => 'personal/signature',
00348                         'filter-callback' => array( 'Preferences', 'cleanSignature' ),
00349                 );
00350                 $defaultPreferences['fancysig'] = array(
00351                         'type' => 'toggle',
00352                         'label-message' => 'tog-fancysig',
00353                         'help-message' => 'prefs-help-signature', // show general help about signature at the bottom of the section
00354                         'section' => 'personal/signature'
00355                 );
00356 
00357                 ## Email stuff
00358 
00359                 if ( $wgEnableEmail ) {
00360                         $helpMessages[] = $wgEmailConfirmToEdit
00361                                         ? 'prefs-help-email-required'
00362                                         : 'prefs-help-email';
00363 
00364                         if( $wgEnableUserEmail ) {
00365                                 // additional messages when users can send email to each other
00366                                 $helpMessages[] = 'prefs-help-email-others';
00367                         }
00368 
00369                         $link = Linker::link(
00370                                 SpecialPage::getTitleFor( 'ChangeEmail' ),
00371                                 $context->msg( $user->getEmail() ? 'prefs-changeemail' : 'prefs-setemail' )->escaped(),
00372                                 array(),
00373                                 array( 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ) );
00374 
00375                         $emailAddress = $user->getEmail() ? htmlspecialchars( $user->getEmail() ) : '';
00376                         if ( $wgAuth->allowPropChange( 'emailaddress' ) ) {
00377                                 $emailAddress .= $emailAddress == '' ? $link : (
00378                                         $context->msg( 'word-separator' )->plain()
00379                                         . $context->msg( 'parentheses' )->rawParams( $link )->plain()
00380                                 );
00381                         }
00382 
00383 
00384                         $defaultPreferences['emailaddress'] = array(
00385                                 'type' => 'info',
00386                                 'raw' => true,
00387                                 'default' => $emailAddress,
00388                                 'label-message' => 'youremail',
00389                                 'section' => 'personal/email',
00390                                 'help-messages' => $helpMessages,
00391                                 # 'cssclass' chosen below
00392                         );
00393 
00394                         $disableEmailPrefs = false;
00395 
00396                         $emailauthenticationclass = 'mw-email-not-authenticated';
00397                         if ( $wgEmailAuthentication ) {
00398                                 if ( $user->getEmail() ) {
00399                                         if ( $user->getEmailAuthenticationTimestamp() ) {
00400                                                 // date and time are separate parameters to facilitate localisation.
00401                                                 // $time is kept for backward compat reasons.
00402                                                 // 'emailauthenticated' is also used in SpecialConfirmemail.php
00403                                                 $displayUser = $context->getUser();
00404                                                 $emailTimestamp = $user->getEmailAuthenticationTimestamp();
00405                                                 $time = $lang->userTimeAndDate( $emailTimestamp, $displayUser );
00406                                                 $d = $lang->userDate( $emailTimestamp, $displayUser );
00407                                                 $t = $lang->userTime( $emailTimestamp, $displayUser );
00408                                                 $emailauthenticated = $context->msg( 'emailauthenticated',
00409                                                         $time, $d, $t )->parse() . '<br />';
00410                                                 $disableEmailPrefs = false;
00411                                                 $emailauthenticationclass = 'mw-email-authenticated';
00412                                         } else {
00413                                                 $disableEmailPrefs = true;
00414                                                 $emailauthenticated = $context->msg( 'emailnotauthenticated' )->parse() . '<br />' .
00415                                                         Linker::linkKnown(
00416                                                                 SpecialPage::getTitleFor( 'Confirmemail' ),
00417                                                                 $context->msg( 'emailconfirmlink' )->escaped()
00418                                                         ) . '<br />';
00419                                                 $emailauthenticationclass="mw-email-not-authenticated";
00420                                         }
00421                                 } else {
00422                                         $disableEmailPrefs = true;
00423                                         $emailauthenticated = $context->msg( 'noemailprefs' )->escaped();
00424                                         $emailauthenticationclass = 'mw-email-none';
00425                                 }
00426 
00427                                 $defaultPreferences['emailauthentication'] = array(
00428                                         'type' => 'info',
00429                                         'raw' => true,
00430                                         'section' => 'personal/email',
00431                                         'label-message' => 'prefs-emailconfirm-label',
00432                                         'default' => $emailauthenticated,
00433                                         # Apply the same CSS class used on the input to the message:
00434                                         'cssclass' => $emailauthenticationclass,
00435                                 );
00436                         }
00437                         $defaultPreferences['emailaddress']['cssclass'] = $emailauthenticationclass;
00438 
00439                         if ( $wgEnableUserEmail && $user->isAllowed( 'sendemail' ) ) {
00440                                 $defaultPreferences['disablemail'] = array(
00441                                         'type' => 'toggle',
00442                                         'invert' => true,
00443                                         'section' => 'personal/email',
00444                                         'label-message' => 'allowemail',
00445                                         'disabled' => $disableEmailPrefs,
00446                                 );
00447                                 $defaultPreferences['ccmeonemails'] = array(
00448                                         'type' => 'toggle',
00449                                         'section' => 'personal/email',
00450                                         'label-message' => 'tog-ccmeonemails',
00451                                         'disabled' => $disableEmailPrefs,
00452                                 );
00453                         }
00454 
00455                         if ( $wgEnotifWatchlist ) {
00456                                 $defaultPreferences['enotifwatchlistpages'] = array(
00457                                         'type' => 'toggle',
00458                                         'section' => 'personal/email',
00459                                         'label-message' => 'tog-enotifwatchlistpages',
00460                                         'disabled' => $disableEmailPrefs,
00461                                 );
00462                         }
00463                         if ( $wgEnotifUserTalk ) {
00464                                 $defaultPreferences['enotifusertalkpages'] = array(
00465                                         'type' => 'toggle',
00466                                         'section' => 'personal/email',
00467                                         'label-message' => 'tog-enotifusertalkpages',
00468                                         'disabled' => $disableEmailPrefs,
00469                                 );
00470                         }
00471                         if ( $wgEnotifUserTalk || $wgEnotifWatchlist ) {
00472                                 $defaultPreferences['enotifminoredits'] = array(
00473                                         'type' => 'toggle',
00474                                         'section' => 'personal/email',
00475                                         'label-message' => 'tog-enotifminoredits',
00476                                         'disabled' => $disableEmailPrefs,
00477                                 );
00478 
00479                                 if ( $wgEnotifRevealEditorAddress ) {
00480                                         $defaultPreferences['enotifrevealaddr'] = array(
00481                                                 'type' => 'toggle',
00482                                                 'section' => 'personal/email',
00483                                                 'label-message' => 'tog-enotifrevealaddr',
00484                                                 'disabled' => $disableEmailPrefs,
00485                                         );
00486                                 }
00487                         }
00488                 }
00489         }
00490 
00497         static function skinPreferences( $user, IContextSource $context, &$defaultPreferences ) {
00498                 ## Skin #####################################
00499                 global $wgAllowUserCss, $wgAllowUserJs;
00500 
00501                 $defaultPreferences['skin'] = array(
00502                         'type' => 'radio',
00503                         'options' => self::generateSkinOptions( $user, $context ),
00504                         'label' => '&#160;',
00505                         'section' => 'rendering/skin',
00506                 );
00507 
00508                 # Create links to user CSS/JS pages for all skins
00509                 # This code is basically copied from generateSkinOptions().  It'd
00510                 # be nice to somehow merge this back in there to avoid redundancy.
00511                 if ( $wgAllowUserCss || $wgAllowUserJs ) {
00512                         $linkTools = array();
00513                         $userName = $user->getName();
00514 
00515                         if ( $wgAllowUserCss ) {
00516                                 $cssPage = Title::makeTitleSafe( NS_USER, $userName . '/common.css' );
00517                                 $linkTools[] = Linker::link( $cssPage, $context->msg( 'prefs-custom-css' )->escaped() );
00518                         }
00519 
00520                         if ( $wgAllowUserJs ) {
00521                                 $jsPage = Title::makeTitleSafe( NS_USER, $userName . '/common.js' );
00522                                 $linkTools[] = Linker::link( $jsPage, $context->msg( 'prefs-custom-js' )->escaped() );
00523                         }
00524 
00525                         $defaultPreferences['commoncssjs'] = array(
00526                                 'type' => 'info',
00527                                 'raw' => true,
00528                                 'default' => $context->getLanguage()->pipeList( $linkTools ),
00529                                 'label-message' => 'prefs-common-css-js',
00530                                 'section' => 'rendering/skin',
00531                         );
00532                 }
00533 
00534                 $selectedSkin = $user->getOption( 'skin' );
00535                 if ( in_array( $selectedSkin, array( 'cologneblue', 'standard' ) ) ) {
00536                         $settings = array_flip( $context->getLanguage()->getQuickbarSettings() );
00537 
00538                         $defaultPreferences['quickbar'] = array(
00539                                 'type' => 'radio',
00540                                 'options' => $settings,
00541                                 'section' => 'rendering/skin',
00542                                 'label-message' => 'qbsettings',
00543                         );
00544                 }
00545         }
00546 
00552         static function filesPreferences( $user, IContextSource $context, &$defaultPreferences ) {
00553                 ## Files #####################################
00554                 $defaultPreferences['imagesize'] = array(
00555                         'type' => 'select',
00556                         'options' => self::getImageSizes( $context ),
00557                         'label-message' => 'imagemaxsize',
00558                         'section' => 'rendering/files',
00559                 );
00560                 $defaultPreferences['thumbsize'] = array(
00561                         'type' => 'select',
00562                         'options' => self::getThumbSizes( $context ),
00563                         'label-message' => 'thumbsize',
00564                         'section' => 'rendering/files',
00565                 );
00566         }
00567 
00574         static function datetimePreferences( $user, IContextSource $context, &$defaultPreferences ) {
00575                 ## Date and time #####################################
00576                 $dateOptions = self::getDateOptions( $context );
00577                 if ( $dateOptions ) {
00578                         $defaultPreferences['date'] = array(
00579                                 'type' => 'radio',
00580                                 'options' => $dateOptions,
00581                                 'label' => '&#160;',
00582                                 'section' => 'datetime/dateformat',
00583                         );
00584                 }
00585 
00586                 // Info
00587                 $now = wfTimestampNow();
00588                 $lang = $context->getLanguage();
00589                 $nowlocal = Xml::element( 'span', array( 'id' => 'wpLocalTime' ),
00590                         $lang->time( $now, true ) );
00591                 $nowserver = $lang->time( $now, false ) .
00592                         Html::hidden( 'wpServerTime', (int)substr( $now, 8, 2 ) * 60 + (int)substr( $now, 10, 2 ) );
00593 
00594                 $defaultPreferences['nowserver'] = array(
00595                         'type' => 'info',
00596                         'raw' => 1,
00597                         'label-message' => 'servertime',
00598                         'default' => $nowserver,
00599                         'section' => 'datetime/timeoffset',
00600                 );
00601 
00602                 $defaultPreferences['nowlocal'] = array(
00603                         'type' => 'info',
00604                         'raw' => 1,
00605                         'label-message' => 'localtime',
00606                         'default' => $nowlocal,
00607                         'section' => 'datetime/timeoffset',
00608                 );
00609 
00610                 // Grab existing pref.
00611                 $tzOffset = $user->getOption( 'timecorrection' );
00612                 $tz = explode( '|', $tzOffset, 3 );
00613 
00614                 $tzOptions = self::getTimezoneOptions( $context );
00615 
00616                 $tzSetting = $tzOffset;
00617                 if ( count( $tz ) > 1 && $tz[0] == 'Offset' ) {
00618                         $minDiff = $tz[1];
00619                         $tzSetting = sprintf( '%+03d:%02d', floor( $minDiff / 60 ), abs( $minDiff ) % 60 );
00620                 } elseif ( count( $tz ) > 1 && $tz[0] == 'ZoneInfo' &&
00621                         !in_array( $tzOffset, HTMLFormField::flattenOptions( $tzOptions ) ) )
00622                 {
00623                         # Timezone offset can vary with DST
00624                         $userTZ = timezone_open( $tz[2] );
00625                         if ( $userTZ !== false ) {
00626                                 $minDiff = floor( timezone_offset_get( $userTZ, date_create( 'now' ) ) / 60 );
00627                                 $tzSetting = "ZoneInfo|$minDiff|{$tz[2]}";
00628                         }
00629                 }
00630 
00631                 $defaultPreferences['timecorrection'] = array(
00632                         'class' => 'HTMLSelectOrOtherField',
00633                         'label-message' => 'timezonelegend',
00634                         'options' => $tzOptions,
00635                         'default' => $tzSetting,
00636                         'size' => 20,
00637                         'section' => 'datetime/timeoffset',
00638                 );
00639         }
00640 
00646         static function renderingPreferences( $user, IContextSource $context, &$defaultPreferences ) {
00647                 ## Page Rendering ##############################
00648                 global $wgAllowUserCssPrefs;
00649                 if ( $wgAllowUserCssPrefs ) {
00650                         $defaultPreferences['underline'] = array(
00651                                 'type' => 'select',
00652                                 'options' => array(
00653                                         $context->msg( 'underline-never' )->text() => 0,
00654                                         $context->msg( 'underline-always' )->text() => 1,
00655                                         $context->msg( 'underline-default' )->text() => 2,
00656                                 ),
00657                                 'label-message' => 'tog-underline',
00658                                 'section' => 'rendering/advancedrendering',
00659                         );
00660                 }
00661 
00662                 $stubThresholdValues = array( 50, 100, 500, 1000, 2000, 5000, 10000 );
00663                 $stubThresholdOptions = array( $context->msg( 'stub-threshold-disabled' )->text() => 0 );
00664                 foreach ( $stubThresholdValues as $value ) {
00665                         $stubThresholdOptions[$context->msg( 'size-bytes', $value )->text()] = $value;
00666                 }
00667 
00668                 $defaultPreferences['stubthreshold'] = array(
00669                         'type' => 'selectorother',
00670                         'section' => 'rendering/advancedrendering',
00671                         'options' => $stubThresholdOptions,
00672                         'size' => 20,
00673                         'label' => $context->msg( 'stub-threshold' )->text(), // Raw HTML message. Yay?
00674                 );
00675 
00676                 if ( $wgAllowUserCssPrefs ) {
00677                         $defaultPreferences['showtoc'] = array(
00678                                 'type' => 'toggle',
00679                                 'section' => 'rendering/advancedrendering',
00680                                 'label-message' => 'tog-showtoc',
00681                         );
00682                 }
00683                 $defaultPreferences['nocache'] = array(
00684                         'type' => 'toggle',
00685                         'label-message' => 'tog-nocache',
00686                         'section' => 'rendering/advancedrendering',
00687                 );
00688                 $defaultPreferences['showhiddencats'] = array(
00689                         'type' => 'toggle',
00690                         'section' => 'rendering/advancedrendering',
00691                         'label-message' => 'tog-showhiddencats'
00692                 );
00693                 $defaultPreferences['showjumplinks'] = array(
00694                         'type' => 'toggle',
00695                         'section' => 'rendering/advancedrendering',
00696                         'label-message' => 'tog-showjumplinks',
00697                 );
00698 
00699                 if ( $wgAllowUserCssPrefs ) {
00700                         $defaultPreferences['justify'] = array(
00701                                 'type' => 'toggle',
00702                                 'section' => 'rendering/advancedrendering',
00703                                 'label-message' => 'tog-justify',
00704                         );
00705                 }
00706 
00707                 $defaultPreferences['numberheadings'] = array(
00708                         'type' => 'toggle',
00709                         'section' => 'rendering/advancedrendering',
00710                         'label-message' => 'tog-numberheadings',
00711                 );
00712         }
00713 
00719         static function editingPreferences( $user, IContextSource $context, &$defaultPreferences ) {
00720                 global $wgUseExternalEditor, $wgAllowUserCssPrefs;
00721 
00722                 ## Editing #####################################
00723                 $defaultPreferences['cols'] = array(
00724                         'type' => 'int',
00725                         'label-message' => 'columns',
00726                         'section' => 'editing/textboxsize',
00727                         'min' => 4,
00728                         'max' => 1000,
00729                 );
00730                 $defaultPreferences['rows'] = array(
00731                         'type' => 'int',
00732                         'label-message' => 'rows',
00733                         'section' => 'editing/textboxsize',
00734                         'min' => 4,
00735                         'max' => 1000,
00736                 );
00737 
00738                 if ( $wgAllowUserCssPrefs ) {
00739                         $defaultPreferences['editfont'] = array(
00740                                 'type' => 'select',
00741                                 'section' => 'editing/advancedediting',
00742                                 'label-message' => 'editfont-style',
00743                                 'options' => array(
00744                                         $context->msg( 'editfont-default' )->text() => 'default',
00745                                         $context->msg( 'editfont-monospace' )->text() => 'monospace',
00746                                         $context->msg( 'editfont-sansserif' )->text() => 'sans-serif',
00747                                         $context->msg( 'editfont-serif' )->text() => 'serif',
00748                                 )
00749                         );
00750                 }
00751                 $defaultPreferences['previewontop'] = array(
00752                         'type' => 'toggle',
00753                         'section' => 'editing/advancedediting',
00754                         'label-message' => 'tog-previewontop',
00755                 );
00756                 $defaultPreferences['previewonfirst'] = array(
00757                         'type' => 'toggle',
00758                         'section' => 'editing/advancedediting',
00759                         'label-message' => 'tog-previewonfirst',
00760                 );
00761 
00762                 if ( $wgAllowUserCssPrefs ) {
00763                         $defaultPreferences['editsection'] = array(
00764                                 'type' => 'toggle',
00765                                 'section' => 'editing/advancedediting',
00766                                 'label-message' => 'tog-editsection',
00767                         );
00768                 }
00769                 $defaultPreferences['editsectiononrightclick'] = array(
00770                         'type' => 'toggle',
00771                         'section' => 'editing/advancedediting',
00772                         'label-message' => 'tog-editsectiononrightclick',
00773                 );
00774                 $defaultPreferences['editondblclick'] = array(
00775                         'type' => 'toggle',
00776                         'section' => 'editing/advancedediting',
00777                         'label-message' => 'tog-editondblclick',
00778                 );
00779                 $defaultPreferences['showtoolbar'] = array(
00780                         'type' => 'toggle',
00781                         'section' => 'editing/advancedediting',
00782                         'label-message' => 'tog-showtoolbar',
00783                 );
00784 
00785                 if ( $user->isAllowed( 'minoredit' ) ) {
00786                         $defaultPreferences['minordefault'] = array(
00787                                 'type' => 'toggle',
00788                                 'section' => 'editing/advancedediting',
00789                                 'label-message' => 'tog-minordefault',
00790                         );
00791                 }
00792 
00793                 if ( $wgUseExternalEditor ) {
00794                         $defaultPreferences['externaleditor'] = array(
00795                                 'type' => 'toggle',
00796                                 'section' => 'editing/advancedediting',
00797                                 'label-message' => 'tog-externaleditor',
00798                         );
00799                         $defaultPreferences['externaldiff'] = array(
00800                                 'type' => 'toggle',
00801                                 'section' => 'editing/advancedediting',
00802                                 'label-message' => 'tog-externaldiff',
00803                         );
00804                 }
00805 
00806                 $defaultPreferences['forceeditsummary'] = array(
00807                         'type' => 'toggle',
00808                         'section' => 'editing/advancedediting',
00809                         'label-message' => 'tog-forceeditsummary',
00810                 );
00811 
00812 
00813                 $defaultPreferences['uselivepreview'] = array(
00814                         'type' => 'toggle',
00815                         'section' => 'editing/advancedediting',
00816                         'label-message' => 'tog-uselivepreview',
00817                 );
00818         }
00819 
00825         static function rcPreferences( $user, IContextSource $context, &$defaultPreferences ) {
00826                 global $wgRCMaxAge, $wgRCShowWatchingUsers;
00827 
00828                 ## RecentChanges #####################################
00829                 $defaultPreferences['rcdays'] = array(
00830                         'type' => 'float',
00831                         'label-message' => 'recentchangesdays',
00832                         'section' => 'rc/displayrc',
00833                         'min' => 1,
00834                         'max' => ceil( $wgRCMaxAge / ( 3600 * 24 ) ),
00835                         'help' => $context->msg( 'recentchangesdays-max' )->numParams(
00836                                 ceil( $wgRCMaxAge / ( 3600 * 24 ) ) )->text()
00837                 );
00838                 $defaultPreferences['rclimit'] = array(
00839                         'type' => 'int',
00840                         'label-message' => 'recentchangescount',
00841                         'help-message' => 'prefs-help-recentchangescount',
00842                         'section' => 'rc/displayrc',
00843                 );
00844                 $defaultPreferences['usenewrc'] = array(
00845                         'type' => 'toggle',
00846                         'label-message' => 'tog-usenewrc',
00847                         'section' => 'rc/advancedrc',
00848                 );
00849                 $defaultPreferences['hideminor'] = array(
00850                         'type' => 'toggle',
00851                         'label-message' => 'tog-hideminor',
00852                         'section' => 'rc/advancedrc',
00853                 );
00854 
00855                 if ( $user->useRCPatrol() ) {
00856                         $defaultPreferences['hidepatrolled'] = array(
00857                                 'type' => 'toggle',
00858                                 'section' => 'rc/advancedrc',
00859                                 'label-message' => 'tog-hidepatrolled',
00860                         );
00861                         $defaultPreferences['newpageshidepatrolled'] = array(
00862                                 'type' => 'toggle',
00863                                 'section' => 'rc/advancedrc',
00864                                 'label-message' => 'tog-newpageshidepatrolled',
00865                         );
00866                 }
00867 
00868                 if ( $wgRCShowWatchingUsers ) {
00869                         $defaultPreferences['shownumberswatching'] = array(
00870                                 'type' => 'toggle',
00871                                 'section' => 'rc/advancedrc',
00872                                 'label-message' => 'tog-shownumberswatching',
00873                         );
00874                 }
00875         }
00876 
00882         static function watchlistPreferences( $user, IContextSource $context, &$defaultPreferences ) {
00883                 global $wgUseRCPatrol, $wgEnableAPI, $wgRCMaxAge;
00884 
00885                 $watchlistdaysMax = ceil( $wgRCMaxAge / ( 3600 * 24 ) );
00886 
00887                 ## Watchlist #####################################
00888                 $defaultPreferences['watchlistdays'] = array(
00889                         'type' => 'float',
00890                         'min' => 0,
00891                         'max' => $watchlistdaysMax,
00892                         'section' => 'watchlist/displaywatchlist',
00893                         'help' => $context->msg( 'prefs-watchlist-days-max' )->numParams(
00894                                 $watchlistdaysMax )->text(),
00895                         'label-message' => 'prefs-watchlist-days',
00896                 );
00897                 $defaultPreferences['wllimit'] = array(
00898                         'type' => 'int',
00899                         'min' => 0,
00900                         'max' => 1000,
00901                         'label-message' => 'prefs-watchlist-edits',
00902                         'help' => $context->msg( 'prefs-watchlist-edits-max' )->escaped(),
00903                         'section' => 'watchlist/displaywatchlist',
00904                 );
00905                 $defaultPreferences['extendwatchlist'] = array(
00906                         'type' => 'toggle',
00907                         'section' => 'watchlist/advancedwatchlist',
00908                         'label-message' => 'tog-extendwatchlist',
00909                 );
00910                 $defaultPreferences['watchlisthideminor'] = array(
00911                         'type' => 'toggle',
00912                         'section' => 'watchlist/advancedwatchlist',
00913                         'label-message' => 'tog-watchlisthideminor',
00914                 );
00915                 $defaultPreferences['watchlisthidebots'] = array(
00916                         'type' => 'toggle',
00917                         'section' => 'watchlist/advancedwatchlist',
00918                         'label-message' => 'tog-watchlisthidebots',
00919                 );
00920                 $defaultPreferences['watchlisthideown'] = array(
00921                         'type' => 'toggle',
00922                         'section' => 'watchlist/advancedwatchlist',
00923                         'label-message' => 'tog-watchlisthideown',
00924                 );
00925                 $defaultPreferences['watchlisthideanons'] = array(
00926                         'type' => 'toggle',
00927                         'section' => 'watchlist/advancedwatchlist',
00928                         'label-message' => 'tog-watchlisthideanons',
00929                 );
00930                 $defaultPreferences['watchlisthideliu'] = array(
00931                         'type' => 'toggle',
00932                         'section' => 'watchlist/advancedwatchlist',
00933                         'label-message' => 'tog-watchlisthideliu',
00934                 );
00935 
00936                 if ( $wgUseRCPatrol ) {
00937                         $defaultPreferences['watchlisthidepatrolled'] = array(
00938                                 'type' => 'toggle',
00939                                 'section' => 'watchlist/advancedwatchlist',
00940                                 'label-message' => 'tog-watchlisthidepatrolled',
00941                         );
00942                 }
00943 
00944                 if ( $wgEnableAPI ) {
00945                         # Some random gibberish as a proposed default
00946                         // @todo Fixme: this should use CryptRand but we may not want to read urandom on every view
00947                         $hash = sha1( mt_rand() . microtime( true ) );
00948 
00949                         $defaultPreferences['watchlisttoken'] = array(
00950                                 'type' => 'text',
00951                                 'section' => 'watchlist/advancedwatchlist',
00952                                 'label-message' => 'prefs-watchlist-token',
00953                                 'help' => $context->msg( 'prefs-help-watchlist-token', $hash )->escaped()
00954                         );
00955                 }
00956 
00957                 $watchTypes = array(
00958                         'edit' => 'watchdefault',
00959                         'move' => 'watchmoves',
00960                         'delete' => 'watchdeletion'
00961                 );
00962 
00963                 // Kinda hacky
00964                 if ( $user->isAllowed( 'createpage' ) || $user->isAllowed( 'createtalk' ) ) {
00965                         $watchTypes['read'] = 'watchcreations';
00966                 }
00967 
00968                 foreach ( $watchTypes as $action => $pref ) {
00969                         if ( $user->isAllowed( $action ) ) {
00970                                 $defaultPreferences[$pref] = array(
00971                                         'type' => 'toggle',
00972                                         'section' => 'watchlist/advancedwatchlist',
00973                                         'label-message' => "tog-$pref",
00974                                 );
00975                         }
00976                 }
00977         }
00978 
00984         static function searchPreferences( $user, IContextSource $context, &$defaultPreferences ) {
00985                 global $wgContLang, $wgVectorUseSimpleSearch;
00986 
00987                 ## Search #####################################
00988                 $defaultPreferences['searchlimit'] = array(
00989                         'type' => 'int',
00990                         'label-message' => 'resultsperpage',
00991                         'section' => 'searchoptions/displaysearchoptions',
00992                         'min' => 0,
00993                 );
00994 
00995 
00996                 if ( $wgVectorUseSimpleSearch ) {
00997                         $defaultPreferences['vector-simplesearch'] = array(
00998                                 'type' => 'toggle',
00999                                 'label-message' => 'vector-simplesearch-preference',
01000                                 'section' => 'searchoptions/displaysearchoptions',
01001                         );
01002                 }
01003 
01004                 $defaultPreferences['disablesuggest'] = array(
01005                         'type' => 'toggle',
01006                         'label-message' => 'mwsuggest-disable',
01007                         'section' => 'searchoptions/displaysearchoptions',
01008                 );
01009 
01010                 $defaultPreferences['searcheverything'] = array(
01011                         'type' => 'toggle',
01012                         'label-message' => 'searcheverything-enable',
01013                         'section' => 'searchoptions/advancedsearchoptions',
01014                 );
01015 
01016                 $nsOptions = $wgContLang->getFormattedNamespaces();
01017                 $nsOptions[0] = $context->msg( 'blanknamespace' )->text();
01018                 foreach ( $nsOptions as $ns => $name ) {
01019                         if ( $ns < 0 )
01020                                 unset( $nsOptions[$ns] );
01021                 }
01022 
01023                 $defaultPreferences['searchnamespaces'] = array(
01024                         'type' => 'multiselect',
01025                         'label-message' => 'defaultns',
01026                         'options' => array_flip( $nsOptions ),
01027                         'section' => 'searchoptions/advancedsearchoptions',
01028                         'prefix' => 'searchNs',
01029                 );
01030         }
01031 
01037         static function miscPreferences( $user, IContextSource $context, &$defaultPreferences ) {
01038                 global $wgContLang;
01039 
01040                 ## Misc #####################################
01041                 $defaultPreferences['diffonly'] = array(
01042                         'type' => 'toggle',
01043                         'section' => 'misc/diffs',
01044                         'label-message' => 'tog-diffonly',
01045                 );
01046                 $defaultPreferences['norollbackdiff'] = array(
01047                         'type' => 'toggle',
01048                         'section' => 'misc/diffs',
01049                         'label-message' => 'tog-norollbackdiff',
01050                 );
01051 
01052                 // Stuff from Language::getExtraUserToggles()
01053                 $toggles = $wgContLang->getExtraUserToggles();
01054 
01055                 foreach ( $toggles as $toggle ) {
01056                         $defaultPreferences[$toggle] = array(
01057                                 'type' => 'toggle',
01058                                 'section' => 'personal/i18n',
01059                                 'label-message' => "tog-$toggle",
01060                         );
01061                 }
01062         }
01063 
01069         static function generateSkinOptions( $user, IContextSource $context ) {
01070                 global $wgDefaultSkin, $wgAllowUserCss, $wgAllowUserJs;
01071                 $ret = array();
01072 
01073                 $mptitle = Title::newMainPage();
01074                 $previewtext = $context->msg( 'skin-preview' )->text();
01075 
01076                 # Only show members of Skin::getSkinNames() rather than
01077                 # $skinNames (skins is all skin names from Language.php)
01078                 $validSkinNames = Skin::getUsableSkins();
01079 
01080                 # Sort by UI skin name. First though need to update validSkinNames as sometimes
01081                 # the skinkey & UI skinname differ (e.g. "standard" skinkey is "Classic" in the UI).
01082                 foreach ( $validSkinNames as $skinkey => &$skinname ) {
01083                         $msg = $context->msg( "skinname-{$skinkey}" );
01084                         if ( $msg->exists() ) {
01085                                 $skinname = htmlspecialchars( $msg->text() );
01086                         }
01087                 }
01088                 asort( $validSkinNames );
01089 
01090                 foreach ( $validSkinNames as $skinkey => $sn ) {
01091                         $linkTools = array();
01092 
01093                         # Mark the default skin
01094                         if ( $skinkey == $wgDefaultSkin ) {
01095                                 $linkTools[] = $context->msg( 'default' )->escaped();
01096                         }
01097 
01098                         # Create preview link
01099                         $mplink = htmlspecialchars( $mptitle->getLocalURL( "useskin=$skinkey" ) );
01100                         $linkTools[] = "<a target='_blank' href=\"$mplink\">$previewtext</a>";
01101 
01102                         # Create links to user CSS/JS pages
01103                         if ( $wgAllowUserCss ) {
01104                                 $cssPage = Title::makeTitleSafe( NS_USER, $user->getName() . '/' . $skinkey . '.css' );
01105                                 $linkTools[] = Linker::link( $cssPage, $context->msg( 'prefs-custom-css' )->escaped() );
01106                         }
01107 
01108                         if ( $wgAllowUserJs ) {
01109                                 $jsPage = Title::makeTitleSafe( NS_USER, $user->getName() . '/' . $skinkey . '.js' );
01110                                 $linkTools[] = Linker::link( $jsPage, $context->msg( 'prefs-custom-js' )->escaped() );
01111                         }
01112 
01113                         $display = $sn . ' ' . $context->msg( 'parentheses', $context->getLanguage()->pipeList( $linkTools ) )->text();
01114                         $ret[$display] = $skinkey;
01115                 }
01116 
01117                 return $ret;
01118         }
01119 
01124         static function getDateOptions( IContextSource $context ) {
01125                 $lang = $context->getLanguage();
01126                 $dateopts = $lang->getDatePreferences();
01127 
01128                 $ret = array();
01129 
01130                 if ( $dateopts ) {
01131                         if ( !in_array( 'default', $dateopts ) ) {
01132                                 $dateopts[] = 'default'; // Make sure default is always valid
01133                                                                                 // Bug 19237
01134                         }
01135 
01136                         // KLUGE: site default might not be valid for user language
01137                         global $wgDefaultUserOptions;
01138                         if ( !in_array( $wgDefaultUserOptions['date'], $dateopts ) ) {
01139                                 $wgDefaultUserOptions['date'] = 'default';
01140                         }
01141 
01142                         $epoch = wfTimestampNow();
01143                         foreach ( $dateopts as $key ) {
01144                                 if ( $key == 'default' ) {
01145                                         $formatted = $context->msg( 'datedefault' )->escaped();
01146                                 } else {
01147                                         $formatted = htmlspecialchars( $lang->timeanddate( $epoch, false, $key ) );
01148                                 }
01149                                 $ret[$formatted] = $key;
01150                         }
01151                 }
01152                 return $ret;
01153         }
01154 
01159         static function getImageSizes( IContextSource $context ) {
01160                 global $wgImageLimits;
01161 
01162                 $ret = array();
01163                 $pixels = $context->msg( 'unit-pixel' )->text();
01164 
01165                 foreach ( $wgImageLimits as $index => $limits ) {
01166                         $display = "{$limits[0]}×{$limits[1]}" . $pixels;
01167                         $ret[$display] = $index;
01168                 }
01169 
01170                 return $ret;
01171         }
01172 
01177         static function getThumbSizes( IContextSource $context ) {
01178                 global $wgThumbLimits;
01179 
01180                 $ret = array();
01181                 $pixels = $context->msg( 'unit-pixel' )->text();
01182 
01183                 foreach ( $wgThumbLimits as $index => $size ) {
01184                         $display = $size . $pixels;
01185                         $ret[$display] = $index;
01186                 }
01187 
01188                 return $ret;
01189         }
01190 
01197         static function validateSignature( $signature, $alldata, $form ) {
01198                 global $wgParser, $wgMaxSigChars;
01199                 if ( mb_strlen( $signature ) > $wgMaxSigChars ) {
01200                         return Xml::element( 'span', array( 'class' => 'error' ),
01201                                 $form->msg( 'badsiglength' )->numParams( $wgMaxSigChars )->text() );
01202                 } elseif ( isset( $alldata['fancysig'] ) &&
01203                                 $alldata['fancysig'] &&
01204                                 false === $wgParser->validateSig( $signature ) ) {
01205                         return Xml::element( 'span', array( 'class' => 'error' ), $form->msg( 'badsig' )->text() );
01206                 } else {
01207                         return true;
01208                 }
01209         }
01210 
01217         static function cleanSignature( $signature, $alldata, $form ) {
01218                 if ( isset( $alldata['fancysig'] ) && $alldata['fancysig'] ) {
01219                         global $wgParser;
01220                         $signature = $wgParser->cleanSig( $signature );
01221                 } else {
01222                         // When no fancy sig used, make sure ~{3,5} get removed.
01223                         $signature = Parser::cleanSigInSig( $signature );
01224                 }
01225 
01226                 return $signature;
01227         }
01228 
01236         static function getFormObject( $user, IContextSource $context, $formClass = 'PreferencesForm', array $remove = array() ) {
01237                 $formDescriptor = Preferences::getPreferences( $user, $context );
01238                 if ( count( $remove ) ) {
01239                         $removeKeys = array_flip( $remove );
01240                         $formDescriptor = array_diff_key( $formDescriptor, $removeKeys );
01241                 }
01242 
01243                 // Remove type=api preferences. They are not intended for rendering in the form.
01244                 foreach ( $formDescriptor as $name => $info ) {
01245                         if ( isset( $info['type'] ) && $info['type'] === 'api' ) {
01246                                 unset( $formDescriptor[$name] );
01247                         }
01248                 }
01249 
01253                 $htmlForm = new $formClass( $formDescriptor, $context, 'prefs' );
01254 
01255                 $htmlForm->setModifiedUser( $user );
01256                 $htmlForm->setId( 'mw-prefs-form' );
01257                 $htmlForm->setSubmitText( $context->msg( 'saveprefs' )->text() );
01258                 # Used message keys: 'accesskey-preferences-save', 'tooltip-preferences-save'
01259                 $htmlForm->setSubmitTooltip( 'preferences-save' );
01260                 $htmlForm->setSubmitID( 'prefsubmit' );
01261                 $htmlForm->setSubmitCallback( array( 'Preferences', 'tryFormSubmit' ) );
01262 
01263                 return $htmlForm;
01264         }
01265 
01269         static function getTimezoneOptions( IContextSource $context ) {
01270                 $opt = array();
01271 
01272                 global $wgLocalTZoffset, $wgLocaltimezone;
01273                 // Check that $wgLocalTZoffset is the same as $wgLocaltimezone
01274                 if ( $wgLocalTZoffset == date( 'Z' ) / 60 ) {
01275                         $server_tz_msg = $context->msg( 'timezoneuseserverdefault', $wgLocaltimezone )->text();
01276                 } else {
01277                         $tzstring = sprintf( '%+03d:%02d', floor( $wgLocalTZoffset / 60 ), abs( $wgLocalTZoffset ) % 60 );
01278                         $server_tz_msg = $context->msg( 'timezoneuseserverdefault', $tzstring )->text();
01279                 }
01280                 $opt[$server_tz_msg] = "System|$wgLocalTZoffset";
01281                 $opt[$context->msg( 'timezoneuseoffset' )->text()] = 'other';
01282                 $opt[$context->msg( 'guesstimezone' )->text()] = 'guess';
01283 
01284                 if ( function_exists( 'timezone_identifiers_list' ) ) {
01285                         # Read timezone list
01286                         $tzs = timezone_identifiers_list();
01287                         sort( $tzs );
01288 
01289                         $tzRegions = array();
01290                         $tzRegions['Africa'] = $context->msg( 'timezoneregion-africa' )->text();
01291                         $tzRegions['America'] = $context->msg( 'timezoneregion-america' )->text();
01292                         $tzRegions['Antarctica'] = $context->msg( 'timezoneregion-antarctica' )->text();
01293                         $tzRegions['Arctic'] = $context->msg( 'timezoneregion-arctic' )->text();
01294                         $tzRegions['Asia'] = $context->msg( 'timezoneregion-asia' )->text();
01295                         $tzRegions['Atlantic'] = $context->msg( 'timezoneregion-atlantic' )->text();
01296                         $tzRegions['Australia'] = $context->msg( 'timezoneregion-australia' )->text();
01297                         $tzRegions['Europe'] = $context->msg( 'timezoneregion-europe' )->text();
01298                         $tzRegions['Indian'] = $context->msg( 'timezoneregion-indian' )->text();
01299                         $tzRegions['Pacific'] = $context->msg( 'timezoneregion-pacific' )->text();
01300                         asort( $tzRegions );
01301 
01302                         $prefill = array_fill_keys( array_values( $tzRegions ), array() );
01303                         $opt = array_merge( $opt, $prefill );
01304 
01305                         $now = date_create( 'now' );
01306 
01307                         foreach ( $tzs as $tz ) {
01308                                 $z = explode( '/', $tz, 2 );
01309 
01310                                 # timezone_identifiers_list() returns a number of
01311                                 # backwards-compatibility entries. This filters them out of the
01312                                 # list presented to the user.
01313                                 if ( count( $z ) != 2 || !array_key_exists( $z[0], $tzRegions ) ) {
01314                                         continue;
01315                                 }
01316 
01317                                 # Localize region
01318                                 $z[0] = $tzRegions[$z[0]];
01319 
01320                                 $minDiff = floor( timezone_offset_get( timezone_open( $tz ), $now ) / 60 );
01321 
01322                                 $display = str_replace( '_', ' ', $z[0] . '/' . $z[1] );
01323                                 $value = "ZoneInfo|$minDiff|$tz";
01324 
01325                                 $opt[$z[0]][$display] = $value;
01326                         }
01327                 }
01328                 return $opt;
01329         }
01330 
01336         static function filterIntval( $value, $alldata ) {
01337                 return intval( $value );
01338         }
01339 
01345         static function filterTimezoneInput( $tz, $alldata ) {
01346                 $data = explode( '|', $tz, 3 );
01347                 switch ( $data[0] ) {
01348                         case 'ZoneInfo':
01349                         case 'System':
01350                                 return $tz;
01351                         default:
01352                                 $data = explode( ':', $tz, 2 );
01353                                 if ( count( $data ) == 2 ) {
01354                                         $data[0] = intval( $data[0] );
01355                                         $data[1] = intval( $data[1] );
01356                                         $minDiff = abs( $data[0] ) * 60 + $data[1];
01357                                         if ( $data[0] < 0 ) $minDiff = - $minDiff;
01358                                 } else {
01359                                         $minDiff = intval( $data[0] ) * 60;
01360                                 }
01361 
01362                                 # Max is +14:00 and min is -12:00, see:
01363                                 # http://en.wikipedia.org/wiki/Timezone
01364                                 $minDiff = min( $minDiff, 840 );  # 14:00
01365                                 $minDiff = max( $minDiff, - 720 ); # -12:00
01366                                 return 'Offset|' . $minDiff;
01367                 }
01368         }
01369 
01376         static function tryFormSubmit( $formData, $form, $entryPoint = 'internal' ) {
01377                 global $wgHiddenPrefs, $wgAuth;
01378 
01379                 $user = $form->getModifiedUser();
01380                 $result = true;
01381 
01382                 // Filter input
01383                 foreach ( array_keys( $formData ) as $name ) {
01384                         if ( isset( self::$saveFilters[$name] ) ) {
01385                                 $formData[$name] =
01386                                         call_user_func( self::$saveFilters[$name], $formData[$name], $formData );
01387                         }
01388                 }
01389 
01390                 // Stuff that shouldn't be saved as a preference.
01391                 $saveBlacklist = array(
01392                         'realname',
01393                         'emailaddress',
01394                 );
01395 
01396                 // Fortunately, the realname field is MUCH simpler
01397                 if ( !in_array( 'realname', $wgHiddenPrefs ) ) {
01398                         $realName = $formData['realname'];
01399                         $user->setRealName( $realName );
01400                 }
01401 
01402                 foreach ( $saveBlacklist as $b ) {
01403                         unset( $formData[$b] );
01404                 }
01405 
01406                 # If users have saved a value for a preference which has subsequently been disabled
01407                 # via $wgHiddenPrefs, we don't want to destroy that setting in case the preference
01408                 # is subsequently re-enabled
01409                 # TODO: maintenance script to actually delete these
01410                 foreach( $wgHiddenPrefs as $pref ) {
01411                         # If the user has not set a non-default value here, the default will be returned
01412                         # and subsequently discarded
01413                         $formData[$pref] = $user->getOption( $pref, null, true );
01414                 }
01415 
01416                 // Keep old preferences from interfering due to back-compat code, etc.
01417                 $user->resetOptions( 'unused', $form->getContext() );
01418 
01419                 foreach ( $formData as $key => $value ) {
01420                         $user->setOption( $key, $value );
01421                 }
01422 
01423                 $user->saveSettings();
01424 
01425                 $wgAuth->updateExternalDB( $user );
01426 
01427                 return $result;
01428         }
01429 
01435         public static function tryUISubmit( $formData, $form ) {
01436                 $res = self::tryFormSubmit( $formData, $form, 'ui' );
01437 
01438                 if ( $res ) {
01439                         $urlOptions = array( 'success' => 1 );
01440 
01441                         if ( $res === 'eauth' ) {
01442                                 $urlOptions['eauth'] = 1;
01443                         }
01444 
01445                         $urlOptions += $form->getExtraSuccessRedirectParameters();
01446 
01447                         $url = $form->getTitle()->getFullURL( $urlOptions );
01448 
01449                         $form->getContext()->getOutput()->redirect( $url );
01450                 }
01451 
01452                 return Status::newGood();
01453         }
01454 
01465         public static function trySetUserEmail( User $user, $newaddr ) {
01466                 wfDeprecated( __METHOD__, '1.20' );
01467 
01468                 $result = $user->setEmailWithConfirmation( $newaddr );
01469                 if ( $result->isGood() ) {
01470                         return array( true, $result->value );
01471                 } else {
01472                         return array( $result, 'mailerror' );
01473                 }
01474         }
01475 
01481         public static function loadOldSearchNs( $user ) {
01482                 wfDeprecated( __METHOD__, '1.19' );
01483 
01484                 $searchableNamespaces = SearchEngine::searchableNamespaces();
01485                 // Back compat with old format
01486                 $arr = array();
01487 
01488                 foreach ( $searchableNamespaces as $ns => $name ) {
01489                         if ( $user->getOption( 'searchNs' . $ns ) ) {
01490                                 $arr[] = $ns;
01491                         }
01492                 }
01493 
01494                 return $arr;
01495         }
01496 }
01497 
01499 class PreferencesForm extends HTMLForm {
01500         // Override default value from HTMLForm
01501         protected $mSubSectionBeforeFields = false;
01502 
01503         private $modifiedUser;
01504 
01508         public function setModifiedUser( $user ) {
01509                 $this->modifiedUser = $user;
01510         }
01511 
01515         public function getModifiedUser() {
01516                 if ( $this->modifiedUser === null ) {
01517                         return $this->getUser();
01518                 } else {
01519                         return $this->modifiedUser;
01520                 }
01521         }
01522 
01529         public function getExtraSuccessRedirectParameters() {
01530                 return array();
01531         }
01532 
01537         function wrapForm( $html ) {
01538                 $html = Xml::tags( 'div', array( 'id' => 'preferences' ), $html );
01539 
01540                 return parent::wrapForm( $html );
01541         }
01542 
01546         function getButtons() {
01547                 $html = parent::getButtons();
01548 
01549                 $t = SpecialPage::getTitleFor( 'Preferences', 'reset' );
01550 
01551                 $html .= "\n" . Linker::link( $t, $this->msg( 'restoreprefs' )->escaped() );
01552 
01553                 $html = Xml::tags( 'div', array( 'class' => 'mw-prefs-buttons' ), $html );
01554 
01555                 return $html;
01556         }
01557 
01562         function filterDataForSubmit( $data ) {
01563                 // Support for separating MultiSelect preferences into multiple preferences
01564                 // Due to lack of array support.
01565                 foreach ( $this->mFlatFields as $fieldname => $field ) {
01566                         $info = $field->mParams;
01567                         if ( $field instanceof HTMLMultiSelectField ) {
01568                                 $options = HTMLFormField::flattenOptions( $info['options'] );
01569                                 $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $fieldname;
01570 
01571                                 foreach ( $options as $opt ) {
01572                                         $data["$prefix$opt"] = in_array( $opt, $data[$fieldname] );
01573                                 }
01574 
01575                                 unset( $data[$fieldname] );
01576                         }
01577                 }
01578 
01579                 return $data;
01580         }
01581 
01586         function getBody() {
01587                 return $this->displaySection( $this->mFieldTree, '', 'mw-prefsection-' );
01588         }
01589 
01596         function getLegend( $key ) {
01597                 $legend = parent::getLegend( $key );
01598                 wfRunHooks( 'PreferencesGetLegend', array( $this, $key, &$legend ) );
01599                 return $legend;
01600         }
01601 }