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