diff options
author | jsn <jsherman@wikimedia.org> | 2022-12-02 15:03:12 -0600 |
---|---|---|
committer | jsn <jsherman@wikimedia.org> | 2022-12-12 09:43:53 -0600 |
commit | ac3128360deb0ad0ee55bbe67008f9d6e1b38094 (patch) | |
tree | d885623a8c6b0c0b59ad6af51ea78958102b074c | |
parent | 949c83b98b922aac2daa5e5e924cf2e863e256b4 (diff) | |
download | mediawikicore-ac3128360deb0ad0ee55bbe67008f9d6e1b38094.tar.gz mediawikicore-ac3128360deb0ad0ee55bbe67008f9d6e1b38094.zip |
Optimize mobile prefs modals
Bug: T324227
Change-Id: I9f399f5517602b15a34c9e1af5dca213c2678785
3 files changed, 151 insertions, 101 deletions
diff --git a/includes/specials/forms/PreferencesFormOOUI.php b/includes/specials/forms/PreferencesFormOOUI.php index 48bbe2ecb067..bc70394d0d5d 100644 --- a/includes/specials/forms/PreferencesFormOOUI.php +++ b/includes/specials/forms/PreferencesFormOOUI.php @@ -247,7 +247,7 @@ class PreferencesFormOOUI extends OOUIHTMLForm { 'expanded' => false, 'content' => [], 'framed' => false, - 'classes' => [ 'mw-mobile-preferences-option' ] + 'classes' => [ 'mw-mobile-prefsection' ] ] ); $iconHeaderDiv = ( new OOUI\Tag( 'div' ) ) @@ -277,20 +277,24 @@ class PreferencesFormOOUI extends OOUIHTMLForm { $contentDiv = ( new OOUI\Tag( 'div' ) )->addClasses( [ 'mw-prefs-hidden' ] ); $contentDiv->addClasses( [ 'mw-prefs-content-page' ] ); $contentDiv->setAttributes( [ - 'id' => 'mw-prefs-option-' . $key . '-content' + 'id' => 'mw-mobile-prefs-' . $key . '-content' + ] ); + $contentHeader = ( new OOUI\Tag( 'div' ) )->setAttributes( [ + 'id' => 'mw-mobile-prefs-' . $key . '-head' ] ); - $contentHeader = ( new OOUI\Tag( 'div' ) )->addClasses( [ 'mw-prefs-content-header' ] ); $contentHeaderBackButton = new OOUI\IconWidget( [ - 'icon' => 'previous', + 'icon' => 'close', 'label' => $this->msg( "prefs-back-label" ), 'title' => $this->msg( "prefs-back-title" ), - 'classes' => [ 'mw-prefs-header-icon' ], + 'classes' => [ 'mw-prefs-header-icon', 'mw-ui-icon' ], ] ); $contentHeaderBackButton->setAttributes( [ - 'id' => 'mw-prefs-option-' . $key . '-back-button', + 'id' => 'mw-mobile-prefs-' . $key . '-back-button', + ] ); + $contentHeaderTitle = ( new OOUI\Tag( 'h5' ) )->setAttributes( [ + 'id' => 'mw-mobile-prefs-' . $key . '-title', ] ); - $contentHeaderTitle = ( new OOUI\Tag( 'h5' ) ) - ->appendContent( $label )->addClasses( [ 'mw-prefs-header-title' ] ); + $contentHeaderTitle->appendContent( $label )->addClasses( [ 'mw-prefs-header-title' ] ); $formContent = new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $content ) ] ); @@ -301,7 +305,7 @@ class PreferencesFormOOUI extends OOUIHTMLForm { $contentDiv->appendContent( $hiddenForm ); $prefPanel->appendContent( $contentDiv ); $prefPanel->setAttributes( [ - 'id' => 'mw-prefs-option-' . $key, + 'id' => 'mw-mobile-prefs-' . $key, ] ); $prefPanel->setInfusable( true ); $prefPanels[] = $prefPanel; diff --git a/resources/src/mediawiki.special.preferences.ooui/mobile.js b/resources/src/mediawiki.special.preferences.ooui/mobile.js index 1dc1b213675c..c9fcb8a87571 100644 --- a/resources/src/mediawiki.special.preferences.ooui/mobile.js +++ b/resources/src/mediawiki.special.preferences.ooui/mobile.js @@ -2,12 +2,14 @@ * JavaScript for Special:Preferences: mobileLayout. */ ( function () { + // Define a window manager to control the dialogs + var dialogFactory = new OO.Factory(); + var windowManager = new OO.ui.WindowManager( { factory: dialogFactory } ); /* - * Adds a ToggleSwitchWidget to control each checkboxWidget - * Hides each checkboxWidget + * Add a ToggleSwitchWidget to control each checkboxWidget + * Hide each checkboxWidget */ - function insertToggles() { - var checkboxes = document.querySelectorAll( 'span.oo-ui-checkboxInputWidget' ); + function insertToggles( checkboxes ) { Array.prototype.forEach.call( checkboxes, function ( checkboxWidget ) { var checkboxInput = checkboxWidget.querySelector( 'input' ); var toggleSwitchWidget = new OO.ui.ToggleSwitchWidget( { @@ -22,63 +24,67 @@ checkboxWidget.classList.add( 'hidden' ); } ); } - $( function () { - insertToggles(); - var options, windowManager, preferencesForm, prefOptionsContainer, prefContent, prefFormWrapper; - options = OO.ui.infuse( document.querySelector( '.mw-mobile-preferences-container' ) ); - windowManager = new OO.ui.WindowManager(); - preferencesForm = document.querySelector( '#mw-prefs-form' ); - prefOptionsContainer = document.querySelector( '#mw-prefs-container' ); - prefFormWrapper = document.querySelector( '.mw-htmlform-ooui-wrapper' ); - - function showContent( element ) { - prefContent = document.querySelector( '#' + element.elementId + '-content' ); - prefContent.classList.remove( 'mw-prefs-hidden' ); - prefOptionsContainer.classList.add( 'mw-prefs-hidden' ); - prefOptionsContainer.removeAttribute( 'style' ); - preferencesForm.insertBefore( prefContent, preferencesForm.firstChild ); - - function PrefDialog( config ) { - PrefDialog.super.call( this, config ); - } - - OO.inheritClass( PrefDialog, OO.ui.Dialog ); - PrefDialog.static.name = element.elementId; - PrefDialog.static.escapable = false; - PrefDialog.prototype.initialize = function () { - PrefDialog.super.prototype.initialize.call( this ); - this.content = new OO.ui.PanelLayout( { padded: true, expanded: true } ); - this.$body.append( preferencesForm ); - }; - - PrefDialog.prototype.getBodyHeight = function () { - return this.content.$element.outerHeight( true ); - }; - - var prefDialog = new PrefDialog( { size: 'full' } ); - - $( document.body ).append( windowManager.$element ); - windowManager.addWindows( [ prefDialog ] ); - windowManager.openWindow( prefDialog ); - - if ( prefDialog.isOpening() ) { - document.querySelector( '#mw-mf-viewport' ).classList.add( 'hidden' ); - } + /* + * Configure and register a dialog for a pref section + */ + function sectionDialog( sectionId, sectionHead, sectionBody ) { + function PrefDialog() { + var conf = { classes: [ 'overlay-content', 'mw-mobile-pref-window' ] }; + PrefDialog.super.call( this, conf ); } + OO.inheritClass( PrefDialog, OO.ui.Dialog ); + PrefDialog.static.name = sectionId; + PrefDialog.static.escapable = true; + PrefDialog.static.size = 'larger'; + PrefDialog.prototype.initialize = function () { + insertToggles( sectionBody.querySelectorAll( 'span.oo-ui-checkboxInputWidget' ) ); + this.name = sectionId; + PrefDialog.super.prototype.initialize.call( this ); + this.$head.append( sectionHead ); + this.$head[ 0 ].classList.add( 'mw-mobile-pref-dialog-head' ); + this.$body.append( sectionBody ); + this.content = new OO.ui.PanelLayout( { padded: true, expanded: true } ); + this.$body[ 0 ].classList.add( 'mw-mobile-pref-dialog-body' ); + }; - options.items.forEach( function ( element ) { - document.querySelector( '#' + element.elementId ).addEventListener( 'click', function () { - showContent( element ); + dialogFactory.register( PrefDialog ); + } + // DOM-dependant code + $( function () { + /* + * Initialize Dialogs for all pref sections + */ + function initDialogs() { + // Query the document once, then query that returned element afterwards. + var preferencesForm = document.querySelector( '#mw-prefs-form' ); + var prefButtons = preferencesForm.querySelector( 'div.mw-prefs-buttons' ); + var sections = preferencesForm.querySelectorAll( '.mw-mobile-prefsection' ); + // Move the form buttons (such as save) into the dialog after opening. + windowManager.on( 'opening', function ( win, opened ) { + if ( opened ) { + win.$foot[ 0 ].appendChild( prefButtons ); + } } ); - - var backButtonId = '#' + element.elementId + '-back-button'; - document.querySelector( backButtonId ).addEventListener( 'click', function () { - prefContent.classList.add( 'mw-prefs-hidden' ); - prefOptionsContainer.classList.remove( 'mw-prefs-hidden' ); - prefFormWrapper.insertBefore( preferencesForm, prefFormWrapper.firstChild ); - document.querySelector( '#mw-mf-viewport' ).classList.remove( 'hidden' ); - windowManager.currentWindow.close(); + // Move the form buttons (such as save) back to the main form while closing. + windowManager.on( 'closing', function () { + preferencesForm.querySelector( '#preferences' ).appendChild( prefButtons ); } ); - } ); + // Add the window manager to the form + $( preferencesForm ).append( windowManager.$element ); + // add event listeners and register a dialog for each section + Array.prototype.forEach.call( sections, function ( section ) { + var sectionContent = preferencesForm.querySelector( '#' + section.id + '-content' ); + var sectionBody = sectionContent.querySelector( 'div > div.oo-ui-widget' ); + var sectionHead = sectionContent.querySelector( '#' + section.id + '-head' ); + sectionHead.querySelector( '#' + section.id + '-back-button' ).addEventListener( 'click', function () { + windowManager.closeWindow( section.id ); + } ); + preferencesForm.querySelector( '#' + section.id ).addEventListener( 'click', function () { + windowManager.openWindow( section.id ); + } ); + sectionDialog( section.id, sectionHead, sectionBody ); + } ); + } + initDialogs(); } ); }() ); diff --git a/resources/src/mediawiki.special.preferences.styles.ooui.less b/resources/src/mediawiki.special.preferences.styles.ooui.less index 803cfd220c60..d0508c12eb88 100644 --- a/resources/src/mediawiki.special.preferences.styles.ooui.less +++ b/resources/src/mediawiki.special.preferences.styles.ooui.less @@ -26,28 +26,14 @@ .mw-email-authenticated .oo-ui-labelWidget { } */ -/* - * Use `position: sticky` on supported browsers, degrades gracefully in - * all others, therefore no `@supports` feature query to reduce code complexity. - */ .mw-prefs-buttons { background-color: #fff; - .position-sticky(); - bottom: 0; - margin-top: -1px; border-top: 1px solid #c8ccd1; padding: 1em 0; // Add top box shadow on top only to emphasize content is scrollable underneath `sticky`. box-shadow: 0 -4px 4px -4px rgba( 0, 0, 0, 0.25 ); } -// Support Edge: The `position: sticky` rule above causes the buttons to -// disappear in RTL languages on Microsoft Edge. This magically fixes the issue. See T220706. -#preferences { - /* stylelint-disable-next-line plugin/no-unsupported-browser-features */ - filter: brightness( 1 ); -} - /* This is needed because add extra buttons in a weird way */ .mw-prefs-buttons .mw-htmlform-submit-buttons { margin: 0; @@ -191,17 +177,17 @@ These are used when users navigate to Special:Preferences with params ?useskin=vector&useformat=mobile */ -.mw-mobile-preferences-option { +.mw-mobile-prefsection { cursor: pointer; padding-top: 0.3125em; border-bottom: 0.0625em solid @colorGray12; } -.mw-mobile-preferences-option:hover { +.mw-mobile-prefsection:hover { background-color: @colorGray15; } -.mw-mobile-preferences-option:last-child { +.mw-mobile-prefsection:last-child { border-bottom: none; // stylelint-disable-line declaration-property-value-disallowed-list } @@ -232,36 +218,88 @@ with params ?useskin=vector&useformat=mobile display: flex; } -.mw-prefs-content-header + div { - margin-top: 50px; +/* Override default inline styles for 'larger' dialog */ +.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-active.mw-mobile-pref-window { + padding-top: 0; } -.mw-prefs-content-header { +/* Overriding default inline styles for 'larger' dialog */ +.mw-mobile-pref-window > .oo-ui-window-frame { + width: auto !important; /* stylelint-disable-line declaration-no-important */ + height: 100% !important; /* stylelint-disable-line declaration-no-important */ + max-height: 100% !important; /* stylelint-disable-line declaration-no-important */ +} + +.oo-ui-window-head.mw-mobile-pref-dialog-head { width: 100%; - height: 3.125em; - display: block; + height: 3em; + display: flex; + align-items: center; border-bottom: 1px solid @colorGray12; box-shadow: 0 0.25em 0.125em -0.1875em rgba( 0, 0, 0, 0.25 ); position: fixed; background: #fff; - z-index: 100; - margin-top: -52px; - padding-top: 16px; } -.mw-prefs-content-page div.oo-ui-widget.oo-ui-widget-enabled { - margin-left: 10px; +.oo-ui-window-head.mw-mobile-pref-dialog-head > div > h5.mw-prefs-header-title { + font-size: 1em; + font-weight: bold; + line-height: 1.25em; +} + +.oo-ui-window-body.mw-mobile-pref-dialog-body { margin-right: 5px; - padding-top: 16px; + margin-top: 49px; + padding-bottom: 66px; } -.oo-ui-window-body .mw-htmlform-submit-buttons { - padding-left: 16px; +.oo-ui-window-body.mw-mobile-pref-dialog-body > div.oo-ui-widget-enabled > div { + padding: 16px; +} + +.oo-ui-window-body.mw-mobile-pref-dialog-body > div.oo-ui-widget-enabled > div:last-child { + margin-bottom: 16px; +} + +/* T317110: sub-section title */ +.oo-ui-window-body.mw-mobile-pref-dialog-body > div.oo-ui-widget-enabled > div.mw-prefs-fieldset-wrapper > fieldset.oo-ui-fieldsetLayout.oo-ui-labelElement > legend.oo-ui-fieldsetLayout-header { + border-bottom: 1px #000 solid; + max-width: 100%; +} + +/* T317110: sub-section and sub-sub-section titles */ +.oo-ui-window-body.mw-mobile-pref-dialog-body div.oo-ui-widget-enabled > div.mw-prefs-fieldset-wrapper > fieldset.oo-ui-fieldsetLayout.oo-ui-labelElement > legend.oo-ui-fieldsetLayout-header > span.oo-ui-labelElement-label { + font-size: 1em; + font-weight: bold; + line-height: 1.25em; + margin-bottom: 12px; +} + +/* T317110: preference separation */ +.oo-ui-window-body.mw-mobile-pref-dialog-body div.oo-ui-widget-enabled > div.mw-prefs-fieldset-wrapper > fieldset.oo-ui-fieldsetLayout > div.oo-ui-fieldsetLayout-group > div.oo-ui-widget-enabled > div > div { + padding: 12px 0; + margin: 0; + border-bottom: 1px #eaecf0 solid; +} + +/* T317110: preference label */ +.oo-ui-window-body.mw-mobile-pref-dialog-body .oo-ui-labelElement-label { + line-height: 1.25em; } -.oo-ui-window-body #preferences { - position: sticky; - bottom: 0; +/* T317110: help text */ +.oo-ui-window-body.mw-mobile-pref-dialog-body div.oo-ui-fieldLayout-body label.oo-ui-inline-help.oo-ui-labelElement-label.oo-ui-labelElement.oo-ui-labelWidget { + font-size: 0.875em; + line-height: 1.25em; +} + +/* T317110: non-interactive text */ +.oo-ui-window-body.mw-mobile-pref-dialog-body .oo-ui-labelElement-label.oo-ui-labelElement.oo-ui-labelWidget { + color: #72777d; +} + +.oo-ui-window-foot > .mw-prefs-buttons { + padding-left: 16px; } .oo-ui-window-body .oo-ui-fieldLayout-messages { @@ -271,7 +309,9 @@ with params ?useskin=vector&useformat=mobile .oo-ui-iconWidget.mw-prefs-header-icon { color: @colorGray2; cursor: pointer; - margin: 0.25em 0.5em; + width: 1.25em; + height: 1.25em; + margin: 0 16px 0 17px; } .mw-prefs-header-title { |