Merge "[feature] add menu button to toggle panel visibility"
This commit is contained in:
commit
15a30c26f8
|
@ -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",
|
||||
|
|
|
@ -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}}",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
15
jsdoc.json
15
jsdoc.json
|
@ -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": "#"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 |
|
@ -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 |
|
@ -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 );
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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; );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
12
skin.json
12
skin.json
|
@ -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": {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue