From 255a58bedd29491c5550eebe4b8d0a5968f0d56c Mon Sep 17 00:00:00 2001 From: Ed Sanders Date: Fri, 22 Mar 2019 15:11:17 +0000 Subject: [PATCH] SpecialPreferences: Use real OOUI PHP layouts Change-Id: Id8c798c0d5be07afd1c4d6584af22c54c3465621 --- .../specials/forms/PreferencesFormOOUI.php | 138 ++++++------------ .../tabs.js | 53 ++----- ...awiki.special.preferences.styles.ooui.less | 111 +++++++------- 3 files changed, 107 insertions(+), 195 deletions(-) diff --git a/includes/specials/forms/PreferencesFormOOUI.php b/includes/specials/forms/PreferencesFormOOUI.php index 81abf1c8e1..fd98dcbc33 100644 --- a/includes/specials/forms/PreferencesFormOOUI.php +++ b/includes/specials/forms/PreferencesFormOOUI.php @@ -117,45 +117,12 @@ class PreferencesFormOOUI extends OOUIHTMLForm { } 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; } /** @@ -163,61 +130,50 @@ class PreferencesFormOOUI extends OOUIHTMLForm { * @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 + ] ); } /** diff --git a/resources/src/mediawiki.special.preferences.ooui/tabs.js b/resources/src/mediawiki.special.preferences.ooui/tabs.js index ffa9e42f34..71b343c132 100644 --- a/resources/src/mediawiki.special.preferences.ooui/tabs.js +++ b/resources/src/mediawiki.special.preferences.ooui/tabs.js @@ -3,9 +3,7 @@ */ ( 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. @@ -18,46 +16,13 @@ } ) .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 ); } @@ -75,7 +40,7 @@ // 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(); } @@ -86,7 +51,7 @@ /** * @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. */ @@ -108,14 +73,14 @@ 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(); } } @@ -126,7 +91,7 @@ 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. diff --git a/resources/src/mediawiki.special.preferences.styles.ooui.less b/resources/src/mediawiki.special.preferences.styles.ooui.less index b1931f486a..532b9ca5a8 100644 --- a/resources/src/mediawiki.special.preferences.styles.ooui.less +++ b/resources/src/mediawiki.special.preferences.styles.ooui.less @@ -45,89 +45,80 @@ 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 { + // 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 */ -- 2.20.1