Merge "[feature] add menu button to toggle panel visibility"

This commit is contained in:
jenkins-bot 2020-05-28 02:57:14 +00:00 committed by Gerrit Code Review
commit 15a30c26f8
15 changed files with 272 additions and 14 deletions

View File

@ -10,6 +10,7 @@
"vector-opt-out-tooltip": "Change your settings to go back to the old look of the skin (legacy Vector)",
"vector.css": "/* All CSS here will be loaded for users of the Vector skin */",
"vector.js": "/* All JavaScript here will be loaded for users of the Vector skin */",
"vector-action-toggle-sidebar": "Toggle sidebar",
"vector-action-addsection": "Add topic",
"vector-action-delete": "Delete",
"vector-action-move": "Move",

View File

@ -21,6 +21,7 @@
"vector-opt-out-tooltip": "Used as the tooltip for the Vector opt-out link",
"vector.css": "{{optional}}",
"vector.js": "{{optional}}",
"vector-action-toggle-sidebar": "Accessibility label for the button that toggles the sidebar's visibility, as well as audible presentation for screen readers.",
"vector-action-addsection": "Used in the Vector skin. See for example {{canonicalurl:Talk:Main_Page|useskin=vector}}\n{{Identical|Add topic}}",
"vector-action-delete": "Used in the Vector skin, as the name of a tab at the top of the page. See for example {{canonicalurl:Translating:MediaWiki|useskin=vector}}\n\n{{Identical|Delete}}",
"vector-action-move": "Used in the Vector skin, on the tabs at the top of the page. See for example {{canonicalurl:Talk:Main_Page|useskin=vector}}\n\n{{Identical|Move}}",

View File

@ -80,11 +80,17 @@ class SkinVector extends SkinTemplate {
*/
public function getDefaultModules() {
$modules = parent::getDefaultModules();
// add vector skin styles and vector module
$module = $this->isLegacy()
? 'skins.vector.styles.legacy' : 'skins.vector.styles';
$modules['styles']['skin'][] = $module;
$modules['core'][] = $this->isLegacy() ? 'skins.vector.legacy.js' : 'skins.vector.js';
if ( $this->isLegacy() ) {
$modules['styles']['skin'][] = 'skins.vector.styles.legacy';
$modules[Constants::SKIN_NAME] = 'skins.vector.legacy.js';
} else {
$modules['styles'] = array_merge(
$modules['styles'],
[ 'skins.vector.styles', 'mediawiki.ui.icon', 'skins.vector.icons' ]
);
$modules[Constants::SKIN_NAME][] = 'skins.vector.js';
}
return $modules;
}

View File

@ -371,6 +371,9 @@ class VectorTemplate extends BaseTemplate {
),
'array-portals-rest' => array_slice( $props, 1 ),
'data-portals-first' => $firstPortal,
'msg-toggle-sidebar-button-label' => $this->msg( 'vector-action-toggle-sidebar' )->text(),
// [todo] fetch user preference when logged in (T246427).
'sidebar-visible' => false
];
}

View File

