]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - includes/Preferences.php
MediaWiki 1.17.0
[autoinstalls/mediawiki.git] / includes / Preferences.php
1 <?php
2 /**
3  * We're now using the HTMLForm object with some customisation to generate the
4  * Preferences form. This object handles generic submission, CSRF protection,
5  * layout and other logic in a reusable manner. We subclass it as a PreferencesForm
6  * to make some minor customisations.
7  *
8  * In order to generate the form, the HTMLForm object needs an array structure
9  * detailing the form fields available, and that's what this class is for. Each
10  * element of the array is a basic property-list, including the type of field,
11  * the label it is to be given in the form, callbacks for validation and
12  * 'filtering', and other pertinent information. Note that the 'default' field
13  * is named for generic forms, and does not represent the preference's default
14  * (which is stored in $wgDefaultUserOptions), but the default for the form
15  * field, which should be whatever the user has set for that preference. There
16  * is no need to override it unless you have some special storage logic (for
17  * instance, those not presently stored as options, but which are best set from
18  * the user preferences view).
19  *
20  * Field types are implemented as subclasses of the generic HTMLFormField
21  * object, and typically implement at least getInputHTML, which generates the
22  * HTML for the input field to be placed in the table.
23  *
24  * Once fields have been retrieved and validated, submission logic is handed
25  * over to the tryUISubmit static method of this class.
26  */
27
28 class Preferences {
29         static $defaultPreferences = null;
30         static $saveFilters = array(
31                         'timecorrection' => array( 'Preferences', 'filterTimezoneInput' ),
32                         'cols' => array( 'Preferences', 'filterIntval' ),
33                         'rows' => array( 'Preferences', 'filterIntval' ),
34                         'rclimit' => array( 'Preferences', 'filterIntval' ),
35                         'wllimit' => array( 'Preferences', 'filterIntval' ),
36                         'searchlimit' => array( 'Preferences', 'filterIntval' ),
37         );
38
39         static function getPreferences( $user ) {
40                 if ( self::$defaultPreferences )
41                         return self::$defaultPreferences;
42
43                 $defaultPreferences = array();
44
45                 self::profilePreferences( $user, $defaultPreferences );
46                 self::skinPreferences( $user, $defaultPreferences );
47                 self::filesPreferences( $user, $defaultPreferences );
48                 self::mathPreferences( $user, $defaultPreferences );
49                 self::datetimePreferences( $user, $defaultPreferences );
50                 self::renderingPreferences( $user, $defaultPreferences );
51                 self::editingPreferences( $user, $defaultPreferences );
52                 self::rcPreferences( $user, $defaultPreferences );
53                 self::watchlistPreferences( $user, $defaultPreferences );
54                 self::searchPreferences( $user, $defaultPreferences );
55                 self::miscPreferences( $user, $defaultPreferences );
56
57                 wfRunHooks( 'GetPreferences', array( $user, &$defaultPreferences ) );
58
59                 ## Remove preferences that wikis don't want to use
60                 global $wgHiddenPrefs;
61                 foreach ( $wgHiddenPrefs as $pref ) {
62                         if ( isset( $defaultPreferences[$pref] ) ) {
63                                 unset( $defaultPreferences[$pref] );
64                         }
65                 }
66
67                 ## Prod in defaults from the user
68                 foreach ( $defaultPreferences as $name => &$info ) {
69                         $prefFromUser = self::getOptionFromUser( $name, $info, $user );
70                         $field = HTMLForm::loadInputFromParameters( $name, $info ); // For validation
71                         $defaultOptions = User::getDefaultOptions();
72                         $globalDefault = isset( $defaultOptions[$name] )
73                                 ? $defaultOptions[$name]
74                                 : null;
75
76                         // If it validates, set it as the default
77                         if ( isset( $info['default'] ) ) {
78                                 // Already set, no problem
79                                 continue;
80                         } elseif ( !is_null( $prefFromUser ) && // Make sure we're not just pulling nothing
81                                         $field->validate( $prefFromUser, $user->mOptions ) === true ) {
82                                 $info['default'] = $prefFromUser;
83                         } elseif ( $field->validate( $globalDefault, $user->mOptions ) === true ) {
84                                 $info['default'] = $globalDefault;
85                         } else {
86                                 throw new MWException( "Global default '$globalDefault' is invalid for field $name" );
87                         }
88                 }
89
90                 self::$defaultPreferences = $defaultPreferences;
91
92                 return $defaultPreferences;
93         }
94
95         // Pull option from a user account. Handles stuff like array-type preferences.
96         static function getOptionFromUser( $name, $info, $user ) {
97                 $val = $user->getOption( $name );
98
99                 // Handling for array-type preferences
100                 if ( ( isset( $info['type'] ) && $info['type'] == 'multiselect' ) ||
101                                 ( isset( $info['class'] ) && $info['class'] == 'HTMLMultiSelectField' ) ) {
102                         $options = HTMLFormField::flattenOptions( $info['options'] );
103                         $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
104                         $val = array();
105
106                         foreach ( $options as $value ) {
107                                 if ( $user->getOption( "$prefix$value" ) ) {
108                                         $val[] = $value;
109                                 }
110                         }
111                 }
112
113                 return $val;
114         }
115
116         static function profilePreferences( $user, &$defaultPreferences ) {
117                 global $wgLang, $wgUser;
118                 ## User info #####################################
119                 // Information panel
120                 $defaultPreferences['username'] = array(
121                         'type' => 'info',
122                         'label-message' => 'username',
123                         'default' => $user->getName(),
124                         'section' => 'personal/info',
125                 );
126
127                 $defaultPreferences['userid'] = array(
128                         'type' => 'info',
129                         'label-message' => 'uid',
130                         'default' => $user->getId(),
131                         'section' => 'personal/info',
132                 );
133
134                 # Get groups to which the user belongs
135                 $userEffectiveGroups = $user->getEffectiveGroups();
136                 $userGroups = $userMembers = array();
137                 foreach ( $userEffectiveGroups as $ueg ) {
138                         if ( $ueg == '*' ) {
139                                 // Skip the default * group, seems useless here
140                                 continue;
141                         }
142                         $groupName  = User::getGroupName( $ueg );
143                         $userGroups[] = User::makeGroupLinkHTML( $ueg, $groupName );
144
145                         $memberName = User::getGroupMember( $ueg );
146                         $userMembers[] = User::makeGroupLinkHTML( $ueg, $memberName );
147                 }
148                 asort( $userGroups );
149                 asort( $userMembers );
150
151                 $defaultPreferences['usergroups'] = array(
152                         'type' => 'info',
153                         'label' => wfMsgExt(
154                                 'prefs-memberingroups', 'parseinline',
155                                 $wgLang->formatNum( count( $userGroups ) )
156                         ),
157                         'default' => wfMsgExt(
158                                 'prefs-memberingroups-type', array(),
159                                 $wgLang->commaList( $userGroups ),
160                                 $wgLang->commaList( $userMembers )
161                         ),
162                         'raw' => true,
163                         'section' => 'personal/info',
164                 );
165
166                 $defaultPreferences['editcount'] = array(
167                         'type' => 'info',
168                         'label-message' => 'prefs-edits',
169                         'default' => $wgLang->formatNum( $user->getEditCount() ),
170                         'section' => 'personal/info',
171                 );
172
173                 if ( $user->getRegistration() ) {
174                         $defaultPreferences['registrationdate'] = array(
175                                 'type' => 'info',
176                                 'label-message' => 'prefs-registration',
177                                 'default' => wfMsgExt(
178                                         'prefs-registration-date-time', 'parsemag',
179                                         $wgLang->timeanddate( $user->getRegistration(), true ),
180                                         $wgLang->date( $user->getRegistration(), true ),
181                                         $wgLang->time( $user->getRegistration(), true )
182                                 ),
183                                 'section' => 'personal/info',
184                         );
185                 }
186
187                 // Actually changeable stuff
188                 global $wgAuth;
189                 $defaultPreferences['realname'] = array(
190                         'type' => $wgAuth->allowPropChange( 'realname' ) ? 'text' : 'info',
191                         'default' => $user->getRealName(),
192                         'section' => 'personal/info',
193                         'label-message' => 'yourrealname',
194                         'help-message' => 'prefs-help-realname',
195                 );
196
197                 $defaultPreferences['gender'] = array(
198                         'type' => 'select',
199                         'section' => 'personal/info',
200                         'options' => array(
201                                 wfMsg( 'gender-male' ) => 'male',
202                                 wfMsg( 'gender-female' ) => 'female',
203                                 wfMsg( 'gender-unknown' ) => 'unknown',
204                         ),
205                         'label-message' => 'yourgender',
206                         'help-message' => 'prefs-help-gender',
207                 );
208
209                 if ( $wgAuth->allowPasswordChange() ) {
210                         $link = $wgUser->getSkin()->link( SpecialPage::getTitleFor( 'Resetpass' ),
211                                 wfMsgHtml( 'prefs-resetpass' ), array(),
212                                 array( 'returnto' => SpecialPage::getTitleFor( 'Preferences' ) ) );
213
214                         $defaultPreferences['password'] = array(
215                                 'type' => 'info',
216                                 'raw' => true,
217                                 'default' => $link,
218                                 'label-message' => 'yourpassword',
219                                 'section' => 'personal/info',
220                         );
221                 }
222                 global $wgCookieExpiration;
223                 if ( $wgCookieExpiration > 0 ) {
224                         $defaultPreferences['rememberpassword'] = array(
225                                 'type' => 'toggle',
226                                 'label' => wfMsgExt(
227                                         'tog-rememberpassword',
228                                         array( 'parsemag' ),
229                                         $wgLang->formatNum( ceil( $wgCookieExpiration / ( 3600 * 24 ) ) )
230                                         ),
231                                 'section' => 'personal/info',
232                         );
233                 }
234
235                 // Language
236                 global $wgLanguageCode;
237                 $languages = Language::getLanguageNames( false );
238                 if ( !array_key_exists( $wgLanguageCode, $languages ) ) {
239                         $languages[$wgLanguageCode] = $wgLanguageCode;
240                 }
241                 ksort( $languages );
242
243                 $options = array();
244                 foreach ( $languages as $code => $name ) {
245                         $display = wfBCP47( $code ) . ' - ' . $name;
246                         $options[$display] = $code;
247                 }
248                 $defaultPreferences['language'] = array(
249                         'type' => 'select',
250                         'section' => 'personal/i18n',
251                         'options' => $options,
252                         'label-message' => 'yourlanguage',
253                 );
254
255                 global $wgContLang, $wgDisableLangConversion;
256                 global $wgDisableTitleConversion;
257                 /* see if there are multiple language variants to choose from*/
258                 $variantArray = array();
259                 if ( !$wgDisableLangConversion ) {
260                         $variants = $wgContLang->getVariants();
261
262                         $languages = Language::getLanguageNames( true );
263                         foreach ( $variants as $v ) {
264                                 $v = str_replace( '_', '-', strtolower( $v ) );
265                                 if ( array_key_exists( $v, $languages ) ) {
266                                         // If it doesn't have a name, we'll pretend it doesn't exist
267                                         $variantArray[$v] = $languages[$v];
268                                 }
269                         }
270
271                         $options = array();
272                         foreach ( $variantArray as $code => $name ) {
273                                 $display = wfBCP47( $code ) . ' - ' . $name;
274                                 $options[$display] = $code;
275                         }
276
277                         if ( count( $variantArray ) > 1 ) {
278                                 $defaultPreferences['variant'] = array(
279                                         'label-message' => 'yourvariant',
280                                         'type' => 'select',
281                                         'options' => $options,
282                                         'section' => 'personal/i18n',
283                                 );
284                         }
285                 }
286
287                 if ( count( $variantArray ) > 1 && !$wgDisableLangConversion && !$wgDisableTitleConversion ) {
288                         $defaultPreferences['noconvertlink'] =
289                                         array(
290                                 'type' => 'toggle',
291                                 'section' => 'personal/i18n',
292                                 'label-message' => 'tog-noconvertlink',
293                         );
294                 }
295
296                 global $wgMaxSigChars, $wgOut, $wgParser;
297
298                 // show a preview of the old signature first
299                 $oldsigWikiText = $wgParser->preSaveTransform( "~~~", new Title , $user, new ParserOptions );
300                 $oldsigHTML = $wgOut->parseInline( $oldsigWikiText );
301                 $defaultPreferences['oldsig'] = array(
302                         'type' => 'info',
303                         'raw' => true,
304                         'label-message' => 'tog-oldsig',
305                         'default' => $oldsigHTML,
306                         'section' => 'personal/signature',
307                 );
308                 $defaultPreferences['nickname'] = array(
309                         'type' => $wgAuth->allowPropChange( 'nickname' ) ? 'text' : 'info',
310                         'maxlength' => $wgMaxSigChars,
311                         'label-message' => 'yournick',
312                         'validation-callback' => array( 'Preferences', 'validateSignature' ),
313                         'section' => 'personal/signature',
314                         'filter-callback' => array( 'Preferences', 'cleanSignature' ),
315                 );
316                 $defaultPreferences['fancysig'] = array(
317                         'type' => 'toggle',
318                         'label-message' => 'tog-fancysig',
319                         'help-message' => 'prefs-help-signature', // show general help about signature at the bottom of the section
320                         'section' => 'personal/signature'
321                 );
322
323                 ## Email stuff
324
325                 global $wgEnableEmail;
326                 if ( $wgEnableEmail ) {
327                         global $wgEmailConfirmToEdit;
328
329                         $defaultPreferences['emailaddress'] = array(
330                                 'type' => $wgAuth->allowPropChange( 'emailaddress' ) ? 'email' : 'info',
331                                 'default' => $user->getEmail(),
332                                 'section' => 'personal/email',
333                                 'label-message' => 'youremail',
334                                 'help-message' => $wgEmailConfirmToEdit
335                                         ? 'prefs-help-email-required'
336                                         : 'prefs-help-email',
337                                 'validation-callback' => array( 'Preferences', 'validateEmail' ),
338                         );
339
340                         global $wgEnableUserEmail, $wgEmailAuthentication;
341
342                         $disableEmailPrefs = false;
343
344                         if ( $wgEmailAuthentication ) {
345                                 if ( $user->getEmail() ) {
346                                         if ( $user->getEmailAuthenticationTimestamp() ) {
347                                                 // date and time are separate parameters to facilitate localisation.
348                                                 // $time is kept for backward compat reasons.
349                                                 // 'emailauthenticated' is also used in SpecialConfirmemail.php
350                                                 $time = $wgLang->timeAndDate( $user->getEmailAuthenticationTimestamp(), true );
351                                                 $d = $wgLang->date( $user->getEmailAuthenticationTimestamp(), true );
352                                                 $t = $wgLang->time( $user->getEmailAuthenticationTimestamp(), true );
353                                                 $emailauthenticated = wfMsgExt(
354                                                         'emailauthenticated', 'parseinline',
355                                                         array( $time, $d, $t )
356                                                 ) . '<br />';
357                                                 $disableEmailPrefs = false;
358                                         } else {
359                                                 $disableEmailPrefs = true;
360                                                 $skin = $wgUser->getSkin();
361                                                 $emailauthenticated = wfMsgExt( 'emailnotauthenticated', 'parseinline' ) . '<br />' .
362                                                         $skin->link(
363                                                                 SpecialPage::getTitleFor( 'Confirmemail' ),
364                                                                 wfMsg( 'emailconfirmlink' ),
365                                                                 array(),
366                                                                 array(),
367                                                                 array( 'known', 'noclasses' )
368                                                         ) . '<br />';
369                                         }
370                                 } else {
371                                         $disableEmailPrefs = true;
372                                         $emailauthenticated = wfMsgHtml( 'noemailprefs' );
373                                 }
374
375                                 $defaultPreferences['emailauthentication'] = array(
376                                         'type' => 'info',
377                                         'raw' => true,
378                                         'section' => 'personal/email',
379                                         'label-message' => 'prefs-emailconfirm-label',
380                                         'default' => $emailauthenticated,
381                                 );
382
383                         }
384
385                         if ( $wgEnableUserEmail && $user->isAllowed( 'sendemail' ) ) {
386                                 $defaultPreferences['disablemail'] = array(
387                                         'type' => 'toggle',
388                                         'invert' => true,
389                                         'section' => 'personal/email',
390                                         'label-message' => 'allowemail',
391                                         'disabled' => $disableEmailPrefs,
392                                 );
393                                 $defaultPreferences['ccmeonemails'] = array(
394                                         'type' => 'toggle',
395                                         'section' => 'personal/email',
396                                         'label-message' => 'tog-ccmeonemails',
397                                         'disabled' => $disableEmailPrefs,
398                                 );
399                         }
400
401                         global $wgEnotifWatchlist;
402                         if ( $wgEnotifWatchlist ) {
403                                 $defaultPreferences['enotifwatchlistpages'] = array(
404                                         'type' => 'toggle',
405                                         'section' => 'personal/email',
406                                         'label-message' => 'tog-enotifwatchlistpages',
407                                         'disabled' => $disableEmailPrefs,
408                                 );
409                         }
410                         global $wgEnotifUserTalk;
411                         if ( $wgEnotifUserTalk ) {
412                                 $defaultPreferences['enotifusertalkpages'] = array(
413                                         'type' => 'toggle',
414                                         'section' => 'personal/email',
415                                         'label-message' => 'tog-enotifusertalkpages',
416                                         'disabled' => $disableEmailPrefs,
417                                 );
418                         }
419                         if ( $wgEnotifUserTalk || $wgEnotifWatchlist ) {
420                                 $defaultPreferences['enotifminoredits'] = array(
421                                         'type' => 'toggle',
422                                         'section' => 'personal/email',
423                                         'label-message' => 'tog-enotifminoredits',
424                                         'disabled' => $disableEmailPrefs,
425                                 );
426
427                                 global $wgEnotifRevealEditorAddress;
428                                 if ( $wgEnotifRevealEditorAddress ) {
429                                         $defaultPreferences['enotifrevealaddr'] = array(
430                                                 'type' => 'toggle',
431                                                 'section' => 'personal/email',
432                                                 'label-message' => 'tog-enotifrevealaddr',
433                                                 'disabled' => $disableEmailPrefs,
434                                         );
435                                 }
436                         }
437                 }
438         }
439
440         static function skinPreferences( $user, &$defaultPreferences ) {
441                 ## Skin #####################################
442                 global $wgLang, $wgAllowUserCss, $wgAllowUserJs;
443
444                 $defaultPreferences['skin'] = array(
445                         'type' => 'radio',
446                         'options' => self::generateSkinOptions( $user ),
447                         'label' => '&#160;',
448                         'section' => 'rendering/skin',
449                 );
450
451                 # Create links to user CSS/JS pages for all skins
452                 # This code is basically copied from generateSkinOptions().  It'd
453                 # be nice to somehow merge this back in there to avoid redundancy.
454                 if ( $wgAllowUserCss || $wgAllowUserJs ) {
455                         $sk = $user->getSkin();
456                         $linkTools = array();
457
458                         if ( $wgAllowUserCss ) {
459                                 $cssPage = Title::makeTitleSafe( NS_USER, $user->getName() . '/common.css' );
460                                 $linkTools[] = $sk->link( $cssPage, wfMsgHtml( 'prefs-custom-css' ) );
461                         }
462
463                         if ( $wgAllowUserJs ) {
464                                 $jsPage = Title::makeTitleSafe( NS_USER, $user->getName() . '/common.js' );
465                                 $linkTools[] = $sk->link( $jsPage, wfMsgHtml( 'prefs-custom-js' ) );
466                         }
467
468                         $defaultPreferences['commoncssjs'] = array(
469                                 'type' => 'info',
470                                 'raw' => true,
471                                 'default' => $wgLang->pipeList( $linkTools ),
472                                 'label-message' => 'prefs-common-css-js',
473                                 'section' => 'rendering/skin',
474                         );
475                 }
476
477                 $selectedSkin = $user->getOption( 'skin' );
478                 if ( in_array( $selectedSkin, array( 'cologneblue', 'standard' ) ) ) {
479                         $settings = array_flip( $wgLang->getQuickbarSettings() );
480
481                         $defaultPreferences['quickbar'] = array(
482                                 'type' => 'radio',
483                                 'options' => $settings,
484                                 'section' => 'rendering/skin',
485                                 'label-message' => 'qbsettings',
486                         );
487                 }
488         }
489
490         static function mathPreferences( $user, &$defaultPreferences ) {
491                 ## Math #####################################
492                 global $wgUseTeX, $wgLang;
493                 if ( $wgUseTeX ) {
494                         $defaultPreferences['math'] = array(
495                                 'type' => 'radio',
496                                 'options' => array_flip( array_map( 'wfMsgHtml', $wgLang->getMathNames() ) ),
497                                 'label' => '&#160;',
498                                 'section' => 'rendering/math',
499                         );
500                 }
501         }
502
503         static function filesPreferences( $user, &$defaultPreferences ) {
504                 ## Files #####################################
505                 $defaultPreferences['imagesize'] = array(
506                         'type' => 'select',
507                         'options' => self::getImageSizes(),
508                         'label-message' => 'imagemaxsize',
509                         'section' => 'rendering/files',
510                 );
511                 $defaultPreferences['thumbsize'] = array(
512                         'type' => 'select',
513                         'options' => self::getThumbSizes(),
514                         'label-message' => 'thumbsize',
515                         'section' => 'rendering/files',
516                 );
517         }
518
519         static function datetimePreferences( $user, &$defaultPreferences ) {
520                 global $wgLang;
521
522                 ## Date and time #####################################
523                 $dateOptions = self::getDateOptions();
524                 if ( $dateOptions ) {
525                         $defaultPreferences['date'] = array(
526                                 'type' => 'radio',
527                                 'options' => $dateOptions,
528                                 'label' => '&#160;',
529                                 'section' => 'datetime/dateformat',
530                         );
531                 }
532
533                 // Info
534                 $nowlocal = Xml::element( 'span', array( 'id' => 'wpLocalTime' ),
535                         $wgLang->time( $now = wfTimestampNow(), true ) );
536                 $nowserver = $wgLang->time( $now, false ) .
537                         Html::hidden( 'wpServerTime', substr( $now, 8, 2 ) * 60 + substr( $now, 10, 2 ) );
538
539                 $defaultPreferences['nowserver'] = array(
540                         'type' => 'info',
541                         'raw' => 1,
542                         'label-message' => 'servertime',
543                         'default' => $nowserver,
544                         'section' => 'datetime/timeoffset',
545                 );
546
547                 $defaultPreferences['nowlocal'] = array(
548                         'type' => 'info',
549                         'raw' => 1,
550                         'label-message' => 'localtime',
551                         'default' => $nowlocal,
552                         'section' => 'datetime/timeoffset',
553                 );
554
555                 // Grab existing pref.
556                 $tzOffset = $user->getOption( 'timecorrection' );
557                 $tz = explode( '|', $tzOffset, 2 );
558
559                 $tzSetting = $tzOffset;
560                 if ( count( $tz ) > 1 && $tz[0] == 'Offset' ) {
561                         $minDiff = $tz[1];
562                         $tzSetting = sprintf( '%+03d:%02d', floor( $minDiff / 60 ), abs( $minDiff ) % 60 );
563                 }
564
565                 $defaultPreferences['timecorrection'] = array(
566                         'class' => 'HTMLSelectOrOtherField',
567                         'label-message' => 'timezonelegend',
568                         'options' => self::getTimezoneOptions(),
569                         'default' => $tzSetting,
570                         'size' => 20,
571                         'section' => 'datetime/timeoffset',
572                 );
573         }
574
575         static function renderingPreferences( $user, &$defaultPreferences ) {
576                 ## Page Rendering ##############################
577                 global $wgAllowUserCssPrefs;
578                 if ( $wgAllowUserCssPrefs ) {
579                         $defaultPreferences['underline'] = array(
580                                 'type' => 'select',
581                                 'options' => array(
582                                         wfMsg( 'underline-never' ) => 0,
583                                         wfMsg( 'underline-always' ) => 1,
584                                         wfMsg( 'underline-default' ) => 2,
585                                 ),
586                                 'label-message' => 'tog-underline',
587                                 'section' => 'rendering/advancedrendering',
588                         );
589                 }
590
591                 $stubThresholdValues = array( 50, 100, 500, 1000, 2000, 5000, 10000 );
592                 $stubThresholdOptions = array( wfMsg( 'stub-threshold-disabled' ) => 0 );
593                 foreach ( $stubThresholdValues as $value ) {
594                         $stubThresholdOptions[wfMsg( 'size-bytes', $value )] = $value;
595                 }
596
597                 $defaultPreferences['stubthreshold'] = array(
598                         'type' => 'selectorother',
599                         'section' => 'rendering/advancedrendering',
600                         'options' => $stubThresholdOptions,
601                         'size' => 20,
602                         'label' => wfMsg( 'stub-threshold' ), // Raw HTML message. Yay?
603                 );
604
605                 if ( $wgAllowUserCssPrefs ) {
606                         $defaultPreferences['highlightbroken'] = array(
607                                 'type' => 'toggle',
608                                 'section' => 'rendering/advancedrendering',
609                                 'label' => wfMsg( 'tog-highlightbroken' ), // Raw HTML
610                         );
611                         $defaultPreferences['showtoc'] = array(
612                                 'type' => 'toggle',
613                                 'section' => 'rendering/advancedrendering',
614                                 'label-message' => 'tog-showtoc',
615                         );
616                 }
617                 $defaultPreferences['nocache'] = array(
618                         'type' => 'toggle',
619                         'label-message' => 'tog-nocache',
620                         'section' => 'rendering/advancedrendering',
621                 );
622                 $defaultPreferences['showhiddencats'] = array(
623                         'type' => 'toggle',
624                         'section' => 'rendering/advancedrendering',
625                         'label-message' => 'tog-showhiddencats'
626                 );
627                 $defaultPreferences['showjumplinks'] = array(
628                         'type' => 'toggle',
629                         'section' => 'rendering/advancedrendering',
630                         'label-message' => 'tog-showjumplinks',
631                 );
632
633                 if ( $wgAllowUserCssPrefs ) {
634                         $defaultPreferences['justify'] = array(
635                                 'type' => 'toggle',
636                                 'section' => 'rendering/advancedrendering',
637                                 'label-message' => 'tog-justify',
638                         );
639                 }
640
641                 $defaultPreferences['numberheadings'] = array(
642                         'type' => 'toggle',
643                         'section' => 'rendering/advancedrendering',
644                         'label-message' => 'tog-numberheadings',
645                 );
646         }
647
648         static function editingPreferences( $user, &$defaultPreferences ) {
649                 global $wgUseExternalEditor, $wgAllowUserCssPrefs;
650
651                 ## Editing #####################################
652                 $defaultPreferences['cols'] = array(
653                         'type' => 'int',
654                         'label-message' => 'columns',
655                         'section' => 'editing/textboxsize',
656                         'min' => 4,
657                         'max' => 1000,
658                 );
659                 $defaultPreferences['rows'] = array(
660                         'type' => 'int',
661                         'label-message' => 'rows',
662                         'section' => 'editing/textboxsize',
663                         'min' => 4,
664                         'max' => 1000,
665                 );
666
667                 if ( $wgAllowUserCssPrefs ) {
668                         $defaultPreferences['editfont'] = array(
669                                 'type' => 'select',
670                                 'section' => 'editing/advancedediting',
671                                 'label-message' => 'editfont-style',
672                                 'options' => array(
673                                         wfMsg( 'editfont-default' ) => 'default',
674                                         wfMsg( 'editfont-monospace' ) => 'monospace',
675                                         wfMsg( 'editfont-sansserif' ) => 'sans-serif',
676                                         wfMsg( 'editfont-serif' ) => 'serif',
677                                 )
678                         );
679                 }
680                 $defaultPreferences['previewontop'] = array(
681                         'type' => 'toggle',
682                         'section' => 'editing/advancedediting',
683                         'label-message' => 'tog-previewontop',
684                 );
685                 $defaultPreferences['previewonfirst'] = array(
686                         'type' => 'toggle',
687                         'section' => 'editing/advancedediting',
688                         'label-message' => 'tog-previewonfirst',
689                 );
690
691                 if ( $wgAllowUserCssPrefs ) {
692                         $defaultPreferences['editsection'] = array(
693                                 'type' => 'toggle',
694                                 'section' => 'editing/advancedediting',
695                                 'label-message' => 'tog-editsection',
696                         );
697                 }
698                 $defaultPreferences['editsectiononrightclick'] = array(
699                         'type' => 'toggle',
700                         'section' => 'editing/advancedediting',
701                         'label-message' => 'tog-editsectiononrightclick',
702                 );
703                 $defaultPreferences['editondblclick'] = array(
704                         'type' => 'toggle',
705                         'section' => 'editing/advancedediting',
706                         'label-message' => 'tog-editondblclick',
707                 );
708                 $defaultPreferences['showtoolbar'] = array(
709                         'type' => 'toggle',
710                         'section' => 'editing/advancedediting',
711                         'label-message' => 'tog-showtoolbar',
712                 );
713                 $defaultPreferences['minordefault'] = array(
714                         'type' => 'toggle',
715                         'section' => 'editing/advancedediting',
716                         'label-message' => 'tog-minordefault',
717                 );
718
719                 if ( $wgUseExternalEditor ) {
720                         $defaultPreferences['externaleditor'] = array(
721                                 'type' => 'toggle',
722                                 'section' => 'editing/advancedediting',
723                                 'label-message' => 'tog-externaleditor',
724                         );
725                         $defaultPreferences['externaldiff'] = array(
726                                 'type' => 'toggle',
727                                 'section' => 'editing/advancedediting',
728                                 'label-message' => 'tog-externaldiff',
729                         );
730                 }
731
732                 $defaultPreferences['forceeditsummary'] = array(
733                         'type' => 'toggle',
734                         'section' => 'editing/advancedediting',
735                         'label-message' => 'tog-forceeditsummary',
736                 );
737
738                                 
739                 $defaultPreferences['uselivepreview'] = array(
740                         'type' => 'toggle',
741                         'section' => 'editing/advancedediting',
742                         'label-message' => 'tog-uselivepreview',
743                 );
744         }
745
746         static function rcPreferences( $user, &$defaultPreferences ) {
747                 global $wgRCMaxAge, $wgUseRCPatrol, $wgLang;
748
749                 ## RecentChanges #####################################
750                 $defaultPreferences['rcdays'] = array(
751                         'type' => 'float',
752                         'label-message' => 'recentchangesdays',
753                         'section' => 'rc/displayrc',
754                         'min' => 1,
755                         'max' => ceil( $wgRCMaxAge / ( 3600 * 24 ) ),
756                         'help' => wfMsgExt(
757                                 'recentchangesdays-max',
758                                 array( 'parsemag' ),
759                                 $wgLang->formatNum( ceil( $wgRCMaxAge / ( 3600 * 24 ) ) )
760                         )
761                 );
762                 $defaultPreferences['rclimit'] = array(
763                         'type' => 'int',
764                         'label-message' => 'recentchangescount',
765                         'help-message' => 'prefs-help-recentchangescount',
766                         'section' => 'rc/displayrc',
767                 );
768                 $defaultPreferences['usenewrc'] = array(
769                         'type' => 'toggle',
770                         'label-message' => 'tog-usenewrc',
771                         'section' => 'rc/advancedrc',
772                 );
773                 $defaultPreferences['hideminor'] = array(
774                         'type' => 'toggle',
775                         'label-message' => 'tog-hideminor',
776                         'section' => 'rc/advancedrc',
777                 );
778
779                 if ( $wgUseRCPatrol ) {
780                         $defaultPreferences['hidepatrolled'] = array(
781                                 'type' => 'toggle',
782                                 'section' => 'rc/advancedrc',
783                                 'label-message' => 'tog-hidepatrolled',
784                         );
785                         $defaultPreferences['newpageshidepatrolled'] = array(
786                                 'type' => 'toggle',
787                                 'section' => 'rc/advancedrc',
788                                 'label-message' => 'tog-newpageshidepatrolled',
789                         );
790                 }
791
792                 global $wgRCShowWatchingUsers;
793                 if ( $wgRCShowWatchingUsers ) {
794                         $defaultPreferences['shownumberswatching'] = array(
795                                 'type' => 'toggle',
796                                 'section' => 'rc/advancedrc',
797                                 'label-message' => 'tog-shownumberswatching',
798                         );
799                 }
800         }
801
802         static function watchlistPreferences( $user, &$defaultPreferences ) {
803                 global $wgUseRCPatrol, $wgEnableAPI;
804
805                 ## Watchlist #####################################
806                 $defaultPreferences['watchlistdays'] = array(
807                         'type' => 'float',
808                         'min' => 0,
809                         'max' => 7,
810                         'section' => 'watchlist/displaywatchlist',
811                         'help' => wfMsgHtml( 'prefs-watchlist-days-max' ),
812                         'label-message' => 'prefs-watchlist-days',
813                 );
814                 $defaultPreferences['wllimit'] = array(
815                         'type' => 'int',
816                         'min' => 0,
817                         'max' => 1000,
818                         'label-message' => 'prefs-watchlist-edits',
819                         'help' => wfMsgHtml( 'prefs-watchlist-edits-max' ),
820                         'section' => 'watchlist/displaywatchlist',
821                 );
822                 $defaultPreferences['extendwatchlist'] = array(
823                         'type' => 'toggle',
824                         'section' => 'watchlist/advancedwatchlist',
825                         'label-message' => 'tog-extendwatchlist',
826                 );
827                 $defaultPreferences['watchlisthideminor'] = array(
828                         'type' => 'toggle',
829                         'section' => 'watchlist/advancedwatchlist',
830                         'label-message' => 'tog-watchlisthideminor',
831                 );
832                 $defaultPreferences['watchlisthidebots'] = array(
833                         'type' => 'toggle',
834                         'section' => 'watchlist/advancedwatchlist',
835                         'label-message' => 'tog-watchlisthidebots',
836                 );
837                 $defaultPreferences['watchlisthideown'] = array(
838                         'type' => 'toggle',
839                         'section' => 'watchlist/advancedwatchlist',
840                         'label-message' => 'tog-watchlisthideown',
841                 );
842                 $defaultPreferences['watchlisthideanons'] = array(
843                         'type' => 'toggle',
844                         'section' => 'watchlist/advancedwatchlist',
845                         'label-message' => 'tog-watchlisthideanons',
846                 );
847                 $defaultPreferences['watchlisthideliu'] = array(
848                         'type' => 'toggle',
849                         'section' => 'watchlist/advancedwatchlist',
850                         'label-message' => 'tog-watchlisthideliu',
851                 );
852
853                 if ( $wgUseRCPatrol ) {
854                         $defaultPreferences['watchlisthidepatrolled'] = array(
855                                 'type' => 'toggle',
856                                 'section' => 'watchlist/advancedwatchlist',
857                                 'label-message' => 'tog-watchlisthidepatrolled',
858                         );
859                 }
860
861                 if ( $wgEnableAPI ) {
862                         # Some random gibberish as a proposed default
863                         $hash = sha1( mt_rand() . microtime( true ) );
864
865                         $defaultPreferences['watchlisttoken'] = array(
866                                 'type' => 'text',
867                                 'section' => 'watchlist/advancedwatchlist',
868                                 'label-message' => 'prefs-watchlist-token',
869                                 'help' => wfMsgHtml( 'prefs-help-watchlist-token', $hash )
870                         );
871                 }
872
873                 $watchTypes = array(
874                         'edit' => 'watchdefault',
875                         'move' => 'watchmoves',
876                         'delete' => 'watchdeletion'
877                 );
878
879                 // Kinda hacky
880                 if ( $user->isAllowed( 'createpage' ) || $user->isAllowed( 'createtalk' ) ) {
881                         $watchTypes['read'] = 'watchcreations';
882                 }
883
884                 foreach ( $watchTypes as $action => $pref ) {
885                         if ( $user->isAllowed( $action ) ) {
886                                 $defaultPreferences[$pref] = array(
887                                         'type' => 'toggle',
888                                         'section' => 'watchlist/advancedwatchlist',
889                                         'label-message' => "tog-$pref",
890                                 );
891                         }
892                 }
893         }
894
895         static function searchPreferences( $user, &$defaultPreferences ) {
896                 global $wgContLang;
897
898                 ## Search #####################################
899                 $defaultPreferences['searchlimit'] = array(
900                         'type' => 'int',
901                         'label-message' => 'resultsperpage',
902                         'section' => 'searchoptions/displaysearchoptions',
903                         'min' => 0,
904                 );
905                 $defaultPreferences['contextlines'] = array(
906                         'type' => 'int',
907                         'label-message' => 'contextlines',
908                         'section' => 'searchoptions/displaysearchoptions',
909                         'min' => 0,
910                 );
911                 $defaultPreferences['contextchars'] = array(
912                         'type' => 'int',
913                         'label-message' => 'contextchars',
914                         'section' => 'searchoptions/displaysearchoptions',
915                         'min' => 0,
916                 );
917
918                 global $wgEnableMWSuggest;
919                 if ( $wgEnableMWSuggest ) {
920                         $defaultPreferences['disablesuggest'] = array(
921                                 'type' => 'toggle',
922                                 'label-message' => 'mwsuggest-disable',
923                                 'section' => 'searchoptions/displaysearchoptions',
924                         );
925                 }
926                 
927                 global $wgVectorUseSimpleSearch;
928                 if ( $wgVectorUseSimpleSearch ) {
929                         $defaultPreferences['vector-simplesearch'] = array(
930                                 'type' => 'toggle',
931                                 'label-message' => 'vector-simplesearch-preference',
932                                 'section' => 'searchoptions/displaysearchoptions'
933                         );
934                 }
935
936                 $defaultPreferences['searcheverything'] = array(
937                         'type' => 'toggle',
938                         'label-message' => 'searcheverything-enable',
939                         'section' => 'searchoptions/advancedsearchoptions',
940                 );
941
942                 // Searchable namespaces back-compat with old format
943                 $searchableNamespaces = SearchEngine::searchableNamespaces();
944
945                 $nsOptions = array();
946
947                 foreach ( $wgContLang->getNamespaces() as $ns => $name ) {
948                         if ( $ns < 0 ) {
949                                 continue;
950                         }
951
952                         $displayNs = str_replace( '_', ' ', $name );
953
954                         if ( !$displayNs ) {
955                                 $displayNs = wfMsg( 'blanknamespace' );
956                         }
957
958                         $displayNs = htmlspecialchars( $displayNs );
959                         $nsOptions[$displayNs] = $ns;
960                 }
961
962                 $defaultPreferences['searchnamespaces'] = array(
963                         'type' => 'multiselect',
964                         'label-message' => 'defaultns',
965                         'options' => $nsOptions,
966                         'section' => 'searchoptions/advancedsearchoptions',
967                         'prefix' => 'searchNs',
968                 );
969         }
970
971         static function miscPreferences( $user, &$defaultPreferences ) {
972                 ## Misc #####################################
973                 $defaultPreferences['diffonly'] = array(
974                         'type' => 'toggle',
975                         'section' => 'misc/diffs',
976                         'label-message' => 'tog-diffonly',
977                 );
978                 $defaultPreferences['norollbackdiff'] = array(
979                         'type' => 'toggle',
980                         'section' => 'misc/diffs',
981                         'label-message' => 'tog-norollbackdiff',
982                 );
983
984                 // Stuff from Language::getExtraUserToggles()
985                 global $wgContLang;
986
987                 $toggles = $wgContLang->getExtraUserToggles();
988
989                 foreach ( $toggles as $toggle ) {
990                         $defaultPreferences[$toggle] = array(
991                                 'type' => 'toggle',
992                                 'section' => 'personal/i18n',
993                                 'label-message' => "tog-$toggle",
994                         );
995                 }
996         }
997
998         /**
999          * @param $user The User object
1000          * @return Array: text/links to display as key; $skinkey as value
1001          */
1002         static function generateSkinOptions( $user ) {
1003                 global $wgDefaultSkin, $wgLang, $wgAllowUserCss, $wgAllowUserJs;
1004                 $ret = array();
1005
1006                 $mptitle = Title::newMainPage();
1007                 $previewtext = wfMsgHtml( 'skin-preview' );
1008
1009                 # Only show members of Skin::getSkinNames() rather than
1010                 # $skinNames (skins is all skin names from Language.php)
1011                 $validSkinNames = Skin::getUsableSkins();
1012
1013                 # Sort by UI skin name. First though need to update validSkinNames as sometimes
1014                 # the skinkey & UI skinname differ (e.g. "standard" skinkey is "Classic" in the UI).
1015                 foreach ( $validSkinNames as $skinkey => &$skinname ) {
1016                         $msgName = "skinname-{$skinkey}";
1017                         $localisedSkinName = wfMsg( $msgName );
1018                         if ( !wfEmptyMsg( $msgName, $localisedSkinName ) ) {
1019                                 $skinname = htmlspecialchars( $localisedSkinName );
1020                         }
1021                 }
1022                 asort( $validSkinNames );
1023                 $sk = $user->getSkin();
1024
1025                 foreach ( $validSkinNames as $skinkey => $sn ) {
1026                         $linkTools = array();
1027
1028                         # Mark the default skin
1029                         if ( $skinkey == $wgDefaultSkin ) {
1030                                 $linkTools[] = wfMsgHtml( 'default' );
1031                         }
1032
1033                         # Create preview link
1034                         $mplink = htmlspecialchars( $mptitle->getLocalURL( "useskin=$skinkey" ) );
1035                         $linkTools[] = "<a target='_blank' href=\"$mplink\">$previewtext</a>";
1036
1037                         # Create links to user CSS/JS pages
1038                         if ( $wgAllowUserCss ) {
1039                                 $cssPage = Title::makeTitleSafe( NS_USER, $user->getName() . '/' . $skinkey . '.css' );
1040                                 $linkTools[] = $sk->link( $cssPage, wfMsgHtml( 'prefs-custom-css' ) );
1041                         }
1042
1043                         if ( $wgAllowUserJs ) {
1044                                 $jsPage = Title::makeTitleSafe( NS_USER, $user->getName() . '/' . $skinkey . '.js' );
1045                                 $linkTools[] = $sk->link( $jsPage, wfMsgHtml( 'prefs-custom-js' ) );
1046                         }
1047
1048                         $display = $sn . ' ' . wfMsg( 'parentheses', $wgLang->pipeList( $linkTools ) );
1049                         $ret[$display] = $skinkey;
1050                 }
1051
1052                 return $ret;
1053         }
1054
1055         static function getDateOptions() {
1056                 global $wgLang;
1057                 $dateopts = $wgLang->getDatePreferences();
1058
1059                 $ret = array();
1060
1061                 if ( $dateopts ) {
1062                         if ( !in_array( 'default', $dateopts ) ) {
1063                                 $dateopts[] = 'default'; // Make sure default is always valid
1064                                                                                 // Bug 19237
1065                         }
1066
1067                         // KLUGE: site default might not be valid for user language
1068                         global $wgDefaultUserOptions;
1069                         if ( !in_array( $wgDefaultUserOptions['date'], $dateopts ) ) {
1070                                 $wgDefaultUserOptions['date'] = 'default';
1071                         }
1072
1073                         $epoch = wfTimestampNow();
1074                         foreach ( $dateopts as $key ) {
1075                                 if ( $key == 'default' ) {
1076                                         $formatted = wfMsgHtml( 'datedefault' );
1077                                 } else {
1078                                         $formatted = htmlspecialchars( $wgLang->timeanddate( $epoch, false, $key ) );
1079                                 }
1080                                 $ret[$formatted] = $key;
1081                         }
1082                 }
1083                 return $ret;
1084         }
1085
1086         static function getImageSizes() {
1087                 global $wgImageLimits;
1088
1089                 $ret = array();
1090
1091                 foreach ( $wgImageLimits as $index => $limits ) {
1092                         $display = "{$limits[0]}×{$limits[1]}" . wfMsg( 'unit-pixel' );
1093                         $ret[$display] = $index;
1094                 }
1095
1096                 return $ret;
1097         }
1098
1099         static function getThumbSizes() {
1100                 global $wgThumbLimits;
1101
1102                 $ret = array();
1103
1104                 foreach ( $wgThumbLimits as $index => $size ) {
1105                         $display = $size . wfMsg( 'unit-pixel' );
1106                         $ret[$display] = $index;
1107                 }
1108
1109                 return $ret;
1110         }
1111
1112         static function validateSignature( $signature, $alldata ) {
1113                 global $wgParser, $wgMaxSigChars, $wgLang;
1114                 if ( mb_strlen( $signature ) > $wgMaxSigChars ) {
1115                         return Xml::element( 'span', array( 'class' => 'error' ),
1116                                 wfMsgExt( 'badsiglength', 'parsemag',
1117                                         $wgLang->formatNum( $wgMaxSigChars )
1118                                 )
1119                         );
1120                 } elseif ( isset( $alldata['fancysig'] ) &&
1121                                 $alldata['fancysig'] &&
1122                                 false === $wgParser->validateSig( $signature ) ) {
1123                         return Xml::element( 'span', array( 'class' => 'error' ), wfMsg( 'badsig' ) );
1124                 } else {
1125                         return true;
1126                 }
1127         }
1128
1129         static function cleanSignature( $signature, $alldata ) {
1130                 global $wgParser;
1131                 if ( isset( $alldata['fancysig'] ) && $alldata['fancysig'] ) {
1132                         $signature = $wgParser->cleanSig( $signature );
1133                 } else {
1134                         // When no fancy sig used, make sure ~{3,5} get removed.
1135                         $signature = $wgParser->cleanSigInSig( $signature );
1136                 }
1137
1138                 return $signature;
1139         }
1140
1141         static function validateEmail( $email, $alldata ) {
1142                 if ( $email && !User::isValidEmailAddr( $email ) ) {
1143                         return wfMsgExt( 'invalidemailaddress', 'parseinline' );
1144                 }
1145
1146                 global $wgEmailConfirmToEdit;
1147                 if ( $wgEmailConfirmToEdit && !$email ) {
1148                         return wfMsgExt( 'noemailtitle', 'parseinline' );
1149                 }
1150                 return true;
1151         }
1152
1153         static function getFormObject( $user, $formClass = 'PreferencesForm' ) {
1154                 $formDescriptor = Preferences::getPreferences( $user );
1155                 $htmlForm = new $formClass( $formDescriptor, 'prefs' );
1156
1157                 $htmlForm->setSubmitText( wfMsg( 'saveprefs' ) );
1158                 # Used message keys: 'accesskey-preferences-save', 'tooltip-preferences-save'
1159                 $htmlForm->setSubmitTooltip( 'preferences-save' );
1160                 $htmlForm->setTitle( SpecialPage::getTitleFor( 'Preferences' ) );
1161                 $htmlForm->setSubmitID( 'prefsubmit' );
1162                 $htmlForm->setSubmitCallback( array( 'Preferences', 'tryFormSubmit' ) );
1163
1164                 return $htmlForm;
1165         }
1166
1167         static function getTimezoneOptions() {
1168                 $opt = array();
1169
1170                 global $wgLocalTZoffset;
1171
1172                 $opt[wfMsg( 'timezoneuseserverdefault' )] = "System|$wgLocalTZoffset";
1173                 $opt[wfMsg( 'timezoneuseoffset' )] = 'other';
1174                 $opt[wfMsg( 'guesstimezone' )] = 'guess';
1175
1176                 if ( function_exists( 'timezone_identifiers_list' ) ) {
1177                         # Read timezone list
1178                         $tzs = timezone_identifiers_list();
1179                         sort( $tzs );
1180
1181                         $tzRegions = array();
1182                         $tzRegions['Africa'] = wfMsg( 'timezoneregion-africa' );
1183                         $tzRegions['America'] = wfMsg( 'timezoneregion-america' );
1184                         $tzRegions['Antarctica'] = wfMsg( 'timezoneregion-antarctica' );
1185                         $tzRegions['Arctic'] = wfMsg( 'timezoneregion-arctic' );
1186                         $tzRegions['Asia'] = wfMsg( 'timezoneregion-asia' );
1187                         $tzRegions['Atlantic'] = wfMsg( 'timezoneregion-atlantic' );
1188                         $tzRegions['Australia'] = wfMsg( 'timezoneregion-australia' );
1189                         $tzRegions['Europe'] = wfMsg( 'timezoneregion-europe' );
1190                         $tzRegions['Indian'] = wfMsg( 'timezoneregion-indian' );
1191                         $tzRegions['Pacific'] = wfMsg( 'timezoneregion-pacific' );
1192                         asort( $tzRegions );
1193
1194                         $prefill = array_fill_keys( array_values( $tzRegions ), array() );
1195                         $opt = array_merge( $opt, $prefill );
1196
1197                         $now = date_create( 'now' );
1198
1199                         foreach ( $tzs as $tz ) {
1200                                 $z = explode( '/', $tz, 2 );
1201
1202                                 # timezone_identifiers_list() returns a number of
1203                                 # backwards-compatibility entries. This filters them out of the
1204                                 # list presented to the user.
1205                                 if ( count( $z ) != 2 || !array_key_exists( $z[0], $tzRegions ) ) {
1206                                         continue;
1207                                 }
1208
1209                                 # Localize region
1210                                 $z[0] = $tzRegions[$z[0]];
1211
1212                                 $minDiff = floor( timezone_offset_get( timezone_open( $tz ), $now ) / 60 );
1213
1214                                 $display = str_replace( '_', ' ', $z[0] . '/' . $z[1] );
1215                                 $value = "ZoneInfo|$minDiff|$tz";
1216
1217                                 $opt[$z[0]][$display] = $value;
1218                         }
1219                 }
1220                 return $opt;
1221         }
1222         
1223         static function filterIntval( $value, $alldata ){
1224                 return intval( $value );
1225         }
1226
1227         static function filterTimezoneInput( $tz, $alldata ) {
1228                 $data = explode( '|', $tz, 3 );
1229                 switch ( $data[0] ) {
1230                         case 'ZoneInfo':
1231                         case 'System':
1232                                 return $tz;
1233                         default:
1234                                 $data = explode( ':', $tz, 2 );
1235                                 if ( count( $data ) == 2 ) {
1236                                         $data[0] = intval( $data[0] );
1237                                         $data[1] = intval( $data[1] );
1238                                         $minDiff = abs( $data[0] ) * 60 + $data[1];
1239                                         if ( $data[0] < 0 ) $minDiff = - $minDiff;
1240                                 } else {
1241                                         $minDiff = intval( $data[0] ) * 60;
1242                                 }
1243
1244                                 # Max is +14:00 and min is -12:00, see:
1245                                 # http://en.wikipedia.org/wiki/Timezone
1246                                 $minDiff = min( $minDiff, 840 );  # 14:00
1247                                 $minDiff = max( $minDiff, - 720 ); # -12:00
1248                                 return 'Offset|' . $minDiff;
1249                 }
1250         }
1251
1252         static function tryFormSubmit( $formData, $entryPoint = 'internal' ) {
1253                 global $wgUser, $wgEmailAuthentication, $wgEnableEmail;
1254
1255                 $result = true;
1256
1257                 // Filter input
1258                 foreach ( array_keys( $formData ) as $name ) {
1259                         if ( isset( self::$saveFilters[$name] ) ) {
1260                                 $formData[$name] =
1261                                         call_user_func( self::$saveFilters[$name], $formData[$name], $formData );
1262                         }
1263                 }
1264
1265                 // Stuff that shouldn't be saved as a preference.
1266                 $saveBlacklist = array(
1267                         'realname',
1268                         'emailaddress',
1269                 );
1270
1271                 if ( $wgEnableEmail ) {
1272                         $newaddr = $formData['emailaddress'];
1273                         $oldaddr = $wgUser->getEmail();
1274                         if ( ( $newaddr != '' ) && ( $newaddr != $oldaddr ) ) {
1275                                 # the user has supplied a new email address on the login page
1276                                 # new behaviour: set this new emailaddr from login-page into user database record
1277                                 $wgUser->setEmail( $newaddr );
1278                                 # but flag as "dirty" = unauthenticated
1279                                 $wgUser->invalidateEmail();
1280                                 if ( $wgEmailAuthentication ) {
1281                                         # Mail a temporary password to the dirty address.
1282                                         # User can come back through the confirmation URL to re-enable email.
1283                                         $type = $oldaddr != '' ? 'changed' : 'set';
1284                                         $result = $wgUser->sendConfirmationMail( $type );
1285                                         if ( !$result->isGood() ) {
1286                                                 return htmlspecialchars( $result->getWikiText( 'mailerror' ) );
1287                                         } elseif ( $entryPoint == 'ui' ) {
1288                                                 $result = 'eauth';
1289                                         }
1290                                 }
1291                         } else {
1292                                 $wgUser->setEmail( $newaddr );
1293                         }
1294                         if ( $oldaddr != $newaddr ) {
1295                                 wfRunHooks( 'PrefsEmailAudit', array( $wgUser, $oldaddr, $newaddr ) );
1296                         }
1297                 }
1298
1299                 // Fortunately, the realname field is MUCH simpler
1300                 global $wgHiddenPrefs;
1301                 if ( !in_array( 'realname', $wgHiddenPrefs ) ) {
1302                         $realName = $formData['realname'];
1303                         $wgUser->setRealName( $realName );
1304                 }
1305
1306                 foreach ( $saveBlacklist as $b ) {
1307                         unset( $formData[$b] );
1308                 }
1309
1310                 //  Keeps old preferences from interfering due to back-compat
1311                 //  code, etc.
1312                 $wgUser->resetOptions();
1313
1314                 foreach ( $formData as $key => $value ) {
1315                         $wgUser->setOption( $key, $value );
1316                 }
1317
1318                 $wgUser->saveSettings();
1319
1320                 return $result;
1321         }
1322
1323         public static function tryUISubmit( $formData ) {
1324                 $res = self::tryFormSubmit( $formData, 'ui' );
1325
1326                 if ( $res ) {
1327                         $urlOptions = array( 'success' );
1328
1329                         if ( $res === 'eauth' ) {
1330                                 $urlOptions[] = 'eauth';
1331                         }
1332
1333                         $queryString = implode( '&', $urlOptions );
1334
1335                         $url = SpecialPage::getTitleFor( 'Preferences' )->getFullURL( $queryString );
1336
1337                         global $wgOut;
1338                         $wgOut->redirect( $url );
1339                 }
1340
1341                 return Status::newGood();
1342         }
1343
1344         public static function loadOldSearchNs( $user ) {
1345                 $searchableNamespaces = SearchEngine::searchableNamespaces();
1346                 // Back compat with old format
1347                 $arr = array();
1348
1349                 foreach ( $searchableNamespaces as $ns => $name ) {
1350                         if ( $user->getOption( 'searchNs' . $ns ) ) {
1351                                 $arr[] = $ns;
1352                         }
1353                 }
1354
1355                 return $arr;
1356         }
1357 }
1358
1359 /** Some tweaks to allow js prefs to work */
1360 class PreferencesForm extends HTMLForm {
1361         function wrapForm( $html ) {
1362                 $html = Xml::tags( 'div', array( 'id' => 'preferences' ), $html );
1363
1364                 return parent::wrapForm( $html );
1365         }
1366
1367         function getButtons() {
1368                 $html = parent::getButtons();
1369
1370                 global $wgUser;
1371
1372                 $sk = $wgUser->getSkin();
1373                 $t = SpecialPage::getTitleFor( 'Preferences', 'reset' );
1374
1375                 $html .= "\n" . $sk->link( $t, wfMsgHtml( 'restoreprefs' ) );
1376
1377                 $html = Xml::tags( 'div', array( 'class' => 'mw-prefs-buttons' ), $html );
1378
1379                 return $html;
1380         }
1381
1382         function filterDataForSubmit( $data ) {
1383                 // Support for separating MultiSelect preferences into multiple preferences
1384                 // Due to lack of array support.
1385                 foreach ( $this->mFlatFields as $fieldname => $field ) {
1386                         $info = $field->mParams;
1387                         if ( $field instanceof HTMLMultiSelectField ) {
1388                                 $options = HTMLFormField::flattenOptions( $info['options'] );
1389                                 $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $fieldname;
1390
1391                                 foreach ( $options as $opt ) {
1392                                         $data["$prefix$opt"] = in_array( $opt, $data[$fieldname] );
1393                                 }
1394
1395                                 unset( $data[$fieldname] );
1396                         }
1397                 }
1398
1399                 return $data;
1400         }
1401 }