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