MediaWiki  1.29.1
Preferences.php
Go to the documentation of this file.
1 <?php
25 
51 class Preferences {
53  protected static $defaultPreferences = null;
54 
56  protected static $saveFilters = [
57  'timecorrection' => [ 'Preferences', 'filterTimezoneInput' ],
58  'rclimit' => [ 'Preferences', 'filterIntval' ],
59  'wllimit' => [ 'Preferences', 'filterIntval' ],
60  'searchlimit' => [ 'Preferences', 'filterIntval' ],
61  ];
62 
63  // Stuff that shouldn't be saved as a preference.
64  private static $saveBlacklist = [
65  'realname',
66  'emailaddress',
67  ];
68 
72  static function getSaveBlacklist() {
73  return self::$saveBlacklist;
74  }
75 
83  if ( self::$defaultPreferences ) {
85  }
86 
88 
99 
100  Hooks::run( 'GetPreferences', [ $user, &$defaultPreferences ] );
101 
103  self::$defaultPreferences = $defaultPreferences;
104  return $defaultPreferences;
105  }
106 
116  # # Remove preferences that wikis don't want to use
117  foreach ( $context->getConfig()->get( 'HiddenPrefs' ) as $pref ) {
118  if ( isset( $defaultPreferences[$pref] ) ) {
119  unset( $defaultPreferences[$pref] );
120  }
121  }
122 
123  # # Make sure that form fields have their parent set. See T43337.
124  $dummyForm = new HTMLForm( [], $context );
125 
126  $disable = !$user->isAllowed( 'editmyoptions' );
127 
128  $defaultOptions = User::getDefaultOptions();
129  # # Prod in defaults from the user
130  foreach ( $defaultPreferences as $name => &$info ) {
131  $prefFromUser = self::getOptionFromUser( $name, $info, $user );
132  if ( $disable && !in_array( $name, self::$saveBlacklist ) ) {
133  $info['disabled'] = 'disabled';
134  }
135  $field = HTMLForm::loadInputFromParameters( $name, $info, $dummyForm ); // For validation
136  $globalDefault = isset( $defaultOptions[$name] )
137  ? $defaultOptions[$name]
138  : null;
139 
140  // If it validates, set it as the default
141  if ( isset( $info['default'] ) ) {
142  // Already set, no problem
143  continue;
144  } elseif ( !is_null( $prefFromUser ) && // Make sure we're not just pulling nothing
145  $field->validate( $prefFromUser, $user->getOptions() ) === true ) {
146  $info['default'] = $prefFromUser;
147  } elseif ( $field->validate( $globalDefault, $user->getOptions() ) === true ) {
148  $info['default'] = $globalDefault;
149  } else {
150  throw new MWException( "Global default '$globalDefault' is invalid for field $name" );
151  }
152  }
153 
154  return $defaultPreferences;
155  }
156 
165  static function getOptionFromUser( $name, $info, $user ) {
166  $val = $user->getOption( $name );
167 
168  // Handling for multiselect preferences
169  if ( ( isset( $info['type'] ) && $info['type'] == 'multiselect' ) ||
170  ( isset( $info['class'] ) && $info['class'] == 'HTMLMultiSelectField' ) ) {
171  $options = HTMLFormField::flattenOptions( $info['options'] );
172  $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
173  $val = [];
174 
175  foreach ( $options as $value ) {
176  if ( $user->getOption( "$prefix$value" ) ) {
177  $val[] = $value;
178  }
179  }
180  }
181 
182  // Handling for checkmatrix preferences
183  if ( ( isset( $info['type'] ) && $info['type'] == 'checkmatrix' ) ||
184  ( isset( $info['class'] ) && $info['class'] == 'HTMLCheckMatrix' ) ) {
185  $columns = HTMLFormField::flattenOptions( $info['columns'] );
186  $rows = HTMLFormField::flattenOptions( $info['rows'] );
187  $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
188  $val = [];
189 
190  foreach ( $columns as $column ) {
191  foreach ( $rows as $row ) {
192  if ( $user->getOption( "$prefix$column-$row" ) ) {
193  $val[] = "$column-$row";
194  }
195  }
196  }
197  }
198 
199  return $val;
200  }
201 
210 
211  $authManager = AuthManager::singleton();
212  $config = $context->getConfig();
213  // retrieving user name for GENDER and misc.
214  $userName = $user->getName();
215 
216  # # User info #####################################
217  // Information panel
218  $defaultPreferences['username'] = [
219  'type' => 'info',
220  'label-message' => [ 'username', $userName ],
221  'default' => $userName,
222  'section' => 'personal/info',
223  ];
224 
226 
227  # Get groups to which the user belongs
228  $userEffectiveGroups = $user->getEffectiveGroups();
229  $userGroupMemberships = $user->getGroupMemberships();
230  $userGroups = $userMembers = $userTempGroups = $userTempMembers = [];
231  foreach ( $userEffectiveGroups as $ueg ) {
232  if ( $ueg == '*' ) {
233  // Skip the default * group, seems useless here
234  continue;
235  }
236 
237  if ( isset( $userGroupMemberships[$ueg] ) ) {
238  $groupStringOrObject = $userGroupMemberships[$ueg];
239  } else {
240  $groupStringOrObject = $ueg;
241  }
242 
243  $userG = UserGroupMembership::getLink( $groupStringOrObject, $context, 'html' );
244  $userM = UserGroupMembership::getLink( $groupStringOrObject, $context, 'html',
245  $userName );
246 
247  // Store expiring groups separately, so we can place them before non-expiring
248  // groups in the list. This is to avoid the ambiguity of something like
249  // "administrator, bureaucrat (until X date)" -- users might wonder whether the
250  // expiry date applies to both groups, or just the last one
251  if ( $groupStringOrObject instanceof UserGroupMembership &&
252  $groupStringOrObject->getExpiry()
253  ) {
254  $userTempGroups[] = $userG;
255  $userTempMembers[] = $userM;
256  } else {
257  $userGroups[] = $userG;
258  $userMembers[] = $userM;
259  }
260  }
261  sort( $userGroups );
262  sort( $userMembers );
263  sort( $userTempGroups );
264  sort( $userTempMembers );
265  $userGroups = array_merge( $userTempGroups, $userGroups );
266  $userMembers = array_merge( $userTempMembers, $userMembers );
267 
268  $defaultPreferences['usergroups'] = [
269  'type' => 'info',
270  'label' => $context->msg( 'prefs-memberingroups' )->numParams(
271  count( $userGroups ) )->params( $userName )->parse(),
272  'default' => $context->msg( 'prefs-memberingroups-type' )
273  ->rawParams( $lang->commaList( $userGroups ), $lang->commaList( $userMembers ) )
274  ->escaped(),
275  'raw' => true,
276  'section' => 'personal/info',
277  ];
278 
279  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
280 
281  $editCount = $linkRenderer->makeLink( SpecialPage::getTitleFor( "Contributions", $userName ),
282  $lang->formatNum( $user->getEditCount() ) );
283 
284  $defaultPreferences['editcount'] = [
285  'type' => 'info',
286  'raw' => true,
287  'label-message' => 'prefs-edits',
288  'default' => $editCount,
289  'section' => 'personal/info',
290  ];
291 
292  if ( $user->getRegistration() ) {
293  $displayUser = $context->getUser();
294  $userRegistration = $user->getRegistration();
295  $defaultPreferences['registrationdate'] = [
296  'type' => 'info',
297  'label-message' => 'prefs-registration',
298  'default' => $context->msg(
299  'prefs-registration-date-time',
300  $lang->userTimeAndDate( $userRegistration, $displayUser ),
301  $lang->userDate( $userRegistration, $displayUser ),
302  $lang->userTime( $userRegistration, $displayUser )
303  )->parse(),
304  'section' => 'personal/info',
305  ];
306  }
307 
308  $canViewPrivateInfo = $user->isAllowed( 'viewmyprivateinfo' );
309  $canEditPrivateInfo = $user->isAllowed( 'editmyprivateinfo' );
310 
311  // Actually changeable stuff
312  $defaultPreferences['realname'] = [
313  // (not really "private", but still shouldn't be edited without permission)
314  'type' => $canEditPrivateInfo && $authManager->allowsPropertyChange( 'realname' )
315  ? 'text' : 'info',
316  'default' => $user->getRealName(),
317  'section' => 'personal/info',
318  'label-message' => 'yourrealname',
319  'help-message' => 'prefs-help-realname',
320  ];
321 
322  if ( $canEditPrivateInfo && $authManager->allowsAuthenticationDataChange(
323  new PasswordAuthenticationRequest(), false )->isGood()
324  ) {
325  $link = $linkRenderer->makeLink( SpecialPage::getTitleFor( 'ChangePassword' ),
326  $context->msg( 'prefs-resetpass' )->text(), [],
327  [ 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ] );
328 
329  $defaultPreferences['password'] = [
330  'type' => 'info',
331  'raw' => true,
332  'default' => $link,
333  'label-message' => 'yourpassword',
334  'section' => 'personal/info',
335  ];
336  }
337  // Only show prefershttps if secure login is turned on
338  if ( $config->get( 'SecureLogin' ) && wfCanIPUseHTTPS( $context->getRequest()->getIP() ) ) {
339  $defaultPreferences['prefershttps'] = [
340  'type' => 'toggle',
341  'label-message' => 'tog-prefershttps',
342  'help-message' => 'prefs-help-prefershttps',
343  'section' => 'personal/info'
344  ];
345  }
346 
347  // Language
349  $languageCode = $config->get( 'LanguageCode' );
350  if ( !array_key_exists( $languageCode, $languages ) ) {
351  $languages[$languageCode] = $languageCode;
352  }
353  ksort( $languages );
354 
355  $options = [];
356  foreach ( $languages as $code => $name ) {
357  $display = wfBCP47( $code ) . ' - ' . $name;
358  $options[$display] = $code;
359  }
360  $defaultPreferences['language'] = [
361  'type' => 'select',
362  'section' => 'personal/i18n',
363  'options' => $options,
364  'label-message' => 'yourlanguage',
365  ];
366 
367  $defaultPreferences['gender'] = [
368  'type' => 'radio',
369  'section' => 'personal/i18n',
370  'options' => [
371  $context->msg( 'parentheses' )
372  ->params( $context->msg( 'gender-unknown' )->plain() )
373  ->escaped() => 'unknown',
374  $context->msg( 'gender-female' )->escaped() => 'female',
375  $context->msg( 'gender-male' )->escaped() => 'male',
376  ],
377  'label-message' => 'yourgender',
378  'help-message' => 'prefs-help-gender',
379  ];
380 
381  // see if there are multiple language variants to choose from
382  if ( !$config->get( 'DisableLangConversion' ) ) {
383  foreach ( LanguageConverter::$languagesWithVariants as $langCode ) {
384  if ( $langCode == $wgContLang->getCode() ) {
385  $variants = $wgContLang->getVariants();
386 
387  if ( count( $variants ) <= 1 ) {
388  continue;
389  }
390 
391  $variantArray = [];
392  foreach ( $variants as $v ) {
393  $v = str_replace( '_', '-', strtolower( $v ) );
394  $variantArray[$v] = $lang->getVariantname( $v, false );
395  }
396 
397  $options = [];
398  foreach ( $variantArray as $code => $name ) {
399  $display = wfBCP47( $code ) . ' - ' . $name;
400  $options[$display] = $code;
401  }
402 
403  $defaultPreferences['variant'] = [
404  'label-message' => 'yourvariant',
405  'type' => 'select',
406  'options' => $options,
407  'section' => 'personal/i18n',
408  'help-message' => 'prefs-help-variant',
409  ];
410  } else {
411  $defaultPreferences["variant-$langCode"] = [
412  'type' => 'api',
413  ];
414  }
415  }
416  }
417 
418  // Stuff from Language::getExtraUserToggles()
419  // FIXME is this dead code? $extraUserToggles doesn't seem to be defined for any language
420  $toggles = $wgContLang->getExtraUserToggles();
421 
422  foreach ( $toggles as $toggle ) {
423  $defaultPreferences[$toggle] = [
424  'type' => 'toggle',
425  'section' => 'personal/i18n',
426  'label-message' => "tog-$toggle",
427  ];
428  }
429 
430  // show a preview of the old signature first
431  $oldsigWikiText = $wgParser->preSaveTransform(
432  '~~~',
433  $context->getTitle(),
434  $user,
436  );
437  $oldsigHTML = $context->getOutput()->parseInline( $oldsigWikiText, true, true );
438  $defaultPreferences['oldsig'] = [
439  'type' => 'info',
440  'raw' => true,
441  'label-message' => 'tog-oldsig',
442  'default' => $oldsigHTML,
443  'section' => 'personal/signature',
444  ];
445  $defaultPreferences['nickname'] = [
446  'type' => $authManager->allowsPropertyChange( 'nickname' ) ? 'text' : 'info',
447  'maxlength' => $config->get( 'MaxSigChars' ),
448  'label-message' => 'yournick',
449  'validation-callback' => [ 'Preferences', 'validateSignature' ],
450  'section' => 'personal/signature',
451  'filter-callback' => [ 'Preferences', 'cleanSignature' ],
452  ];
453  $defaultPreferences['fancysig'] = [
454  'type' => 'toggle',
455  'label-message' => 'tog-fancysig',
456  // show general help about signature at the bottom of the section
457  'help-message' => 'prefs-help-signature',
458  'section' => 'personal/signature'
459  ];
460 
461  # # Email stuff
462 
463  if ( $config->get( 'EnableEmail' ) ) {
464  if ( $canViewPrivateInfo ) {
465  $helpMessages[] = $config->get( 'EmailConfirmToEdit' )
466  ? 'prefs-help-email-required'
467  : 'prefs-help-email';
468 
469  if ( $config->get( 'EnableUserEmail' ) ) {
470  // additional messages when users can send email to each other
471  $helpMessages[] = 'prefs-help-email-others';
472  }
473 
474  $emailAddress = $user->getEmail() ? htmlspecialchars( $user->getEmail() ) : '';
475  if ( $canEditPrivateInfo && $authManager->allowsPropertyChange( 'emailaddress' ) ) {
476  $link = $linkRenderer->makeLink(
477  SpecialPage::getTitleFor( 'ChangeEmail' ),
478  $context->msg( $user->getEmail() ? 'prefs-changeemail' : 'prefs-setemail' )->text(),
479  [],
480  [ 'returnto' => SpecialPage::getTitleFor( 'Preferences' )->getPrefixedText() ] );
481 
482  $emailAddress .= $emailAddress == '' ? $link : (
483  $context->msg( 'word-separator' )->escaped()
484  . $context->msg( 'parentheses' )->rawParams( $link )->escaped()
485  );
486  }
487 
488  $defaultPreferences['emailaddress'] = [
489  'type' => 'info',
490  'raw' => true,
491  'default' => $emailAddress,
492  'label-message' => 'youremail',
493  'section' => 'personal/email',
494  'help-messages' => $helpMessages,
495  # 'cssclass' chosen below
496  ];
497  }
498 
499  $disableEmailPrefs = false;
500 
501  if ( $config->get( 'EmailAuthentication' ) ) {
502  $emailauthenticationclass = 'mw-email-not-authenticated';
503  if ( $user->getEmail() ) {
504  if ( $user->getEmailAuthenticationTimestamp() ) {
505  // date and time are separate parameters to facilitate localisation.
506  // $time is kept for backward compat reasons.
507  // 'emailauthenticated' is also used in SpecialConfirmemail.php
508  $displayUser = $context->getUser();
509  $emailTimestamp = $user->getEmailAuthenticationTimestamp();
510  $time = $lang->userTimeAndDate( $emailTimestamp, $displayUser );
511  $d = $lang->userDate( $emailTimestamp, $displayUser );
512  $t = $lang->userTime( $emailTimestamp, $displayUser );
513  $emailauthenticated = $context->msg( 'emailauthenticated',
514  $time, $d, $t )->parse() . '<br />';
515  $disableEmailPrefs = false;
516  $emailauthenticationclass = 'mw-email-authenticated';
517  } else {
518  $disableEmailPrefs = true;
519  $emailauthenticated = $context->msg( 'emailnotauthenticated' )->parse() . '<br />' .
520  $linkRenderer->makeKnownLink(
521  SpecialPage::getTitleFor( 'Confirmemail' ),
522  $context->msg( 'emailconfirmlink' )->text()
523  ) . '<br />';
524  $emailauthenticationclass = "mw-email-not-authenticated";
525  }
526  } else {
527  $disableEmailPrefs = true;
528  $emailauthenticated = $context->msg( 'noemailprefs' )->escaped();
529  $emailauthenticationclass = 'mw-email-none';
530  }
531 
532  if ( $canViewPrivateInfo ) {
533  $defaultPreferences['emailauthentication'] = [
534  'type' => 'info',
535  'raw' => true,
536  'section' => 'personal/email',
537  'label-message' => 'prefs-emailconfirm-label',
538  'default' => $emailauthenticated,
539  # Apply the same CSS class used on the input to the message:
540  'cssclass' => $emailauthenticationclass,
541  ];
542  }
543  }
544 
545  if ( $config->get( 'EnableUserEmail' ) && $user->isAllowed( 'sendemail' ) ) {
546  $defaultPreferences['disablemail'] = [
547  'type' => 'toggle',
548  'invert' => true,
549  'section' => 'personal/email',
550  'label-message' => 'allowemail',
551  'disabled' => $disableEmailPrefs,
552  ];
553  $defaultPreferences['ccmeonemails'] = [
554  'type' => 'toggle',
555  'section' => 'personal/email',
556  'label-message' => 'tog-ccmeonemails',
557  'disabled' => $disableEmailPrefs,
558  ];
559  }
560 
561  if ( $config->get( 'EnotifWatchlist' ) ) {
562  $defaultPreferences['enotifwatchlistpages'] = [
563  'type' => 'toggle',
564  'section' => 'personal/email',
565  'label-message' => 'tog-enotifwatchlistpages',
566  'disabled' => $disableEmailPrefs,
567  ];
568  }
569  if ( $config->get( 'EnotifUserTalk' ) ) {
570  $defaultPreferences['enotifusertalkpages'] = [
571  'type' => 'toggle',
572  'section' => 'personal/email',
573  'label-message' => 'tog-enotifusertalkpages',
574  'disabled' => $disableEmailPrefs,
575  ];
576  }
577  if ( $config->get( 'EnotifUserTalk' ) || $config->get( 'EnotifWatchlist' ) ) {
578  if ( $config->get( 'EnotifMinorEdits' ) ) {
579  $defaultPreferences['enotifminoredits'] = [
580  'type' => 'toggle',
581  'section' => 'personal/email',
582  'label-message' => 'tog-enotifminoredits',
583  'disabled' => $disableEmailPrefs,
584  ];
585  }
586 
587  if ( $config->get( 'EnotifRevealEditorAddress' ) ) {
588  $defaultPreferences['enotifrevealaddr'] = [
589  'type' => 'toggle',
590  'section' => 'personal/email',
591  'label-message' => 'tog-enotifrevealaddr',
592  'disabled' => $disableEmailPrefs,
593  ];
594  }
595  }
596  }
597  }
598 
606  # # Skin #####################################
607 
608  // Skin selector, if there is at least one valid skin
609  $skinOptions = self::generateSkinOptions( $user, $context );
610  if ( $skinOptions ) {
611  $defaultPreferences['skin'] = [
612  'type' => 'radio',
613  'options' => $skinOptions,
614  'label' => '&#160;',
615  'section' => 'rendering/skin',
616  ];
617  }
618 
619  $config = $context->getConfig();
620  $allowUserCss = $config->get( 'AllowUserCss' );
621  $allowUserJs = $config->get( 'AllowUserJs' );
622  # Create links to user CSS/JS pages for all skins
623  # This code is basically copied from generateSkinOptions(). It'd
624  # be nice to somehow merge this back in there to avoid redundancy.
625  if ( $allowUserCss || $allowUserJs ) {
626  $linkTools = [];
627  $userName = $user->getName();
628 
629  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
630  if ( $allowUserCss ) {
631  $cssPage = Title::makeTitleSafe( NS_USER, $userName . '/common.css' );
632  $linkTools[] = $linkRenderer->makeLink( $cssPage, $context->msg( 'prefs-custom-css' )->text() );
633  }
634 
635  if ( $allowUserJs ) {
636  $jsPage = Title::makeTitleSafe( NS_USER, $userName . '/common.js' );
637  $linkTools[] = $linkRenderer->makeLink( $jsPage, $context->msg( 'prefs-custom-js' )->text() );
638  }
639 
640  $defaultPreferences['commoncssjs'] = [
641  'type' => 'info',
642  'raw' => true,
643  'default' => $context->getLanguage()->pipeList( $linkTools ),
644  'label-message' => 'prefs-common-css-js',
645  'section' => 'rendering/skin',
646  ];
647  }
648  }
649 
656  # # Files #####################################
657  $defaultPreferences['imagesize'] = [
658  'type' => 'select',
659  'options' => self::getImageSizes( $context ),
660  'label-message' => 'imagemaxsize',
661  'section' => 'rendering/files',
662  ];
663  $defaultPreferences['thumbsize'] = [
664  'type' => 'select',
665  'options' => self::getThumbSizes( $context ),
666  'label-message' => 'thumbsize',
667  'section' => 'rendering/files',
668  ];
669  }
670 
678  # # Date and time #####################################
679  $dateOptions = self::getDateOptions( $context );
680  if ( $dateOptions ) {
681  $defaultPreferences['date'] = [
682  'type' => 'radio',
683  'options' => $dateOptions,
684  'label' => '&#160;',
685  'section' => 'rendering/dateformat',
686  ];
687  }
688 
689  // Info
690  $now = wfTimestampNow();
692  $nowlocal = Xml::element( 'span', [ 'id' => 'wpLocalTime' ],
693  $lang->userTime( $now, $user ) );
694  $nowserver = $lang->userTime( $now, $user,
695  [ 'format' => false, 'timecorrection' => false ] ) .
696  Html::hidden( 'wpServerTime', (int)substr( $now, 8, 2 ) * 60 + (int)substr( $now, 10, 2 ) );
697 
698  $defaultPreferences['nowserver'] = [
699  'type' => 'info',
700  'raw' => 1,
701  'label-message' => 'servertime',
702  'default' => $nowserver,
703  'section' => 'rendering/timeoffset',
704  ];
705 
706  $defaultPreferences['nowlocal'] = [
707  'type' => 'info',
708  'raw' => 1,
709  'label-message' => 'localtime',
710  'default' => $nowlocal,
711  'section' => 'rendering/timeoffset',
712  ];
713 
714  // Grab existing pref.
715  $tzOffset = $user->getOption( 'timecorrection' );
716  $tz = explode( '|', $tzOffset, 3 );
717 
718  $tzOptions = self::getTimezoneOptions( $context );
719 
720  $tzSetting = $tzOffset;
721  if ( count( $tz ) > 1 && $tz[0] == 'ZoneInfo' &&
722  !in_array( $tzOffset, HTMLFormField::flattenOptions( $tzOptions ) )
723  ) {
724  // Timezone offset can vary with DST
725  try {
726  $userTZ = new DateTimeZone( $tz[2] );
727  $minDiff = floor( $userTZ->getOffset( new DateTime( 'now' ) ) / 60 );
728  $tzSetting = "ZoneInfo|$minDiff|{$tz[2]}";
729  } catch ( Exception $e ) {
730  // User has an invalid time zone set. Fall back to just using the offset
731  $tz[0] = 'Offset';
732  }
733  }
734  if ( count( $tz ) > 1 && $tz[0] == 'Offset' ) {
735  $minDiff = $tz[1];
736  $tzSetting = sprintf( '%+03d:%02d', floor( $minDiff / 60 ), abs( $minDiff ) % 60 );
737  }
738 
739  $defaultPreferences['timecorrection'] = [
740  'class' => 'HTMLSelectOrOtherField',
741  'label-message' => 'timezonelegend',
742  'options' => $tzOptions,
743  'default' => $tzSetting,
744  'size' => 20,
745  'section' => 'rendering/timeoffset',
746  ];
747  }
748 
755  # # Diffs ####################################
756  $defaultPreferences['diffonly'] = [
757  'type' => 'toggle',
758  'section' => 'rendering/diffs',
759  'label-message' => 'tog-diffonly',
760  ];
761  $defaultPreferences['norollbackdiff'] = [
762  'type' => 'toggle',
763  'section' => 'rendering/diffs',
764  'label-message' => 'tog-norollbackdiff',
765  ];
766 
767  # # Page Rendering ##############################
768  if ( $context->getConfig()->get( 'AllowUserCssPrefs' ) ) {
769  $defaultPreferences['underline'] = [
770  'type' => 'select',
771  'options' => [
772  $context->msg( 'underline-never' )->text() => 0,
773  $context->msg( 'underline-always' )->text() => 1,
774  $context->msg( 'underline-default' )->text() => 2,
775  ],
776  'label-message' => 'tog-underline',
777  'section' => 'rendering/advancedrendering',
778  ];
779  }
780 
781  $stubThresholdValues = [ 50, 100, 500, 1000, 2000, 5000, 10000 ];
782  $stubThresholdOptions = [ $context->msg( 'stub-threshold-disabled' )->text() => 0 ];
783  foreach ( $stubThresholdValues as $value ) {
784  $stubThresholdOptions[$context->msg( 'size-bytes', $value )->text()] = $value;
785  }
786 
787  $defaultPreferences['stubthreshold'] = [
788  'type' => 'select',
789  'section' => 'rendering/advancedrendering',
790  'options' => $stubThresholdOptions,
791  // This is not a raw HTML message; label-raw is needed for the manual <a></a>
792  'label-raw' => $context->msg( 'stub-threshold' )->rawParams(
793  '<a href="#" class="stub">' .
794  $context->msg( 'stub-threshold-sample-link' )->parse() .
795  '</a>' )->parse(),
796  ];
797 
798  $defaultPreferences['showhiddencats'] = [
799  'type' => 'toggle',
800  'section' => 'rendering/advancedrendering',
801  'label-message' => 'tog-showhiddencats'
802  ];
803 
804  $defaultPreferences['numberheadings'] = [
805  'type' => 'toggle',
806  'section' => 'rendering/advancedrendering',
807  'label-message' => 'tog-numberheadings',
808  ];
809  }
810 
817  # # Editing #####################################
818  $defaultPreferences['editsectiononrightclick'] = [
819  'type' => 'toggle',
820  'section' => 'editing/advancedediting',
821  'label-message' => 'tog-editsectiononrightclick',
822  ];
823  $defaultPreferences['editondblclick'] = [
824  'type' => 'toggle',
825  'section' => 'editing/advancedediting',
826  'label-message' => 'tog-editondblclick',
827  ];
828 
829  if ( $context->getConfig()->get( 'AllowUserCssPrefs' ) ) {
830  $defaultPreferences['editfont'] = [
831  'type' => 'select',
832  'section' => 'editing/editor',
833  'label-message' => 'editfont-style',
834  'options' => [
835  $context->msg( 'editfont-default' )->text() => 'default',
836  $context->msg( 'editfont-monospace' )->text() => 'monospace',
837  $context->msg( 'editfont-sansserif' )->text() => 'sans-serif',
838  $context->msg( 'editfont-serif' )->text() => 'serif',
839  ]
840  ];
841  }
842 
843  if ( $user->isAllowed( 'minoredit' ) ) {
844  $defaultPreferences['minordefault'] = [
845  'type' => 'toggle',
846  'section' => 'editing/editor',
847  'label-message' => 'tog-minordefault',
848  ];
849  }
850 
851  $defaultPreferences['forceeditsummary'] = [
852  'type' => 'toggle',
853  'section' => 'editing/editor',
854  'label-message' => 'tog-forceeditsummary',
855  ];
856  $defaultPreferences['useeditwarning'] = [
857  'type' => 'toggle',
858  'section' => 'editing/editor',
859  'label-message' => 'tog-useeditwarning',
860  ];
861  $defaultPreferences['showtoolbar'] = [
862  'type' => 'toggle',
863  'section' => 'editing/editor',
864  'label-message' => 'tog-showtoolbar',
865  ];
866 
867  $defaultPreferences['previewonfirst'] = [
868  'type' => 'toggle',
869  'section' => 'editing/preview',
870  'label-message' => 'tog-previewonfirst',
871  ];
872  $defaultPreferences['previewontop'] = [
873  'type' => 'toggle',
874  'section' => 'editing/preview',
875  'label-message' => 'tog-previewontop',
876  ];
877  $defaultPreferences['uselivepreview'] = [
878  'type' => 'toggle',
879  'section' => 'editing/preview',
880  'label-message' => 'tog-uselivepreview',
881  ];
882  }
883 
890  $config = $context->getConfig();
891  $rcMaxAge = $config->get( 'RCMaxAge' );
892  # # RecentChanges #####################################
893  $defaultPreferences['rcdays'] = [
894  'type' => 'float',
895  'label-message' => 'recentchangesdays',
896  'section' => 'rc/displayrc',
897  'min' => 1,
898  'max' => ceil( $rcMaxAge / ( 3600 * 24 ) ),
899  'help' => $context->msg( 'recentchangesdays-max' )->numParams(
900  ceil( $rcMaxAge / ( 3600 * 24 ) ) )->escaped()
901  ];
902  $defaultPreferences['rclimit'] = [
903  'type' => 'int',
904  'label-message' => 'recentchangescount',
905  'help-message' => 'prefs-help-recentchangescount',
906  'section' => 'rc/displayrc',
907  ];
908  $defaultPreferences['usenewrc'] = [
909  'type' => 'toggle',
910  'label-message' => 'tog-usenewrc',
911  'section' => 'rc/advancedrc',
912  ];
913  $defaultPreferences['hideminor'] = [
914  'type' => 'toggle',
915  'label-message' => 'tog-hideminor',
916  'section' => 'rc/advancedrc',
917  ];
918 
919  if ( $config->get( 'RCWatchCategoryMembership' ) ) {
920  $defaultPreferences['hidecategorization'] = [
921  'type' => 'toggle',
922  'label-message' => 'tog-hidecategorization',
923  'section' => 'rc/advancedrc',
924  ];
925  }
926 
927  if ( $user->useRCPatrol() ) {
928  $defaultPreferences['hidepatrolled'] = [
929  'type' => 'toggle',
930  'section' => 'rc/advancedrc',
931  'label-message' => 'tog-hidepatrolled',
932  ];
933  }
934 
935  if ( $user->useNPPatrol() ) {
936  $defaultPreferences['newpageshidepatrolled'] = [
937  'type' => 'toggle',
938  'section' => 'rc/advancedrc',
939  'label-message' => 'tog-newpageshidepatrolled',
940  ];
941  }
942 
943  if ( $config->get( 'RCShowWatchingUsers' ) ) {
944  $defaultPreferences['shownumberswatching'] = [
945  'type' => 'toggle',
946  'section' => 'rc/advancedrc',
947  'label-message' => 'tog-shownumberswatching',
948  ];
949  }
950  }
951 
958  $config = $context->getConfig();
959  $watchlistdaysMax = ceil( $config->get( 'RCMaxAge' ) / ( 3600 * 24 ) );
960 
961  # # Watchlist #####################################
962  if ( $user->isAllowed( 'editmywatchlist' ) ) {
963  $editWatchlistLinks = [];
964  $editWatchlistModes = [
965  'edit' => [ 'EditWatchlist', false ],
966  'raw' => [ 'EditWatchlist', 'raw' ],
967  'clear' => [ 'EditWatchlist', 'clear' ],
968  ];
969  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
970  foreach ( $editWatchlistModes as $editWatchlistMode => $mode ) {
971  // Messages: prefs-editwatchlist-edit, prefs-editwatchlist-raw, prefs-editwatchlist-clear
972  $editWatchlistLinks[] = $linkRenderer->makeKnownLink(
973  SpecialPage::getTitleFor( $mode[0], $mode[1] ),
974  new HtmlArmor( $context->msg( "prefs-editwatchlist-{$editWatchlistMode}" )->parse() )
975  );
976  }
977 
978  $defaultPreferences['editwatchlist'] = [
979  'type' => 'info',
980  'raw' => true,
981  'default' => $context->getLanguage()->pipeList( $editWatchlistLinks ),
982  'label-message' => 'prefs-editwatchlist-label',
983  'section' => 'watchlist/editwatchlist',
984  ];
985  }
986 
987  $defaultPreferences['watchlistdays'] = [
988  'type' => 'float',
989  'min' => 0,
990  'max' => $watchlistdaysMax,
991  'section' => 'watchlist/displaywatchlist',
992  'help' => $context->msg( 'prefs-watchlist-days-max' )->numParams(
993  $watchlistdaysMax )->escaped(),
994  'label-message' => 'prefs-watchlist-days',
995  ];
996  $defaultPreferences['wllimit'] = [
997  'type' => 'int',
998  'min' => 0,
999  'max' => 1000,
1000  'label-message' => 'prefs-watchlist-edits',
1001  'help' => $context->msg( 'prefs-watchlist-edits-max' )->escaped(),
1002  'section' => 'watchlist/displaywatchlist',
1003  ];
1004  $defaultPreferences['extendwatchlist'] = [
1005  'type' => 'toggle',
1006  'section' => 'watchlist/advancedwatchlist',
1007  'label-message' => 'tog-extendwatchlist',
1008  ];
1009  $defaultPreferences['watchlisthideminor'] = [
1010  'type' => 'toggle',
1011  'section' => 'watchlist/advancedwatchlist',
1012  'label-message' => 'tog-watchlisthideminor',
1013  ];
1014  $defaultPreferences['watchlisthidebots'] = [
1015  'type' => 'toggle',
1016  'section' => 'watchlist/advancedwatchlist',
1017  'label-message' => 'tog-watchlisthidebots',
1018  ];
1019  $defaultPreferences['watchlisthideown'] = [
1020  'type' => 'toggle',
1021  'section' => 'watchlist/advancedwatchlist',
1022  'label-message' => 'tog-watchlisthideown',
1023  ];
1024  $defaultPreferences['watchlisthideanons'] = [
1025  'type' => 'toggle',
1026  'section' => 'watchlist/advancedwatchlist',
1027  'label-message' => 'tog-watchlisthideanons',
1028  ];
1029  $defaultPreferences['watchlisthideliu'] = [
1030  'type' => 'toggle',
1031  'section' => 'watchlist/advancedwatchlist',
1032  'label-message' => 'tog-watchlisthideliu',
1033  ];
1034  $defaultPreferences['watchlistreloadautomatically'] = [
1035  'type' => 'toggle',
1036  'section' => 'watchlist/advancedwatchlist',
1037  'label-message' => 'tog-watchlistreloadautomatically',
1038  ];
1039 
1040  if ( $config->get( 'RCWatchCategoryMembership' ) ) {
1041  $defaultPreferences['watchlisthidecategorization'] = [
1042  'type' => 'toggle',
1043  'section' => 'watchlist/advancedwatchlist',
1044  'label-message' => 'tog-watchlisthidecategorization',
1045  ];
1046  }
1047 
1048  if ( $user->useRCPatrol() ) {
1049  $defaultPreferences['watchlisthidepatrolled'] = [
1050  'type' => 'toggle',
1051  'section' => 'watchlist/advancedwatchlist',
1052  'label-message' => 'tog-watchlisthidepatrolled',
1053  ];
1054  }
1055 
1056  $watchTypes = [
1057  'edit' => 'watchdefault',
1058  'move' => 'watchmoves',
1059  'delete' => 'watchdeletion'
1060  ];
1061 
1062  // Kinda hacky
1063  if ( $user->isAllowed( 'createpage' ) || $user->isAllowed( 'createtalk' ) ) {
1064  $watchTypes['read'] = 'watchcreations';
1065  }
1066 
1067  if ( $user->isAllowed( 'rollback' ) ) {
1068  $watchTypes['rollback'] = 'watchrollback';
1069  }
1070 
1071  if ( $user->isAllowed( 'upload' ) ) {
1072  $watchTypes['upload'] = 'watchuploads';
1073  }
1074 
1075  foreach ( $watchTypes as $action => $pref ) {
1076  if ( $user->isAllowed( $action ) ) {
1077  // Messages:
1078  // tog-watchdefault, tog-watchmoves, tog-watchdeletion, tog-watchcreations, tog-watchuploads
1079  // tog-watchrollback
1080  $defaultPreferences[$pref] = [
1081  'type' => 'toggle',
1082  'section' => 'watchlist/advancedwatchlist',
1083  'label-message' => "tog-$pref",
1084  ];
1085  }
1086  }
1087 
1088  if ( $config->get( 'EnableAPI' ) ) {
1089  $defaultPreferences['watchlisttoken'] = [
1090  'type' => 'api',
1091  ];
1092  $defaultPreferences['watchlisttoken-info'] = [
1093  'type' => 'info',
1094  'section' => 'watchlist/tokenwatchlist',
1095  'label-message' => 'prefs-watchlist-token',
1096  'default' => $user->getTokenFromOption( 'watchlisttoken' ),
1097  'help-message' => 'prefs-help-watchlist-token2',
1098  ];
1099  }
1100  }
1101 
1108  foreach ( MWNamespace::getValidNamespaces() as $n ) {
1109  $defaultPreferences['searchNs' . $n] = [
1110  'type' => 'api',
1111  ];
1112  }
1113  }
1114 
1119  }
1120 
1127  $ret = [];
1128 
1129  $mptitle = Title::newMainPage();
1130  $previewtext = $context->msg( 'skin-preview' )->escaped();
1131 
1132  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
1133 
1134  # Only show skins that aren't disabled in $wgSkipSkins
1135  $validSkinNames = Skin::getAllowedSkins();
1136 
1137  # Sort by UI skin name. First though need to update validSkinNames as sometimes
1138  # the skinkey & UI skinname differ (e.g. "standard" skinkey is "Classic" in the UI).
1139  foreach ( $validSkinNames as $skinkey => &$skinname ) {
1140  $msg = $context->msg( "skinname-{$skinkey}" );
1141  if ( $msg->exists() ) {
1142  $skinname = htmlspecialchars( $msg->text() );
1143  }
1144  }
1145  asort( $validSkinNames );
1146 
1147  $config = $context->getConfig();
1148  $defaultSkin = $config->get( 'DefaultSkin' );
1149  $allowUserCss = $config->get( 'AllowUserCss' );
1150  $allowUserJs = $config->get( 'AllowUserJs' );
1151 
1152  $foundDefault = false;
1153  foreach ( $validSkinNames as $skinkey => $sn ) {
1154  $linkTools = [];
1155 
1156  # Mark the default skin
1157  if ( strcasecmp( $skinkey, $defaultSkin ) === 0 ) {
1158  $linkTools[] = $context->msg( 'default' )->escaped();
1159  $foundDefault = true;
1160  }
1161 
1162  # Create preview link
1163  $mplink = htmlspecialchars( $mptitle->getLocalURL( [ 'useskin' => $skinkey ] ) );
1164  $linkTools[] = "<a target='_blank' href=\"$mplink\">$previewtext</a>";
1165 
1166  # Create links to user CSS/JS pages
1167  if ( $allowUserCss ) {
1168  $cssPage = Title::makeTitleSafe( NS_USER, $user->getName() . '/' . $skinkey . '.css' );
1169  $linkTools[] = $linkRenderer->makeLink( $cssPage, $context->msg( 'prefs-custom-css' )->text() );
1170  }
1171 
1172  if ( $allowUserJs ) {
1173  $jsPage = Title::makeTitleSafe( NS_USER, $user->getName() . '/' . $skinkey . '.js' );
1174  $linkTools[] = $linkRenderer->makeLink( $jsPage, $context->msg( 'prefs-custom-js' )->text() );
1175  }
1176 
1177  $display = $sn . ' ' . $context->msg( 'parentheses' )
1178  ->rawParams( $context->getLanguage()->pipeList( $linkTools ) )
1179  ->escaped();
1180  $ret[$display] = $skinkey;
1181  }
1182 
1183  if ( !$foundDefault ) {
1184  // If the default skin is not available, things are going to break horribly because the
1185  // default value for skin selector will not be a valid value. Let's just not show it then.
1186  return [];
1187  }
1188 
1189  return $ret;
1190  }
1191 
1197  $lang = $context->getLanguage();
1198  $dateopts = $lang->getDatePreferences();
1199 
1200  $ret = [];
1201 
1202  if ( $dateopts ) {
1203  if ( !in_array( 'default', $dateopts ) ) {
1204  $dateopts[] = 'default'; // Make sure default is always valid T21237
1205  }
1206 
1207  // FIXME KLUGE: site default might not be valid for user language
1209  if ( !in_array( $wgDefaultUserOptions['date'], $dateopts ) ) {
1210  $wgDefaultUserOptions['date'] = 'default';
1211  }
1212 
1213  $epoch = wfTimestampNow();
1214  foreach ( $dateopts as $key ) {
1215  if ( $key == 'default' ) {
1216  $formatted = $context->msg( 'datedefault' )->escaped();
1217  } else {
1218  $formatted = htmlspecialchars( $lang->timeanddate( $epoch, false, $key ) );
1219  }
1220  $ret[$formatted] = $key;
1221  }
1222  }
1223  return $ret;
1224  }
1225 
1231  $ret = [];
1232  $pixels = $context->msg( 'unit-pixel' )->text();
1233 
1234  foreach ( $context->getConfig()->get( 'ImageLimits' ) as $index => $limits ) {
1235  // Note: A left-to-right marker (\u200e) is inserted, see T144386
1236  $display = "{$limits[0]}" . json_decode( '"\u200e"' ) . "×{$limits[1]}" . $pixels;
1237  $ret[$display] = $index;
1238  }
1239 
1240  return $ret;
1241  }
1242 
1248  $ret = [];
1249  $pixels = $context->msg( 'unit-pixel' )->text();
1250 
1251  foreach ( $context->getConfig()->get( 'ThumbLimits' ) as $index => $size ) {
1252  $display = $size . $pixels;
1253  $ret[$display] = $index;
1254  }
1255 
1256  return $ret;
1257  }
1258 
1265  static function validateSignature( $signature, $alldata, $form ) {
1266  global $wgParser;
1267  $maxSigChars = $form->getConfig()->get( 'MaxSigChars' );
1268  if ( mb_strlen( $signature ) > $maxSigChars ) {
1269  return Xml::element( 'span', [ 'class' => 'error' ],
1270  $form->msg( 'badsiglength' )->numParams( $maxSigChars )->text() );
1271  } elseif ( isset( $alldata['fancysig'] ) &&
1272  $alldata['fancysig'] &&
1273  $wgParser->validateSig( $signature ) === false
1274  ) {
1275  return Xml::element(
1276  'span',
1277  [ 'class' => 'error' ],
1278  $form->msg( 'badsig' )->text()
1279  );
1280  } else {
1281  return true;
1282  }
1283  }
1284 
1291  static function cleanSignature( $signature, $alldata, $form ) {
1292  if ( isset( $alldata['fancysig'] ) && $alldata['fancysig'] ) {
1293  global $wgParser;
1294  $signature = $wgParser->cleanSig( $signature );
1295  } else {
1296  // When no fancy sig used, make sure ~{3,5} get removed.
1297  $signature = Parser::cleanSigInSig( $signature );
1298  }
1299 
1300  return $signature;
1301  }
1302 
1310  static function getFormObject(
1311  $user,
1313  $formClass = 'PreferencesForm',
1314  array $remove = []
1315  ) {
1316  $formDescriptor = Preferences::getPreferences( $user, $context );
1317  if ( count( $remove ) ) {
1318  $removeKeys = array_flip( $remove );
1319  $formDescriptor = array_diff_key( $formDescriptor, $removeKeys );
1320  }
1321 
1322  // Remove type=api preferences. They are not intended for rendering in the form.
1323  foreach ( $formDescriptor as $name => $info ) {
1324  if ( isset( $info['type'] ) && $info['type'] === 'api' ) {
1325  unset( $formDescriptor[$name] );
1326  }
1327  }
1328 
1332  $htmlForm = new $formClass( $formDescriptor, $context, 'prefs' );
1333 
1334  $htmlForm->setModifiedUser( $user );
1335  $htmlForm->setId( 'mw-prefs-form' );
1336  $htmlForm->setAutocomplete( 'off' );
1337  $htmlForm->setSubmitText( $context->msg( 'saveprefs' )->text() );
1338  # Used message keys: 'accesskey-preferences-save', 'tooltip-preferences-save'
1339  $htmlForm->setSubmitTooltip( 'preferences-save' );
1340  $htmlForm->setSubmitID( 'prefsubmit' );
1341  $htmlForm->setSubmitCallback( [ 'Preferences', 'tryFormSubmit' ] );
1342 
1343  return $htmlForm;
1344  }
1345 
1351  $opt = [];
1352 
1353  $localTZoffset = $context->getConfig()->get( 'LocalTZoffset' );
1354  $timeZoneList = self::getTimeZoneList( $context->getLanguage() );
1355 
1356  $timestamp = MWTimestamp::getLocalInstance();
1357  // Check that the LocalTZoffset is the same as the local time zone offset
1358  if ( $localTZoffset == $timestamp->format( 'Z' ) / 60 ) {
1359  $timezoneName = $timestamp->getTimezone()->getName();
1360  // Localize timezone
1361  if ( isset( $timeZoneList[$timezoneName] ) ) {
1362  $timezoneName = $timeZoneList[$timezoneName]['name'];
1363  }
1364  $server_tz_msg = $context->msg(
1365  'timezoneuseserverdefault',
1366  $timezoneName
1367  )->text();
1368  } else {
1369  $tzstring = sprintf(
1370  '%+03d:%02d',
1371  floor( $localTZoffset / 60 ),
1372  abs( $localTZoffset ) % 60
1373  );
1374  $server_tz_msg = $context->msg( 'timezoneuseserverdefault', $tzstring )->text();
1375  }
1376  $opt[$server_tz_msg] = "System|$localTZoffset";
1377  $opt[$context->msg( 'timezoneuseoffset' )->text()] = 'other';
1378  $opt[$context->msg( 'guesstimezone' )->text()] = 'guess';
1379 
1380  foreach ( $timeZoneList as $timeZoneInfo ) {
1381  $region = $timeZoneInfo['region'];
1382  if ( !isset( $opt[$region] ) ) {
1383  $opt[$region] = [];
1384  }
1385  $opt[$region][$timeZoneInfo['name']] = $timeZoneInfo['timecorrection'];
1386  }
1387  return $opt;
1388  }
1389 
1395  static function filterIntval( $value, $alldata ) {
1396  return intval( $value );
1397  }
1398 
1404  static function filterTimezoneInput( $tz, $alldata ) {
1405  $data = explode( '|', $tz, 3 );
1406  switch ( $data[0] ) {
1407  case 'ZoneInfo':
1408  $valid = false;
1409 
1410  if ( count( $data ) === 3 ) {
1411  // Make sure this timezone exists
1412  try {
1413  new DateTimeZone( $data[2] );
1414  // If the constructor didn't throw, we know it's valid
1415  $valid = true;
1416  } catch ( Exception $e ) {
1417  // Not a valid timezone
1418  }
1419  }
1420 
1421  if ( !$valid ) {
1422  // If the supplied timezone doesn't exist, fall back to the encoded offset
1423  return 'Offset|' . intval( $tz[1] );
1424  }
1425  return $tz;
1426  case 'System':
1427  return $tz;
1428  default:
1429  $data = explode( ':', $tz, 2 );
1430  if ( count( $data ) == 2 ) {
1431  $data[0] = intval( $data[0] );
1432  $data[1] = intval( $data[1] );
1433  $minDiff = abs( $data[0] ) * 60 + $data[1];
1434  if ( $data[0] < 0 ) {
1435  $minDiff = - $minDiff;
1436  }
1437  } else {
1438  $minDiff = intval( $data[0] ) * 60;
1439  }
1440 
1441  # Max is +14:00 and min is -12:00, see:
1442  # https://en.wikipedia.org/wiki/Timezone
1443  $minDiff = min( $minDiff, 840 ); # 14:00
1444  $minDiff = max( $minDiff, -720 ); # -12:00
1445  return 'Offset|' . $minDiff;
1446  }
1447  }
1448 
1456  static function tryFormSubmit( $formData, $form ) {
1457  $user = $form->getModifiedUser();
1458  $hiddenPrefs = $form->getConfig()->get( 'HiddenPrefs' );
1459  $result = true;
1460 
1461  if ( !$user->isAllowedAny( 'editmyprivateinfo', 'editmyoptions' ) ) {
1462  return Status::newFatal( 'mypreferencesprotected' );
1463  }
1464 
1465  // Filter input
1466  foreach ( array_keys( $formData ) as $name ) {
1467  if ( isset( self::$saveFilters[$name] ) ) {
1468  $formData[$name] =
1469  call_user_func( self::$saveFilters[$name], $formData[$name], $formData );
1470  }
1471  }
1472 
1473  // Fortunately, the realname field is MUCH simpler
1474  // (not really "private", but still shouldn't be edited without permission)
1475 
1476  if ( !in_array( 'realname', $hiddenPrefs )
1477  && $user->isAllowed( 'editmyprivateinfo' )
1478  && array_key_exists( 'realname', $formData )
1479  ) {
1480  $realName = $formData['realname'];
1481  $user->setRealName( $realName );
1482  }
1483 
1484  if ( $user->isAllowed( 'editmyoptions' ) ) {
1485  foreach ( self::$saveBlacklist as $b ) {
1486  unset( $formData[$b] );
1487  }
1488 
1489  # If users have saved a value for a preference which has subsequently been disabled
1490  # via $wgHiddenPrefs, we don't want to destroy that setting in case the preference
1491  # is subsequently re-enabled
1492  foreach ( $hiddenPrefs as $pref ) {
1493  # If the user has not set a non-default value here, the default will be returned
1494  # and subsequently discarded
1495  $formData[$pref] = $user->getOption( $pref, null, true );
1496  }
1497 
1498  // Keep old preferences from interfering due to back-compat code, etc.
1499  $user->resetOptions( 'unused', $form->getContext() );
1500 
1501  foreach ( $formData as $key => $value ) {
1502  $user->setOption( $key, $value );
1503  }
1504 
1505  Hooks::run( 'PreferencesFormPreSave', [ $formData, $form, $user, &$result ] );
1506  }
1507 
1508  MediaWiki\Auth\AuthManager::callLegacyAuthPlugin( 'updateExternalDB', [ $user ] );
1509  $user->saveSettings();
1510 
1511  return $result;
1512  }
1513 
1519  public static function tryUISubmit( $formData, $form ) {
1520  $res = self::tryFormSubmit( $formData, $form );
1521 
1522  if ( $res ) {
1523  $urlOptions = [];
1524 
1525  if ( $res === 'eauth' ) {
1526  $urlOptions['eauth'] = 1;
1527  }
1528 
1529  $urlOptions += $form->getExtraSuccessRedirectParameters();
1530 
1531  $url = $form->getTitle()->getFullURL( $urlOptions );
1532 
1533  $context = $form->getContext();
1534  // Set session data for the success message
1535  $context->getRequest()->getSession()->set( 'specialPreferencesSaveSuccess', 1 );
1536 
1537  $context->getOutput()->redirect( $url );
1538  }
1539 
1540  return Status::newGood();
1541  }
1542 
1551  public static function getTimeZoneList( Language $language ) {
1552  $identifiers = DateTimeZone::listIdentifiers();
1553  if ( $identifiers === false ) {
1554  return [];
1555  }
1556  sort( $identifiers );
1557 
1558  $tzRegions = [
1559  'Africa' => wfMessage( 'timezoneregion-africa' )->inLanguage( $language )->text(),
1560  'America' => wfMessage( 'timezoneregion-america' )->inLanguage( $language )->text(),
1561  'Antarctica' => wfMessage( 'timezoneregion-antarctica' )->inLanguage( $language )->text(),
1562  'Arctic' => wfMessage( 'timezoneregion-arctic' )->inLanguage( $language )->text(),
1563  'Asia' => wfMessage( 'timezoneregion-asia' )->inLanguage( $language )->text(),
1564  'Atlantic' => wfMessage( 'timezoneregion-atlantic' )->inLanguage( $language )->text(),
1565  'Australia' => wfMessage( 'timezoneregion-australia' )->inLanguage( $language )->text(),
1566  'Europe' => wfMessage( 'timezoneregion-europe' )->inLanguage( $language )->text(),
1567  'Indian' => wfMessage( 'timezoneregion-indian' )->inLanguage( $language )->text(),
1568  'Pacific' => wfMessage( 'timezoneregion-pacific' )->inLanguage( $language )->text(),
1569  ];
1570  asort( $tzRegions );
1571 
1572  $timeZoneList = [];
1573 
1574  $now = new DateTime();
1575 
1576  foreach ( $identifiers as $identifier ) {
1577  $parts = explode( '/', $identifier, 2 );
1578 
1579  // DateTimeZone::listIdentifiers() returns a number of
1580  // backwards-compatibility entries. This filters them out of the
1581  // list presented to the user.
1582  if ( count( $parts ) !== 2 || !array_key_exists( $parts[0], $tzRegions ) ) {
1583  continue;
1584  }
1585 
1586  // Localize region
1587  $parts[0] = $tzRegions[$parts[0]];
1588 
1589  $dateTimeZone = new DateTimeZone( $identifier );
1590  $minDiff = floor( $dateTimeZone->getOffset( $now ) / 60 );
1591 
1592  $display = str_replace( '_', ' ', $parts[0] . '/' . $parts[1] );
1593  $value = "ZoneInfo|$minDiff|$identifier";
1594 
1595  $timeZoneList[$identifier] = [
1596  'name' => $display,
1597  'timecorrection' => $value,
1598  'region' => $parts[0],
1599  ];
1600  }
1601 
1602  return $timeZoneList;
1603  }
1604 }
1605 
1607 class PreferencesForm extends HTMLForm {
1608  // Override default value from HTMLForm
1609  protected $mSubSectionBeforeFields = false;
1610 
1611  private $modifiedUser;
1612 
1616  public function setModifiedUser( $user ) {
1617  $this->modifiedUser = $user;
1618  }
1619 
1623  public function getModifiedUser() {
1624  if ( $this->modifiedUser === null ) {
1625  return $this->getUser();
1626  } else {
1627  return $this->modifiedUser;
1628  }
1629  }
1630 
1638  return [];
1639  }
1640 
1645  function wrapForm( $html ) {
1646  $html = Xml::tags( 'div', [ 'id' => 'preferences' ], $html );
1647 
1648  return parent::wrapForm( $html );
1649  }
1650 
1654  function getButtons() {
1655  $attrs = [ 'id' => 'mw-prefs-restoreprefs' ];
1656 
1657  if ( !$this->getModifiedUser()->isAllowedAny( 'editmyprivateinfo', 'editmyoptions' ) ) {
1658  return '';
1659  }
1660 
1661  $html = parent::getButtons();
1662 
1663  if ( $this->getModifiedUser()->isAllowed( 'editmyoptions' ) ) {
1664  $t = SpecialPage::getTitleFor( 'Preferences', 'reset' );
1665 
1666  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
1667  $html .= "\n" . $linkRenderer->makeLink( $t, $this->msg( 'restoreprefs' )->text(),
1668  Html::buttonAttributes( $attrs, [ 'mw-ui-quiet' ] ) );
1669 
1670  $html = Xml::tags( 'div', [ 'class' => 'mw-prefs-buttons' ], $html );
1671  }
1672 
1673  return $html;
1674  }
1675 
1682  function filterDataForSubmit( $data ) {
1683  foreach ( $this->mFlatFields as $fieldname => $field ) {
1684  if ( $field instanceof HTMLNestedFilterable ) {
1685  $info = $field->mParams;
1686  $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $fieldname;
1687  foreach ( $field->filterDataForSubmit( $data[$fieldname] ) as $key => $value ) {
1688  $data["$prefix$key"] = $value;
1689  }
1690  unset( $data[$fieldname] );
1691  }
1692  }
1693 
1694  return $data;
1695  }
1696 
1701  function getBody() {
1702  return $this->displaySection( $this->mFieldTree, '', 'mw-prefsection-' );
1703  }
1704 
1711  function getLegend( $key ) {
1712  $legend = parent::getLegend( $key );
1713  Hooks::run( 'PreferencesGetLegend', [ $this, $key, &$legend ] );
1714  return $legend;
1715  }
1716 
1722  return array_keys( array_filter( $this->mFieldTree, 'is_array' ) );
1723  }
1724 }
Preferences\getPreferences
static getPreferences( $user, IContextSource $context)
Definition: Preferences.php:82
ContextSource\getConfig
getConfig()
Get the Config object.
Definition: ContextSource.php:68
Preferences\getThumbSizes
static getThumbSizes(IContextSource $context)
Definition: Preferences.php:1247
$context
error also a ContextSource you ll probably need to make sure the header is varied on and they can depend only on the ResourceLoaderContext $context
Definition: hooks.txt:2612
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:41
Preferences\filterTimezoneInput
static filterTimezoneInput( $tz, $alldata)
Definition: Preferences.php:1404
HtmlArmor
Marks HTML that shouldn't be escaped.
Definition: HtmlArmor.php:28
PreferencesForm\getPreferenceSections
getPreferenceSections()
Get the keys of each top level preference section.
Definition: Preferences.php:1721
wfBCP47
wfBCP47( $code)
Get the normalised IETF language tag See unit test for examples.
Definition: GlobalFunctions.php:3370
wfCanIPUseHTTPS
wfCanIPUseHTTPS( $ip)
Determine whether the client at a given source IP is likely to be able to access the wiki via HTTPS.
Definition: GlobalFunctions.php:3564
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:189
MWNamespace\getValidNamespaces
static getValidNamespaces()
Returns an array of the namespaces (by integer id) that exist on the wiki.
Definition: MWNamespace.php:264
Preferences\rcPreferences
static rcPreferences( $user, IContextSource $context, &$defaultPreferences)
Definition: Preferences.php:889
$wgParser
$wgParser
Definition: Setup.php:796
ContextSource\msg
msg()
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:187
Xml\tags
static tags( $element, $attribs=null, $contents)
Same as Xml::element(), but does not escape contents.
Definition: Xml.php:131
Preferences\editingPreferences
static editingPreferences( $user, IContextSource $context, &$defaultPreferences)
Definition: Preferences.php:816
PreferencesForm\filterDataForSubmit
filterDataForSubmit( $data)
Separate multi-option preferences into multiple preferences, since we have to store them separately.
Definition: Preferences.php:1682
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:33
PreferencesForm\getExtraSuccessRedirectParameters
getExtraSuccessRedirectParameters()
Get extra parameters for the query string when redirecting after successful save.
Definition: Preferences.php:1637
$opt
$opt
Definition: postprocess-phan.php:115
captcha-old.count
count
Definition: captcha-old.py:225
$languages
switch( $options['output']) $languages
Definition: transstat.php:76
$wgDefaultUserOptions
if( $wgRCFilterByAge) $wgDefaultUserOptions['rcdays']
Definition: Setup.php:284
text
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
Definition: design.txt:12
Title\newMainPage
static newMainPage()
Create a new Title for the Main Page.
Definition: Title.php:559
UserGroupMembership\getExpiry
getExpiry()
Definition: UserGroupMembership.php:74
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page. Return false to stop further processing of the tag $reader:XMLReader object & $pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports. & $fullInterwikiPrefix:Interwiki prefix, may contain colons. & $pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable. Can be used to lazy-load the import sources list. & $importSources:The value of $wgImportSources. Modify as necessary. See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. & $title:Title object for the current page & $request:WebRequest & $ignoreRedirect:boolean to skip redirect check & $target:Title/string of redirect target & $article:Article object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) & $article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() & $ip:IP being check & $result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetMagic':DEPRECATED! Use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language & $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetSpecialPageAliases':DEPRECATED! Use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language & $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Array with elements of the form "language:title" in the order that they will be output. & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LanguageSelector':Hook to change the language selector available on a page. $out:The output page. $cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED! Use HtmlPageLinkRendererBegin instead. Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1954
Preferences\getFormObject
static getFormObject( $user, IContextSource $context, $formClass='PreferencesForm', array $remove=[])
Definition: Preferences.php:1310
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:246
Preferences\getTimeZoneList
static getTimeZoneList(Language $language)
Get a list of all time zones.
Definition: Preferences.php:1551
PreferencesForm\wrapForm
wrapForm( $html)
Definition: Preferences.php:1645
StatusValue\newFatal
static newFatal( $message)
Factory function for fatal errors.
Definition: StatusValue.php:63
PreferencesForm\getLegend
getLegend( $key)
Get the "<legend>" for a given section key.
Definition: Preferences.php:1711
PreferencesForm\getBody
getBody()
Get the whole body of the form.
Definition: Preferences.php:1701
Preferences\searchPreferences
static searchPreferences( $user, IContextSource $context, &$defaultPreferences)
Definition: Preferences.php:1107
$linkRenderer
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing after in associative array form before processing starts Return false to skip default processing and return $ret $linkRenderer
Definition: hooks.txt:1956
SpecialPage\getTitleFor
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
Definition: SpecialPage.php:82
Preferences\filterIntval
static filterIntval( $value, $alldata)
Definition: Preferences.php:1395
$res
$res
Definition: database.txt:21
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:304
ContextSource\getRequest
getRequest()
Get the WebRequest object.
Definition: ContextSource.php:78
Preferences\getDateOptions
static getDateOptions(IContextSource $context)
Definition: Preferences.php:1196
Preferences\tryUISubmit
static tryUISubmit( $formData, $form)
Definition: Preferences.php:1519
ContextSource\getUser
getUser()
Get the User object.
Definition: ContextSource.php:133
ContextSource\getTitle
getTitle()
Get the Title object.
Definition: ContextSource.php:88
PreferencesForm\$modifiedUser
$modifiedUser
Definition: Preferences.php:1611
PreferencesForm\getButtons
getButtons()
Definition: Preferences.php:1654
Html\buttonAttributes
static buttonAttributes(array $attrs, array $modifiers=[])
Modifies a set of attributes meant for button elements and apply a set of default attributes when $wg...
Definition: Html.php:109
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
Preferences\getSaveBlacklist
static getSaveBlacklist()
Definition: Preferences.php:72
User\getDefaultOptions
static getDefaultOptions()
Combine the language default options with any site-specific options and add the default language vari...
Definition: User.php:1563
ContextSource\getLanguage
getLanguage()
Get the Language object.
Definition: ContextSource.php:143
Preferences\$defaultPreferences
static array $defaultPreferences
Definition: Preferences.php:53
MediaWiki\Auth\PasswordAuthenticationRequest
This is a value object for authentication requests with a username and password.
Definition: PasswordAuthenticationRequest.php:29
Preferences
We're now using the HTMLForm object with some customisation to generate the Preferences form.
Definition: Preferences.php:51
$html
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition: hooks.txt:1956
MWException
MediaWiki exception.
Definition: MWException.php:26
PreferencesForm\getModifiedUser
getModifiedUser()
Definition: Preferences.php:1623
Language\fetchLanguageNames
static fetchLanguageNames( $inLanguage=null, $include='mw')
Get an array of language names, indexed by code.
Definition: Language.php:803
UserGroupMembership\getLink
static getLink( $ugm, IContextSource $context, $format, $userName=null)
Gets a link for a user group, possibly including the expiry date if relevant.
Definition: UserGroupMembership.php:346
ContextSource\getOutput
getOutput()
Get the OutputPage object.
Definition: ContextSource.php:123
Preferences\generateSkinOptions
static generateSkinOptions( $user, IContextSource $context)
Definition: Preferences.php:1126
Xml\element
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:39
PreferencesForm
Some tweaks to allow js prefs to work.
Definition: Preferences.php:1607
$time
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1769
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
wfTimestampNow
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Definition: GlobalFunctions.php:2023
Preferences\validateSignature
static validateSignature( $signature, $alldata, $form)
Definition: Preferences.php:1265
HTMLForm\loadInputFromParameters
static loadInputFromParameters( $fieldname, $descriptor, HTMLForm $parent=null)
Initialise a new Object for the field.
Definition: HTMLForm.php:480
MediaWiki\Auth\AuthManager\callLegacyAuthPlugin
static callLegacyAuthPlugin( $method, array $params, $return=null)
Call a legacy AuthPlugin method, if necessary.
Definition: AuthManager.php:238
Preferences\miscPreferences
static miscPreferences( $user, IContextSource $context, &$defaultPreferences)
Dummy, kept for backwards-compatibility.
Definition: Preferences.php:1118
Html\hidden
static hidden( $name, $value, array $attribs=[])
Convenience function to produce an input element with type=hidden.
Definition: Html.php:746
Preferences\watchlistPreferences
static watchlistPreferences( $user, IContextSource $context, &$defaultPreferences)
Definition: Preferences.php:957
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:538
$e
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException' returning false will NOT prevent logging $e
Definition: hooks.txt:2122
Preferences\tryFormSubmit
static tryFormSubmit( $formData, $form)
Handle the form submission if everything validated properly.
Definition: Preferences.php:1456
Preferences\skinPreferences
static skinPreferences( $user, IContextSource $context, &$defaultPreferences)
Definition: Preferences.php:605
$value
$value
Definition: styleTest.css.php:45
ParserOptions\newFromContext
static newFromContext(IContextSource $context)
Get a ParserOptions object from a IContextSource object.
Definition: ParserOptions.php:726
StatusValue\newGood
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:76
Preferences\$saveBlacklist
static $saveBlacklist
Definition: Preferences.php:64
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1956
HTMLForm\displaySection
displaySection( $fields, $sectionName='', $fieldsetIDPrefix='', &$hasUserVisibleFields=false)
Definition: HTMLForm.php:1628
PreferencesForm\setModifiedUser
setModifiedUser( $user)
Definition: Preferences.php:1616
MediaWiki\Auth\AuthManager
This serves as the entry point to the authentication system.
Definition: AuthManager.php:82
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:55
Preferences\profilePreferences
static profilePreferences( $user, IContextSource $context, &$defaultPreferences)
Definition: Preferences.php:208
$code
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable & $code
Definition: hooks.txt:783
Preferences\getTimezoneOptions
static getTimezoneOptions(IContextSource $context)
Definition: Preferences.php:1350
PreferencesForm\$mSubSectionBeforeFields
$mSubSectionBeforeFields
Definition: Preferences.php:1609
HTMLNestedFilterable
Definition: HTMLNestedFilterable.php:3
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
NS_USER
const NS_USER
Definition: Defines.php:64
$link
usually copyright or history_copyright This message must be in HTML not wikitext & $link
Definition: hooks.txt:2929
HTMLFormField\flattenOptions
static flattenOptions( $options)
flatten an array of options to a single array, for instance, a set of "<options>" inside "<optgroups>...
Definition: HTMLFormField.php:1126
wfMessage
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
$t
$t
Definition: testCompression.php:67
MediaWikiServices
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
Skin\getAllowedSkins
static getAllowedSkins()
Fetch the list of user-selectable skins in regards to $wgSkipSkins.
Definition: Skin.php:72
Preferences\getImageSizes
static getImageSizes(IContextSource $context)
Definition: Preferences.php:1230
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:131
MWTimestamp\getLocalInstance
static getLocalInstance( $ts=false)
Get a timestamp instance in the server local timezone ($wgLocaltimezone)
Definition: MWTimestamp.php:204
Preferences\filesPreferences
static filesPreferences( $user, IContextSource $context, &$defaultPreferences)
Definition: Preferences.php:655
Preferences\getOptionFromUser
static getOptionFromUser( $name, $info, $user)
Pull option from a user account.
Definition: Preferences.php:165
Preferences\loadPreferenceValues
static loadPreferenceValues( $user, $context, &$defaultPreferences)
Loads existing values for a given array of preferences.
Definition: Preferences.php:115
Preferences\renderingPreferences
static renderingPreferences( $user, IContextSource $context, &$defaultPreferences)
Definition: Preferences.php:754
$options
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
Definition: hooks.txt:1049
Language
Internationalisation code.
Definition: Language.php:35
Preferences\$saveFilters
static array $saveFilters
Definition: Preferences.php:56
UserGroupMembership
Represents a "user group membership" – a specific instance of a user belonging to a group.
Definition: UserGroupMembership.php:36
array
the array() calling protocol came about after MediaWiki 1.4rc1.
$wgContLang
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the content language as $wgContLang
Definition: design.txt:56
Preferences\cleanSignature
static cleanSignature( $signature, $alldata, $form)
Definition: Preferences.php:1291
HTMLForm
Object handling generic submission, CSRF protection, layout and other logic for UI forms.
Definition: HTMLForm.php:128
Preferences\datetimePreferences
static datetimePreferences( $user, IContextSource $context, &$defaultPreferences)
Definition: Preferences.php:677