MediaWiki  master
PreferencesFormOOUI.php
Go to the documentation of this file.
1 <?php
22 
30  protected $mSubSectionBeforeFields = false;
31 
33  private $modifiedUser;
34 
36  private $privateInfoEditable = true;
37 
39  private $optionsEditable = true;
40 
42  private $useMobileLayout;
43 
47  public function setModifiedUser( $user ) {
48  $this->modifiedUser = $user;
49  }
50 
54  public function getModifiedUser() {
55  if ( $this->modifiedUser === null ) {
56  return $this->getUser();
57  } else {
58  return $this->modifiedUser;
59  }
60  }
61 
65  public function isPrivateInfoEditable() {
66  return $this->privateInfoEditable;
67  }
68 
73  public function setPrivateInfoEditable( $editable ) {
74  $this->privateInfoEditable = $editable;
75  $this->suppressDefaultSubmit( !$this->privateInfoEditable && !$this->optionsEditable );
76  }
77 
81  public function areOptionsEditable() {
82  return $this->optionsEditable;
83  }
84 
88  public function setOptionsEditable( $optionsEditable ) {
89  $this->optionsEditable = $optionsEditable;
90  $this->suppressDefaultSubmit( !$this->privateInfoEditable && !$this->optionsEditable );
91  }
92 
100  return [];
101  }
102 
103  public function wrapForm( $html ) {
104  $html = Xml::tags( 'div', [ 'id' => 'preferences' ], $html );
105 
106  return parent::wrapForm( $html );
107  }
108 
115  public function filterDataForSubmit( $data ) {
116  foreach ( $this->mFlatFields as $fieldname => $field ) {
117  if ( $field instanceof HTMLNestedFilterable ) {
118  $info = $field->mParams;
119  $prefix = $info['prefix'] ?? $fieldname;
120  foreach ( $field->filterDataForSubmit( $data[$fieldname] ) as $key => $value ) {
121  $data["$prefix$key"] = $value;
122  }
123  unset( $data[$fieldname] );
124  }
125  }
126 
127  return $data;
128  }
129 
130  protected function wrapFieldSetSection( $legend, $section, $attributes, $isRoot ) {
131  $layout = parent::wrapFieldSetSection( $legend, $section, $attributes, $isRoot );
132 
133  $layout->addClasses( [ 'mw-prefs-fieldset-wrapper' ] );
134  $layout->removeClasses( [ 'oo-ui-panelLayout-framed' ] );
135 
136  return $layout;
137  }
138 
139  private function isMobileLayout() {
140  if ( $this->useMobileLayout === null ) {
141  $skin = $this->getSkin();
142  $this->useMobileLayout = false;
143  $this->getHookRunner()->onPreferencesGetLayout( $this->useMobileLayout,
144  $skin->getSkinName(), [ 'isResponsive' => $skin->isResponsive() ] );
145  }
146  return $this->useMobileLayout;
147  }
148 
152  public function addFields( $descriptor ) {
153  // Replace checkbox fields with toggle switchs on Special:Preferences
154  if ( $this->isMobileLayout() && $this->getTitle()->isSpecial( 'Preferences' ) ) {
155  foreach ( $descriptor as $_ => &$info ) {
156  if ( isset( $info['type'] ) && in_array( $info['type'], [ 'check', 'toggle' ] ) ) {
157  unset( $info['type'] );
158  $info['class'] = HTMLToggleSwitchField::class;
159  } elseif ( isset( $info['class'] ) && $info['class'] === HTMLCheckField::class ) {
160  $info['class'] = HTMLToggleSwitchField::class;
161  }
162  }
163  }
164  return parent::addFields( $descriptor );
165  }
166 
171  public function getBody() {
172  if ( $this->isMobileLayout() ) {
173  // Import the icons used in the mobile view
174  $this->getOutput()->addModuleStyles(
175  [
176  'oojs-ui.styles.icons-user',
177  'oojs-ui.styles.icons-editing-core',
178  'oojs-ui.styles.icons-editing-advanced',
179  'oojs-ui.styles.icons-wikimediaui',
180  'oojs-ui.styles.icons-content',
181  'oojs-ui.styles.icons-moderation',
182  'oojs-ui.styles.icons-interactions',
183  'oojs-ui.styles.icons-movement',
184  'oojs-ui.styles.icons-wikimedia',
185  'oojs-ui.styles.icons-media',
186  'oojs-ui.styles.icons-accessibility',
187  'oojs-ui.styles.icons-layout',
188  ]
189  );
190  $form = $this->createMobilePreferencesForm();
191  } else {
192  $form = $this->createDesktopPreferencesForm();
193  }
194 
195  $header = $this->formatFormHeader();
196 
197  return $header . $form;
198  }
199 
206  public function getLegend( $key ) {
207  $legend = parent::getLegend( $key );
208  $this->getHookRunner()->onPreferencesGetLegend( $this, $key, $legend );
209  return $legend;
210  }
211 
216  public function getPreferenceSections() {
217  return array_keys( array_filter( $this->mFieldTree, 'is_array' ) );
218  }
219 
224  private function createMobilePreferencesForm() {
225  $sectionButtons = [];
226  $sectionContents = [];
227  $iconNames = $this->getIconNames();
228 
229  foreach ( $this->mFieldTree as $key => $val ) {
230  if ( !is_array( $val ) ) {
231  wfDebug( __METHOD__ . " encountered a field not attached to a section: '$key'" );
232  continue;
233  }
234  $label = $this->getLegend( $key );
235  $content =
236  $this->getHeaderHtml( $key ) .
237  $this->displaySection(
238  $val,
239  "",
240  "mw-prefsection-$key-"
241  ) .
242  $this->getFooterHtml( $key );
243 
244  // Creating the header section
245  $label = ( new OOUI\Tag( 'div' ) )->appendContent(
246  ( new OOUI\Tag( 'h5' ) )->appendContent( $label )->addClasses( [ 'mw-prefs-title' ] ),
247  $this->createMobileDescription( $key )
248  );
249  $contentDiv = $this->createContentMobile( $key, $label, $content );
250 
251  $sectionButton = new OOUI\ButtonWidget( [
252  'id' => 'mw-mobile-prefs-' . $key,
253  'icon' => $iconNames[ $key ] ?? 'settings',
254  'label' => new OOUI\HtmlSnippet( $label->toString() ),
255  'data' => $key,
256  'classes' => [ 'mw-mobile-prefsection' ],
257  'framed' => false,
258  ] );
259  $sectionButtons[] = $sectionButton;
260  $sectionContents[] = $contentDiv;
261  }
262 
263  $buttonGroup = new OOUI\ButtonGroupWidget( [
264  'classes' => [ 'mw-mobile-prefs-sections' ],
265  'infusable' => true,
266  ] );
267  $buttonGroup->addItems( $sectionButtons );
268  $form = ( new OOUI\Tag( 'div' ) )
269  ->setAttributes( [ 'id' => 'mw-prefs-container' ] )
270  ->addClasses( [ 'mw-mobile-prefs-container' ] )
271  ->appendContent( $buttonGroup )
272  ->appendContent( $sectionContents );
273 
274  return $form;
275  }
276 
281  private function getIconNames() {
282  $iconNames = [
283  'personal' => 'userAvatar',
284  'rendering' => 'palette',
285  'editing' => 'edit',
286  'rc' => 'recentChanges',
287  'watchlist' => 'watchlist',
288  'searchoptions' => 'search',
289  'misc' => '',
290  ];
291  $hookIcons = [];
292  // Get icons from extensions that have their own sections
293  $this->getHookRunner()->onPreferencesGetIcon( $hookIcons );
294  $iconNames += $hookIcons;
295 
296  return $iconNames;
297  }
298 
304  private function createMobileDescription( $key ) {
305  $prefDescriptionMsg = $this->msg( "prefs-description-" . $key );
306  $prefDescription = $prefDescriptionMsg->exists() ? $prefDescriptionMsg->text() : "";
307  $prefDescriptionElement = ( new OOUI\Tag( 'p' ) )
308  ->appendContent( $prefDescription )
309  ->addClasses( [ 'mw-prefs-description' ] );
310 
311  return $prefDescriptionElement;
312  }
313 
321  private function createContentMobile( $key, $label, $content ) {
322  $contentDiv = ( new OOUI\Tag( 'div' ) );
323  $contentDiv->addClasses( [
324  'mw-prefs-content-page',
325  'mw-prefs-section-fieldset',
326  ] );
327  $contentDiv->setAttributes( [
328  'id' => 'mw-mobile-prefs-' . $key
329  ] );
330  $contentBody = ( new OOUI\Tag( 'div' ) )
331  ->addClasses( [ 'mw-htmlform-autoinfuse-lazy' ] )
332  ->setAttributes( [
333  'id' => 'mw-mobile-prefs-' . $key . '-content'
334  ] );
335  $contentHeader = ( new OOUI\Tag( 'div' ) )->setAttributes( [
336  'id' => 'mw-mobile-prefs-' . $key . '-head'
337  ] );
338  $contentHeader->addClasses( [ 'mw-prefs-content-head' ] );
339  $contentHeaderTitle = ( new OOUI\Tag( 'h5' ) )->setAttributes( [
340  'id' => 'mw-mobile-prefs-' . $key . '-title',
341  ] );
342  $contentHeaderTitle->appendContent( $label )->addClasses( [ 'mw-prefs-header-title' ] );
343  $formContent = new OOUI\Widget( [
344  'content' => new OOUI\HtmlSnippet( $content )
345  ] );
346  $hiddenForm = ( new OOUI\Tag( 'div' ) )->appendContent( $formContent );
347  $contentHeader->appendContent( $contentHeaderTitle );
348  $contentBody->appendContent( $contentHeader );
349  $contentBody->appendContent( $hiddenForm );
350  $contentDiv->appendContent( $contentBody );
351 
352  return $contentDiv;
353  }
354 
359  private function createDesktopPreferencesForm() {
360  $tabPanels = [];
361  foreach ( $this->mFieldTree as $key => $val ) {
362  if ( !is_array( $val ) ) {
363  wfDebug( __METHOD__ . " encountered a field not attached to a section: '$key'" );
364  continue;
365  }
366  $label = $this->getLegend( $key );
367  $content =
368  $this->getHeaderHtml( $key ) .
369  $this->displaySection(
370  $val,
371  "",
372  "mw-prefsection-$key-"
373  ) .
374  $this->getFooterHtml( $key );
375 
376  $tabPanels[] = new OOUI\TabPanelLayout( 'mw-prefsection-' . $key, [
377  'classes' => [ 'mw-htmlform-autoinfuse-lazy' ],
378  'label' => $label,
379  'content' => new OOUI\FieldsetLayout( [
380  'classes' => [ 'mw-prefs-section-fieldset' ],
381  'id' => "mw-prefsection-$key",
382  'label' => $label,
383  'items' => [
384  new OOUI\Widget( [
385  'content' => new OOUI\HtmlSnippet( $content )
386  ] ),
387  ],
388  ] ),
389  'expanded' => false,
390  'framed' => true,
391  ] );
392  }
393 
394  $indexLayout = new OOUI\IndexLayout( [
395  'infusable' => true,
396  'expanded' => false,
397  'autoFocus' => false,
398  'classes' => [ 'mw-prefs-tabs' ],
399  ] );
400  $indexLayout->addTabPanels( $tabPanels );
401 
402  $form = new OOUI\PanelLayout( [
403  'framed' => true,
404  'expanded' => false,
405  'classes' => [ 'mw-prefs-tabs-wrapper' ],
406  'content' => $indexLayout
407  ] );
408 
409  return $form;
410  }
411 }
addFields( $fields)
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
suppressDefaultSubmit( $suppressSubmit=true)
Stop a default submit button being shown for this form.
Definition: HTMLForm.php:1713
displaySection( $fields, $sectionName='', $fieldsetIDPrefix='', &$hasUserVisibleFields=false)
Definition: HTMLForm.php:1930
getFooterHtml( $section=null)
Get footer HTML.
Definition: HTMLForm.php:1030
internal since 1.36
Definition: User.php:98
Compact stacked vertical format for forms, implemented using OOUI widgets.
getHeaderHtml( $section=null)
Get header HTML.
Form to edit user preferences.
filterDataForSubmit( $data)
Separate multi-option preferences into multiple preferences, since we have to store them separately.
getPreferenceSections()
Get the keys of each top level preference section.
getBody()
Get the whole body of the form.
wrapForm( $html)
Wrap the form innards in an actual "<form>" element.
bool $mSubSectionBeforeFields
Override default value from HTMLForm.
addFields( $descriptor)
Add fields to the form.1.34Array of Field constructs, as described in the class documentation HTMLFor...
getLegend( $key)
Get the "<legend>" for a given section key.
wrapFieldSetSection( $legend, $section, $attributes, $isRoot)
Wraps the given $section into a user-visible fieldset.Stability: stableto overrideLegend text for the...
getExtraSuccessRedirectParameters()
Get extra parameters for the query string when redirecting after successful save.
setPrivateInfoEditable( $editable)
Whether the.
setOptionsEditable( $optionsEditable)
static tags( $element, $attribs, $contents)
Same as Xml::element(), but does not escape contents.
Definition: Xml.php:141
$content
Definition: router.php:76
$header