}
protected function wrapFieldSetSection( $legend, $section, $attributes, $isRoot ) {
- // to get a user visible effect, wrap the fieldset into a framed panel layout
- if ( $isRoot ) {
- // Mimic TabPanelLayout
- $wrapper = new OOUI\PanelLayout( [
- 'expanded' => false,
- 'scrollable' => true,
- // Framed and padded for no-JS, frame hidden with CSS
- 'framed' => true,
- 'infusable' => false,
- 'classes' => [ 'oo-ui-stackLayout oo-ui-indexLayout-stackLayout' ]
- ] );
- $layout = new OOUI\PanelLayout( [
- 'expanded' => false,
- 'scrollable' => true,
- 'infusable' => false,
- 'classes' => [ 'oo-ui-tabPanelLayout' ]
- ] );
- $wrapper->appendContent( $layout );
- } else {
- $wrapper = $layout = new OOUI\PanelLayout( [
- 'expanded' => false,
- 'padded' => true,
- 'framed' => true,
- 'infusable' => false,
- ] );
- }
+ $layout = parent::wrapFieldSetSection( $legend, $section, $attributes, $isRoot );
- $layout->appendContent(
- new OOUI\FieldsetLayout( [
- 'label' => $legend,
- 'infusable' => false,
- 'items' => [
- new OOUI\Widget( [
- 'content' => new OOUI\HtmlSnippet( $section )
- ] ),
- ],
- ] + $attributes )
- );
- return $wrapper;
+ $layout->addClasses( [ 'mw-prefs-fieldset-wrapper' ] );
+ $layout->removeClasses( [ 'oo-ui-panelLayout-framed' ] );
+
+ return $layout;
}
/**
* @return string
*/
function getBody() {
- // Construct fake tabs to avoid FOUC. The structure mimics OOUI's tabPanelLayout.
- // TODO: Consider creating an infusable TabPanelLayout in OOUI-PHP.
- $fakeTabs = [];
- foreach ( $this->getPreferenceSections() as $i => $key ) {
- $fakeTabs[] =
- Html::rawElement(
- 'div',
- [
- 'class' =>
- 'oo-ui-widget oo-ui-widget-enabled oo-ui-optionWidget ' .
- 'oo-ui-tabOptionWidget oo-ui-labelElement' .
- ( $i === 0 ? ' oo-ui-optionWidget-selected' : '' )
+ $tabPanels = [];
+ foreach ( $this->mFieldTree as $key => $val ) {
+ if ( !is_array( $val ) ) {
+ wfDebug( __METHOD__ . " encountered a field not attached to a section: '$key'" );
+ continue;
+ }
+ $label = $this->getLegend( $key );
+ $content =
+ $this->getHeaderText( $key ) .
+ $this->displaySection( $this->mFieldTree[$key] ) .
+ $this->getFooterText( $key );
+
+ $tabPanels[] = new OOUI\TabPanelLayout( [
+ 'classes' => [ 'mw-htmlform-autoinfuse-lazy' ],
+ 'name' => 'mw-prefsection-' . $key,
+ 'label' => $label,
+ 'content' => new OOUI\FieldsetLayout( [
+ 'classes' => [ 'mw-prefs-section-fieldset' ],
+ 'label' => $label,
+ 'items' => [
+ new OOUI\Widget( [
+ 'content' => new OOUI\HtmlSnippet( $content )
+ ] ),
],
- Html::element(
- 'a',
- [
- 'class' => 'oo-ui-labelElement-label',
- // Make this a usable link instead of a span so the tabs
- // can be used before JS runs
- 'href' => '#mw-prefsection-' . $key
- ],
- $this->getLegend( $key )
- )
- );
+ ] ),
+ 'expanded' => false,
+ 'framed' => true,
+ ] );
}
- $fakeTabsHtml = Html::rawElement(
- 'div',
- [ 'class' => 'oo-ui-layout oo-ui-panelLayout oo-ui-indexLayout-tabPanel' ],
- Html::rawElement(
- 'div',
- [ 'class' => 'oo-ui-widget oo-ui-widget-enabled oo-ui-selectWidget ' .
- 'oo-ui-selectWidget-depressed oo-ui-tabSelectWidget' ],
- implode( $fakeTabs )
- )
- );
-
- return Html::rawElement(
- 'div',
- [ 'class' => 'oo-ui-layout oo-ui-panelLayout oo-ui-panelLayout-framed mw-prefs-faketabs' ],
- Html::rawElement(
- 'div',
- [ 'class' => 'oo-ui-layout oo-ui-menuLayout oo-ui-menuLayout-static ' .
- 'oo-ui-menuLayout-top oo-ui-menuLayout-showMenu oo-ui-indexLayout' ],
- Html::rawElement(
- 'div',
- [ 'class' => 'oo-ui-menuLayout-menu' ],
- $fakeTabsHtml
- ) .
- Html::rawElement(
- 'div',
- [ 'class' => 'oo-ui-menuLayout-content mw-htmlform-autoinfuse-lazy' ],
- $this->displaySection( $this->mFieldTree, '', 'mw-prefsection-' )
- )
- )
- );
+
+ $indexLayout = new OOUI\IndexLayout( [
+ 'infusable' => true,
+ 'expanded' => false,
+ 'autoFocus' => false,
+ 'classes' => [ 'mw-prefs-tabs' ],
+ ] );
+ $indexLayout->addTabPanels( $tabPanels );
+
+ return new OOUI\PanelLayout( [
+ 'framed' => true,
+ 'expanded' => false,
+ 'classes' => [ 'mw-prefs-tabs-wrapper' ],
+ 'content' => $indexLayout
+ ] );
}
/**
*/
( function () {
$( function () {
- var $preferences, tabs, wrapper, previousTab, switchingNoHash;
-
- $preferences = $( '#preferences' );
+ var tabs, previousTab, switchingNoHash;
// Make sure the accessibility tip is focussable so that keyboard users take notice,
// but hide it by default to reduce visual clutter.
} )
.insertBefore( '.mw-htmlform-ooui-wrapper' );
- tabs = new OO.ui.IndexLayout( {
- expanded: false,
- // Do not remove focus from the tabs menu after choosing a tab
- autoFocus: false
- } );
-
- mw.config.get( 'wgPreferencesTabs' ).forEach( function ( tabConfig ) {
- var panel, $panelContents;
-
- panel = new OO.ui.TabPanelLayout( tabConfig.name, {
- expanded: false,
- label: tabConfig.label
- } );
- $panelContents = $( '#mw-prefsection-' + tabConfig.name );
-
- // Hide the unnecessary PHP PanelLayouts
- // (Do not use .remove(), as that would remove event handlers for everything inside them)
- $panelContents.parent().detach();
+ tabs = OO.ui.infuse( $( '.mw-prefs-tabs' ) );
- panel.$element.append( $panelContents );
- tabs.addTabPanels( [ panel ] );
-
- // Remove duplicate labels
- // (This must be after .addTabPanels(), otherwise the tab item doesn't exist yet)
- $panelContents.children( 'legend' ).remove();
- $panelContents.attr( 'aria-labelledby', panel.getTabItem().getElementId() );
- } );
-
- wrapper = new OO.ui.PanelLayout( {
- expanded: false,
- padded: false,
- framed: true
- } );
- wrapper.$element.append( tabs.$element );
- $preferences.prepend( wrapper.$element );
- $( '.mw-prefs-faketabs' ).remove();
+ tabs.$element.addClass( 'mw-prefs-tabs-infused' );
function enhancePanel( panel ) {
if ( !panel.$element.data( 'mw-section-infused' ) ) {
- // mw-htmlform-autoinfuse-lazy class has been removed by replacing faketabs
+ panel.$element.removeClass( 'mw-htmlform-autoinfuse-lazy' );
mw.hook( 'htmlform.enhance' ).fire( panel.$element );
panel.$element.data( 'mw-section-infused', true );
}
// Changing the hash apparently causes keyboard focus to be lost?
// Save and restore it. This makes no sense though.
active = document.activeElement;
- location.hash = '#mw-prefsection-' + panel.getName();
+ location.hash = '#' + panel.getName();
if ( active ) {
active.focus();
}
/**
* @ignore
- * @param {string} name the name of a tab without the prefix ("mw-prefsection-")
+ * @param {string} name The name of a tab
* @param {boolean} [noHash] A hash will be set according to the current
* open section. Use this flag to suppress this.
*/
matchedElement, parentSection;
if ( hash.match( /^#mw-prefsection-[\w]+$/ ) ) {
mw.storage.session.remove( 'mwpreferences-prevTab' );
- switchPrefTab( hash.replace( '#mw-prefsection-', '' ) );
+ switchPrefTab( hash.slice( 1 ) );
} else if ( hash.match( /^#mw-[\w-]+$/ ) ) {
matchedElement = document.getElementById( hash.slice( 1 ) );
parentSection = $( matchedElement ).parent().closest( '[id^="mw-prefsection-"]' );
if ( parentSection.length ) {
mw.storage.session.remove( 'mwpreferences-prevTab' );
// Switch to proper tab and scroll to selected item.
- switchPrefTab( parentSection.attr( 'id' ).replace( 'mw-prefsection-', '' ), true );
+ switchPrefTab( parentSection.attr( 'id' ), true );
matchedElement.scrollIntoView();
}
}
if ( hash.match( /^#mw-[\w-]+/ ) ) {
detectHash();
} else if ( hash === '' ) {
- switchPrefTab( 'personal', true );
+ switchPrefTab( 'mw-prefsection-personal', true );
}
} )
// Run the function immediately to select the proper tab on startup.
overflow: hidden;
}
-/* Most outer Panellayout:
- * Decrease contrast of `border` slightly as padding/border combination is sufficient
- * accessibility wise and focus of content is more important here. */
-#preferences .oo-ui-panelLayout-framed {
- border-color: #c8ccd1;
-}
+.mw-prefs-tabs {
+ .mw-prefs-fieldset-wrapper {
+ padding-left: 0;
+ padding-right: 0;
+
+ &:first-child {
+ padding-top: 0;
+ }
-#preferences .oo-ui-menuLayout .oo-ui-panelLayout-framed .oo-ui-panelLayout-framed {
- border-width: 0;
- border-radius: 0;
- padding-left: 0;
- padding-right: 0;
- box-shadow: none;
+ &:last-child {
+ padding-bottom: 0;
+ }
+ }
}
-.mw-prefs-faketabs > .oo-ui-menuLayout > .oo-ui-menuLayout-menu a {
- color: inherit;
- text-decoration: none;
+.mw-prefs-tabs-wrapper.oo-ui-panelLayout-framed,
+.mw-prefs-tabs > .oo-ui-menuLayout-content > .oo-ui-indexLayout-stackLayout > .oo-ui-tabPanelLayout {
+ /* Decrease contrast of `border` slightly as padding/border combination is sufficient
+ * accessibility wise and focus of content is more important here. */
+ border-color: #c8ccd1;
}
-/* Disabled JavaScript */
+/* JavaScript disabled */
.client-nojs {
- /* Adjust the borders: frame each prefsection instead of the
- * whole tabLayout wrapper */
- #preferences .oo-ui-menuLayout .oo-ui-panelLayout-framed .oo-ui-panelLayout-framed:first-child {
- border-color: #c8ccd1;
- border-width: 1px 0 0;
- }
-
- #preferences .oo-ui-panelLayout-framed .oo-ui-panelLayout-framed:last-child {
- padding-bottom: 0;
- margin-bottom: 0;
- }
-
- /* Fake Tabs to address reflow */
- .mw-prefs-faketabs {
+ // Disable .oo-ui-panelLayout-framed on outer wrapper
+ .mw-prefs-tabs-wrapper {
border-width: 0;
border-radius: 0;
- .box-shadow( none );
+ }
- > .oo-ui-menuLayout > .oo-ui-menuLayout-content > .oo-ui-stackLayout {
- margin-bottom: 1em;
+ .mw-prefs-tabs {
+ // Hide the tab menu when JS is disabled as we can't use this feature
+ > .oo-ui-menuLayout-menu {
+ display: none;
}
- /* Hide the tab menu when JS is disabled as we can't use this feature */
- > .oo-ui-menuLayout > .oo-ui-menuLayout-menu {
- display: none;
+ .mw-prefs-section-fieldset {
+ // <legend> is hard to style, so apply border to top of group
+ > .oo-ui-fieldsetLayout-group {
+ padding-top: 1.5em;
+ border-top: 1px solid #c8ccd1;
+ }
+
+ // Remove spacing between legend and underline
+ &.oo-ui-labelElement > .oo-ui-fieldsetLayout-header > .oo-ui-labelElement-label {
+ margin-bottom: 0;
+ }
+ }
+
+ // Spacing between sections
+ > .oo-ui-menuLayout-content > .oo-ui-indexLayout-stackLayout > .oo-ui-tabPanelLayout {
+ margin-bottom: 1em;
}
}
}
-/* Enabled JavaScript
- * Hide top level legends when JS is enabled, as they will not be visible
- * when the real tabLayout is built */
-.client-js #preferences {
+/* JavaScript enabled */
+.client-js .mw-prefs-tabs {
.oo-ui-tabPanelLayout {
- padding-top: 0.5em;
+ // Panels don't need borders as the IndexLayout is inside a framed wrapper.
+ border: 0;
- & > fieldset > legend {
+ // Hide section legend, only used in nojs mode
+ > fieldset > legend {
display: none;
}
}
- .oo-ui-panelLayout-framed .oo-ui-panelLayout-framed {
- margin-top: 2.286em; /* equals `32px` at `font-size: 14px;` */
- margin-bottom: 0;
- border-width: 0;
- border-radius: 0;
- padding: 0;
- box-shadow: none;
-
- &:first-child {
- margin-top: 0.85714286em;
- }
-
- .oo-ui-panelLayout-framed:first-child {
- margin-top: 0;
+ // Hide all but the first panel before infusion
+ &:not( .mw-prefs-tabs-infused ) {
+ .oo-ui-tabPanelLayout:not( :first-child ) {
+ display: none;
}
}
-
- > .oo-ui-panelLayout > .oo-ui-fieldsetLayout > .oo-ui-fieldsetLayout-header {
- margin-bottom: 1em;
- }
}
/* Make the "Basic information" section more compact */