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