Merge "Add edit icons to sticky header"

This commit is contained in:
jenkins-bot 2021-10-05 23:49:35 +00:00 committed by Gerrit Code Review
commit 29b35c25ac
6 changed files with 169 additions and 26 deletions

View File

@ -1,7 +1,7 @@
[
{
"resourceModule": "skins.vector.styles.legacy",
"maxSize": "7.8 kB"
"maxSize": "7.9 kB"
},
{
"resourceModule": "skins.vector.styles",

View File

@ -68,6 +68,30 @@ class SkinVector extends SkinMustache {
'tabindex' => '-1',
'class' => 'sticky-header-icon'
];
private const EDIT_VE_ICON = [
'href' => '#',
'id' => 'ca-ve-edit-sticky-header',
'event' => 've-edit-sticky-header',
'icon' => 'wikimedia-edit',
'is-quiet' => true,
'class' => 'sticky-header-icon'
];
private const EDIT_WIKITEXT_ICON = [
'href' => '#',
'id' => 'ca-edit-sticky-header',
'event' => 'wikitext-edit-sticky-header',
'icon' => 'wikimedia-wikiText',
'is-quiet' => true,
'class' => 'sticky-header-icon'
];
private const EDIT_PROTECTED_ICON = [
'href' => '#',
'id' => 'ca-viewsource-sticky-header',
'event' => 've-edit-protected-sticky-header',
'icon' => 'wikimedia-editLock',
'is-quiet' => true,
'class' => 'sticky-header-icon'
];
private const SEARCH_EXPANDING_CLASS = 'vector-search-box-show-thumbnail';
private const STICKY_HEADER_ENABLED_CLASS = 'vector-sticky-header-enabled';
@ -353,7 +377,7 @@ class SkinVector extends SkinMustache {
* @param array $searchBoxData
* @return array
*/
private function getStickyHeaderData( $searchBoxData ) {
private function getStickyHeaderData( $searchBoxData ): array {
return [
'data-primary-action' => !$this->shouldHideLanguages() ? $this->getULSButtonData() : null,
'data-button-start' => [
@ -365,7 +389,11 @@ class SkinVector extends SkinMustache {
],
'data-search' => $searchBoxData,
'data-buttons' => [
self::TALK_ICON, self::HISTORY_ICON, self::NO_ICON, self::NO_ICON
self::TALK_ICON,
self::HISTORY_ICON,
self::EDIT_VE_ICON,
self::EDIT_PROTECTED_ICON,
self::EDIT_WIKITEXT_ICON
]
];
}

View File

@ -22,6 +22,7 @@
"Element": "https://developer.mozilla.org/docs/Web/API/Element",
"Event": "https://developer.mozilla.org/docs/Web/API/Event",
"HTMLElement": "https://developer.mozilla.org/docs/Web/API/HTMLElement",
"Node": "https://developer.mozilla.org/docs/Web/API/Node",
"NodeList": "https://developer.mozilla.org/docs/Web/API/NodeList",
"HTMLInputElement": "https://developer.mozilla.org/docs/Web/API/HTMLInputElement",
"\"removeEventListener\"": "https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener",

View File

@ -7,8 +7,7 @@ var
FIRST_HEADING_ID = 'firstHeading',
USER_MENU_ID = 'p-personal',
VECTOR_USER_LINKS_SELECTOR = '.vector-user-links',
SEARCH_TOGGLE_SELECTOR = '.vector-sticky-header-search-toggle',
OTHER_STICKY_ELEMENT_SELECTORS = '.charts-stickyhead th';
SEARCH_TOGGLE_SELECTOR = '.vector-sticky-header-search-toggle';
/**
* Copies attribute from an element to another.
@ -48,6 +47,23 @@ function makeNodeTrackable( node ) {
suffixStickyAttribute( node, 'data-event-name' );
}
/**
*
* @param {null|HTMLElement|Node} node
* @return {HTMLElement}
*/
function toHTMLElement( node ) {
// @ts-ignore
return node;
}
/**
* @param {HTMLElement} node
*/
function removeNode( node ) {
toHTMLElement( node.parentNode ).removeChild( node );
}
/**
* Makes sticky header icons functional for modern Vector.
*
@ -77,6 +93,76 @@ function prepareIcons( header, history, talk ) {
}
}
/**
* Render sticky header edit or protected page icons for modern Vector.
*
* @param {HTMLElement} header
* @param {HTMLElement|null} primaryEdit
* @param {boolean} isProtected
* @param {HTMLElement|null} secondaryEdit
*/
function prepareEditIcons(
header,
primaryEdit,
isProtected,
secondaryEdit
) {
var
primaryEditSticky = toHTMLElement(
header.querySelector(
'#ca-ve-edit-sticky-header'
)
),
protectedSticky = toHTMLElement(
header.querySelector(
'#ca-viewsource-sticky-header'
)
),
wikitextSticky = toHTMLElement(
header.querySelector(
'#ca-edit-sticky-header'
)
);
if ( !primaryEdit ) {
removeNode( protectedSticky );
removeNode( wikitextSticky );
removeNode( primaryEditSticky );
return;
} else if ( isProtected ) {
removeNode( wikitextSticky );
removeNode( primaryEditSticky );
copyAttribute( primaryEdit, protectedSticky, 'href' );
copyAttribute( primaryEdit, protectedSticky, 'title' );
} else {
removeNode( protectedSticky );
copyAttribute( primaryEdit, primaryEditSticky, 'href' );
copyAttribute( primaryEdit, primaryEditSticky, 'title' );
if ( secondaryEdit ) {
copyAttribute( secondaryEdit, wikitextSticky, 'href' );
copyAttribute( secondaryEdit, wikitextSticky, 'title' );
} else {
removeNode( wikitextSticky );
}
}
}
/**
* Check if element is in viewport.
*
* @param {HTMLElement} element
* @return {boolean}
*/
function isInViewport( element ) {
var rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= ( window.innerHeight || document.documentElement.clientHeight ) &&
rect.right <= ( window.innerWidth || document.documentElement.clientWidth )
);
}
/**
* Makes sticky header functional for modern Vector.
*
@ -136,13 +222,42 @@ function makeStickyHeaderFunctional(
document.querySelector( '#ca-talk a' )
);
// Apply offset for other sticky elements on page if applicable.
var otherStickyElements = document.querySelectorAll( OTHER_STICKY_ELEMENT_SELECTORS );
Array.prototype.forEach.call( otherStickyElements, function ( el ) {
el.classList.add( 'mw-sticky-header-element' );
} );
var veEdit = document.querySelector( '#ca-ve-edit a' );
var ceEdit = document.querySelector( '#ca-edit a' );
var protectedEdit = document.querySelector( '#ca-viewsource a' );
var isProtected = !!protectedEdit;
var primaryEdit = protectedEdit || ( veEdit || ceEdit );
var secondaryEdit = veEdit ? ceEdit : null;
prepareEditIcons(
header,
toHTMLElement( primaryEdit ),
isProtected,
toHTMLElement( secondaryEdit )
);
stickyObserver.observe( stickyIntersection );
// When Visual Editor is activated, hide sticky header.
mw.hook( 've.activationComplete' ).add( function () {
// eslint-disable-next-line mediawiki/class-doc
header.classList.remove( STICKY_HEADER_VISIBLE_CLASS );
stickyObserver.unobserve( stickyIntersection );
} );
// When Visual Editor is deactivated, by cliking "read" tab at top of page, show sticky header.
mw.hook( 've.deactivationComplete' ).add( function () {
stickyObserver.observe( stickyIntersection );
} );
// After saving edits, re-apply the sticky header if the target is not in the viewport.
mw.hook( 'postEdit.afterRemoval' ).add( function () {
if ( !isInViewport( stickyIntersection ) ) {
// eslint-disable-next-line mediawiki/class-doc
header.classList.add( STICKY_HEADER_VISIBLE_CLASS );
stickyObserver.observe( stickyIntersection );
}
} );
}
/**

View File

@ -56,31 +56,26 @@
//
// Layout
//
&-start {
&-start,
&-end,
&-icons,
&-context-bar {
display: flex;
align-items: center;
flex-grow: 1;
}
&-end {
display: flex;
align-items: center;
&-start {
flex-grow: 1;
}
//
// Components
//
&-icons,
&-context-bar {
display: flex;
align-items: center;
white-space: nowrap;
margin: 0 15px;
padding-left: 30px;
}
&-context-bar {
border-left: 1px solid #c8c8c8;
margin: 0 15px;
padding-left: 30px;
white-space: nowrap;
}
&-context-bar-primary {
@ -147,7 +142,8 @@
// T289817 Override other sticky element offsets to ensure that other
// sticky elements (i.e. table headers) appear below the sticky header.
.mw-sticky-header-element {
.mw-sticky-header-element,
.charts-stickyhead th {
/* stylelint-disable-next-line declaration-no-important */
top: @height-sticky-header !important;
}

View File

@ -176,7 +176,10 @@
"variants": [],
"icons": [
"history",
"speechBubbles"
"speechBubbles",
"edit",
"editLock",
"wikiText"
]
},
"skins.vector.icons": {