@ -7,9 +7,33 @@
MenuDefinition data-portals-first
MenuDefinition[] array-portals-rest
emphasized-sidebar-action data-emphasized-sidebar-action For displaying an emphasized action in the sidebar.
string msg-toggle-sidebar-button-label The label used by the sidebar button.
boolean sidebar-visible For users that want to see the sidebar on initial render, this should be
true.
}}
<div id="mw-panel" class="mw-sidebar">
<input
type="checkbox"
id="mw-sidebar-checkbox"
class="mw-checkbox-hack-checkbox"
role="button"
{{#sidebar-visible}}checked{{/sidebar-visible}}
aria-labelledby="mw-sidebar-button"
aria-controls="mw-panel">
<label
id="mw-sidebar-button"
class="
mw-checkbox-hack-button
mw-ui-icon
mw-ui-icon-element
{{#sidebar-visible}}mw-ui-icon-wikimedia-collapseHorizontal-base20{{/sidebar-visible}}
{{^sidebar-visible}}mw-ui-icon-wikimedia-menu-base20{{/sidebar-visible}}
"
for="mw-sidebar-checkbox"
data-event-name="ui.sidebar">
{{msg-toggle-sidebar-button-label}}
</label>
<div id="mw-panel" class="mw-sidebar mw-checkbox-hack-target">
{{#data-portals-first}}{{>Menu}}{{/data-portals-first}}
{{#data-emphasized-sidebar-action}}
<div class="mw-sidebar-action">

View File

@ -14,6 +14,21 @@
"cleverLinks": true,
"default": {
"useLongnameInNav": true
},
"wmf": {
"linkMap": {
"Document": "https://developer.mozilla.org/docs/Web/API/Document",
"HTMLElement": "https://developer.mozilla.org/docs/Web/API/HTMLElement",
"HTMLInputElement": "https://developer.mozilla.org/docs/Web/API/HTMLInputElement",
"Window": "https://developer.mozilla.org/docs/Web/API/Window",
"CheckboxHack": "https://doc.wikimedia.org/mediawiki-core/master/js",
"MW": "https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw",
"JQueryStatic": "https://api.jquery.com",
"void": "#"
}
}
}
}

16
resources/CheckboxHack.d.ts vendored Normal file
View File

@ -0,0 +1,16 @@
interface CheckboxHack {
updateAriaExpanded(checkbox: HTMLInputElement): void;
bindUpdateAriaExpandedOnInput(checkbox: HTMLInputElement): CheckboxHackListeners;
bindToggleOnClick(checkbox: HTMLInputElement, button: HTMLElement): CheckboxHackListeners;
bindDismissOnClickOutside(window: Window, checkbox: HTMLInputElement, button: HTMLElement, target: Node): CheckboxHackListeners;
bindDismissOnFocusLoss(window: Window, checkbox: HTMLInputElement, button: HTMLElement, target: Node): CheckboxHackListeners;
bind(window: Window, checkbox: HTMLInputElement, button: HTMLElement, target: Node): CheckboxHackListeners;
unbind(window: Window, checkbox: HTMLInputElement, button: HTMLElement, listeners: CheckboxHackListeners): void;
}
interface CheckboxHackListeners {
onUpdateAriaExpandedOnInput?: EventListenerOrEventListenerObject;
onToggleOnClick?: EventListenerOrEventListenerObject;
onDismissOnClickOutside?: EventListenerOrEventListenerObject;
onDismissOnFocusLoss?: EventListenerOrEventListenerObject;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
<title>
collapse
</title>
<path d="M9 2l1.3 1.3L3.7 10l6.6 6.7L9 18l-8-8 8-8zm8.5 0L19 3.3 12.2 10l6.7 6.7-1.4 1.3-8-8 8-8z"/>
</svg>

After

Width:  |  Height:  |  Size: 261 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>menu</title><path d="M1 3v2h18V3zm0 8h18V9H1zm0 6h18v-2H1z"/></svg>

After

Width:  |  Height:  |  Size: 195 B

View File

@ -1,10 +1,56 @@
var
collapsibleTabs = require( '../skins.vector.legacy.js/collapsibleTabs.js' ),
vector = require( '../skins.vector.legacy.js/vector.js' );
/** @type {CheckboxHack} */ var checkboxHack =
require( /** @type {string} */ ( 'mediawiki.page.ready' ) ).checkboxHack;
var collapsibleTabs = require( '../skins.vector.legacy.js/collapsibleTabs.js' );
var vector = require( '../skins.vector.legacy.js/vector.js' );
function main() {
collapsibleTabs.init();
$( vector.init );
/**
* Update the state of the menu icon to be an expanded or collapsed icon.
* @param {HTMLInputElement} checkbox
* @param {HTMLElement} button
* @return {void}
*/
function updateMenuIcon( checkbox, button ) {
button.classList.remove(
checkbox.checked ?
'mw-ui-icon-wikimedia-menu-base20' :
'mw-ui-icon-wikimedia-collapseHorizontal-base20'
);
button.classList.add(
checkbox.checked ?
'mw-ui-icon-wikimedia-collapseHorizontal-base20' :
'mw-ui-icon-wikimedia-menu-base20'
);
}
main();
/**
* Improve the interactivity of the sidebar panel by binding optional checkbox hack enhancements
* for focus and `aria-expanded`. Also, flip the icon image on click.
* @param {Document} document
* @return {void}
*/
function initSidebar( document ) {
var checkbox = document.getElementById( 'mw-sidebar-checkbox' );
var button = document.getElementById( 'mw-sidebar-button' );
if ( checkbox instanceof HTMLInputElement && button ) {
checkboxHack.bindToggleOnClick( checkbox, button );
checkboxHack.bindUpdateAriaExpandedOnInput( checkbox );
button.addEventListener( 'click', updateMenuIcon.bind( undefined, checkbox, button ) );
checkbox.addEventListener( 'input', updateMenuIcon.bind( undefined, checkbox, button ) );
checkboxHack.updateAriaExpanded( checkbox );
updateMenuIcon( checkbox, button );
}
}
/**
* @param {Window} window
* @return {void}
*/
function main( window ) {
collapsibleTabs.init();
$( vector.init );
initSidebar( window.document );
}
main( window );

View File

@ -1,5 +1,6 @@
@import '../../variables.less';
@import 'mediawiki.mixins.less';
@import './layout.less';
.mw-logo {
.flex-display();
@ -8,6 +9,8 @@
height: 100%;
// Center vertically.
align-items: center;
// Make room for the sidebar menu button.
margin-left: @size-sidebar-button;
}
.mw-logo-icon {

View File

@ -1,5 +1,8 @@
@import '../../variables.less';
@import 'mediawiki.mixins.less';
@import './layout.less';
@import 'legacy/Sidebar.less';
@import 'checkboxHack.less';
.mw-sidebar-action {
// Align with the portal heading/links
@ -11,3 +14,67 @@
font-size: @font-size-portal-list-item;
font-weight: bold;
}
// FIXME please add a class, .mw-navigation, and use that instead of this identifier.
#mw-navigation {
.mw-checkbox-hack-checkbox,
.mw-checkbox-hack-button {
// The icon is only 44px tall but the header is 50px. Offset by the difference from the logo
// icon and center with respect to the header.
top: @height-logo-icon - @size-sidebar-button + ( @height-header - @height-logo-icon ) / 2;
// Some made up value to be revised by Alex.
left: 10px;
}
.mw-checkbox-hack-button {
position: absolute;
z-index: @z-index-sidebar-button;
// Override minimum dimensions set by mw-ui-icon.mw-ui-icon-element.
min-width: @size-sidebar-button;
min-height: @size-sidebar-button;
width: @size-sidebar-button;
height: @size-sidebar-button;
border: 1px solid transparent;
border-radius: @border-radius-base;
&:before {
// Center it.
margin: 12px;
// FIXME: the icon itself is supposed to be 20px. mediawiki.ui uses 24px.
// As soon as mediawiki.ui is standardized, remove this override. See T191021.
min-height: 20px;
opacity: 0.87;
}
&:hover {
background-color: @background-color-frameless--hover;
}
.transition( background-color @transition-duration-base, border-color @transition-duration-base, box-shadow @transition-duration-base; );
}
.mw-checkbox-hack-checkbox:focus ~ .mw-checkbox-hack-button {
// Next two rules from OOUI, frameless, icon-only button widget.
border-color: @color-primary;
.box-shadow( inset 0 0 0 1px @color-primary );
}
// Use the MediaWiki checkbox hack class from checkboxHack.less. This class exists on the
// checkbox input for the menu panel.
.mw-checkbox-hack-checkbox:not( :checked ) ~ .mw-sidebar {
// Turn off presentation so that screen readers get the same effect as visually hiding.
// Visibility and opacity can be animated. If animation is unnecessary, use `display: none`
// instead to avoid hidden rendering.
visibility: hidden;
opacity: 0;
.transform( translateX( -100% ) );
}
}
.mw-sidebar {
// Enable animations on desktop width only.
@media ( min-width: @width-breakpoint-desktop ) {
@timing: @transition-duration-base ease-out;
.transition( transform @timing, opacity @timing, visibility @timing; );
}
}

View File

@ -0,0 +1,48 @@
// This file is being considered for Core as part of T252774.
// Notes:
//
// - Usage requires three elements: a hidden checkbox input, a button, and a show / hide target.
// - By convention, the checked state is considered expanded or visible. Unchecked is considered
// hidden.
// - Please see additional documentation in checkboxHack.js for example HTML and JavaScript
// integration.
//
// Example supplemental styles (to be added on a per use case basis):
//
// - Animate target in and out from start (left in LTR) to end (right in LTR):
//
// .mw-checkbox-hack-checkbox:not( :checked ) ~ .mw-checkbox-hack-target {
// // Turn off presentation so that screen readers get the same effect as visually
// // hiding. Visibility and opacity can be animated. If animation is unnecessary, all
// // of this can be replaced with `display: none` instead to avoid hidden rendering.
// visibility: hidden;
// opacity: 0;
// @timing: @transition-duration-base ease-in-out;
// .transition( transform @timing, opacity @timing, visibility @timing; );
// .transform( translateX( -100% ) );
// }
//
// - Show / hide the target instantly without animation:
//
// .mw-checkbox-hack-checkbox:not( :checked ) ~ .mw-checkbox-hack-target {
// display: none;
// }
@import 'mediawiki.ui/variables.less';
@import 'mediawiki.mixins.less';
.mw-checkbox-hack-checkbox {
position: absolute;
// Always lower the checkbox behind the foreground content.
z-index: -1;
// The checkbox `display` cannot be `none` since its focus state is used for other selectors.
opacity: 0;
}
.mw-checkbox-hack-button {
// Labels are inlined by default but are also an icon having width and height specified.
display: inline-block;
// Use the hand icon for the toggle button which is actually a checkbox label.
cursor: pointer;
}

View File

@ -58,6 +58,15 @@
],
"styles": [ "resources/skins.vector.styles/index.less" ]
},
"skins.vector.icons": {
"class": "ResourceLoaderImageModule",
"selector": ".mw-ui-icon-wikimedia-{name}-base20:before",
"defaultColor": "#54595d",
"images": {
"menu": "resources/skins.vector.icons/menu.svg",
"collapseHorizontal": "resources/skins.vector.icons/collapseHorizontal.svg"
}
},
"skins.vector.styles.responsive": {
"targets": [
"desktop",
@ -72,7 +81,8 @@
"resources/skins.vector.legacy.js/vector.js"
],
"dependencies": [
"mediawiki.util"
"mediawiki.util",
"mediawiki.page.ready"
]
},
"skins.vector.legacy.js": {

View File

@ -43,6 +43,10 @@
@color-link-new: #a55858;
@color-link-selected: @color-base;
// See oojs/ui/src/themes/wikimediaui/common.less.
@background-color-frameless--hover: rgba( 0, 24, 73, 7/255 ); // equivalent to @wmui-color-base90 on white
@color-primary: #36c; // wikimedia-ui-base.less
@font-size-base: unit( 14 / @font-size-browser, em ); // Equals `0.875em`.
@font-size-reset: @font-size-root;
@font-size-heading-1: 1.8em;
@ -125,8 +129,14 @@
// @z-index-ui-slider-handle: 2;
// Display on top of page tabs (T39158, T50078).
@z-index-personal: 100;
@z-index-sidebar-button: 101;
// See skinStyles/jquery.ui/jquery.ui.selectable.css.
// @z-index-ui-selectable-helper: 100;
@z-index-overlay: 101;
// See skinStyles/jquery.ui/jquery.ui.tooltip.css.
// @z-index-ui-tooltip: 9999;
// Transitions
@transition-duration-base: 100ms;
@size-sidebar-button: 2.75em; // 44px