[Technical] Separate Dropdown template into 3 templates

Use the new format to remove the need for getTemplateParser
in SkinVector

Bug: T319349
Change-Id: Ic4ac1d6d58099a689c29c16b3029bf43a849e50e
This commit is contained in:
Jon Robson 2022-11-02 16:00:04 -07:00 committed by Jdlrobson
parent e76948f4ed
commit c9cdaadb5e
10 changed files with 85 additions and 64 deletions

View file

@ -221,14 +221,14 @@ abstract class SkinVector extends SkinMustache {
* @param bool $isTempUser
* @param bool $includeLearnMoreLink Pass `true` to include the learn more
* link in the menu for anon users. This param will be inert for temp users.
* @return string
* @return array
*/
private function getAnonMenuBeforePortletHTML(
private function getAnonMenuBeforePortletData(
$returnto,
$useCombinedLoginLink,
$isTempUser,
$includeLearnMoreLink
) {
): array {
$templateParser = $this->getTemplateParser();
$loginLinkData = array_merge( $this->buildLoginData( $returnto, $useCombinedLoginLink ), [
'class' => [ 'vector-menu-content-item', 'vector-menu-content-item-login' ],
@ -240,8 +240,6 @@ abstract class SkinVector extends SkinMustache {
'data-anon-editor' => []
];
$templateName = $isTempUser ? 'UserLinks__templogin' : 'UserLinks__login';
if ( !$isTempUser && $includeLearnMoreLink ) {
$learnMoreLinkData = [
'text' => $this->msg( 'vector-anon-user-menu-pages-learn' )->text(),
@ -255,7 +253,7 @@ abstract class SkinVector extends SkinMustache {
];
}
return $templateParser->processTemplate( $templateName, $templateData );
return $templateData;
}
/**
@ -263,16 +261,11 @@ abstract class SkinVector extends SkinMustache {
* after the menu itself.
* @return string
*/
private function getLogoutHTML() {
private function getLogoutHTML(): string {
$logoutLinkData = array_merge( $this->buildLogoutLinkData(), [
'class' => [ 'vector-menu-content-item', 'vector-menu-content-item-logout' ],
] );
$logoutLinkData = Hooks::updateLinkData( $logoutLinkData );
$templateParser = $this->getTemplateParser();
return $templateParser->processTemplate( 'UserLinks__logout', [
'htmlLogout' => $this->makeLink( 'logout', $logoutLinkData )
] );
return $this->makeLink( 'logout', Hooks::updateLinkData( $logoutLinkData ) );
}
/**
@ -296,7 +289,7 @@ abstract class SkinVector extends SkinMustache {
unset( $userMenuOverflowData[ 'label' ] );
if ( $isAnon || $isTempUser ) {
$userMenuData[ 'html-before-portal' ] .= $this->getAnonMenuBeforePortletHTML(
$additionalData = $this->getAnonMenuBeforePortletData(
$returnto,
$useCombinedLoginLink,
$isTempUser,
@ -308,12 +301,13 @@ abstract class SkinVector extends SkinMustache {
!$userMenuData['is-empty']
);
} else {
// Appending as to not override data potentially set by the onSkinAfterPortlet hook.
$userMenuData[ 'html-after-portal' ] .= $this->getLogoutHTML();
$additionalData = [];
}
$moreItems = substr_count( $userMenuOverflowData['html-items'], '<li' );
return [
return $additionalData + [
'html-logout-link' => $this->getLogoutHTML(),
'is-temp-user' => $isTempUser,
'is-wide' => $moreItems > 3,
'data-user-menu-overflow' => $userMenuOverflowData,
'data-user-menu' => $userMenuData

View file

@ -1,32 +1,5 @@
{{!
See @typedef MenuDefinition
}}
<div id="{{id}}" class="vector-menu vector-menu-dropdown{{#class}} {{.}}{{/class}}" {{{html-tooltip}}} {{{html-user-language-attributes}}}>
{{!
Dropdown menus use the checkbox hack and require `input` and `label` elements.
`aria-label` is applied to the `input` which is semantically a button.
The `label` element is used as a visual button.
}}
<input type="checkbox"
id="{{id}}-checkbox"
role="button"
aria-haspopup="true"
data-event-name="ui.dropdown-{{id}}"
class="vector-menu-checkbox{{#checkbox-class}} {{.}}{{/checkbox-class}}"
{{#aria-label}}aria-label="{{.}}"{{/aria-label}}
{{{html-vector-menu-checkbox-attributes}}}
/>
<label
id="{{id}}-label"
for="{{id}}-checkbox"
class="vector-menu-heading{{#heading-class}} {{.}}{{/heading-class}}"
{{{html-vector-menu-heading-attributes}}}
>
{{{html-vector-heading-icon}}}<span class="vector-menu-heading-label">{{label}}</span>
</label>
<div class="vector-menu-content">
{{>Dropdown/Open}}
{{{html-before-portal}}}
<ul class="vector-menu-content-list">{{{html-items}}}</ul>
{{{html-after-portal}}}
</div>
</div>
{{>Dropdown/Close}}

View file

@ -0,0 +1,3 @@
{{! this template must be used with Dropdown/Open to avoid unclosed HTML tags }}
</div>
</div>

View file

@ -0,0 +1,29 @@
{{!
See @typedef MenuDefinition
}}
{{! this template must be used with Dropdown/Close to avoid unclosed HTML tags }}
<div id="{{id}}" class="vector-menu vector-menu-dropdown{{#class}} {{.}}{{/class}}" {{{html-tooltip}}} {{{html-user-language-attributes}}}>
{{!
Dropdown menus use the checkbox hack and require `input` and `label` elements.
`aria-label` is applied to the `input` which is semantically a button.
The `label` element is used as a visual button.
}}
<input type="checkbox"
id="{{id}}-checkbox"
role="button"
aria-haspopup="true"
data-event-name="ui.dropdown-{{id}}"
class="vector-menu-checkbox{{#checkbox-class}} {{.}}{{/checkbox-class}}"
{{#aria-label}}aria-label="{{.}}"{{/aria-label}}
{{{html-vector-menu-checkbox-attributes}}}
/>
<label
id="{{id}}-label"
for="{{id}}-checkbox"
class="vector-menu-heading{{#heading-class}} {{.}}{{/heading-class}}"
{{{html-vector-menu-heading-attributes}}}
>
{{{html-vector-heading-icon}}}<span class="vector-menu-heading-label">{{label}}</span>
</label>
<div class="vector-menu-content">

View file

@ -1,4 +1,23 @@
<nav class="vector-user-links{{#is-wide}} vector-user-links-wide{{/is-wide}}" aria-label="{{msg-personaltools}}" role="navigation" >
{{#data-user-menu-overflow}}{{>Menu}}{{/data-user-menu-overflow}}
{{#data-user-menu}}{{>Dropdown}}{{/data-user-menu}}
{{#data-user-menu}}
{{>Dropdown/Open}}
{{#is-anon}}
{{#is-temp-user}}
{{>UserLinks__templogin}}
{{/is-temp-user}}
{{^is-temp-user}}
{{>UserLinks__login}}
{{/is-temp-user}}
{{/is-anon}}
<ul class="vector-menu-content-list">{{{html-items}}}</ul>
{{^is-anon}}
{{!-- The #pt-logout ID is required for the AJAX enabled logout in mediawiki.page.ready to work.}}
<div id="pt-logout" class="vector-user-menu-logout">
{{{html-logout-link}}}
</div>
{{/is-anon}}
{{>Dropdown/Close}}
{{/data-user-menu}}
</nav>

View file

@ -1,4 +0,0 @@
{{!-- The #pt-logout ID is required for the AJAX enabled logout in mediawiki.page.ready to work.}}
<div id="pt-logout" class="vector-user-menu-logout">
{{{htmlLogout}}}
</div>

View file

@ -18,12 +18,12 @@ exports[`Sticky header renders 1`] = `
<span class=\\"vector-menu-heading-label\\"></span>
</label>
<div class=\\"vector-menu-content\\">
<ul class=\\"vector-menu-content-list\\"></ul>
</div>
</div>
</div>
</div> </div>
<div class=\\"vector-sticky-header-context-bar-primary\\"></div>
</div>
</div>

View file

@ -2,13 +2,14 @@
exports[`UserLinks renders 1`] = `
"<nav class=\\"vector-user-links\\" aria-label=\\"\\" role=\\"navigation\\">
<div id=\\"p-personal\\" class=\\"vector-menu vector-menu-dropdown mw-portlet mw-portlet-personal vector-user-menu vector-user-menu-logged-in vector-menu-dropdown\\">
<input type=\\"checkbox\\" id=\\"p-personal-checkbox\\" role=\\"button\\" aria-haspopup=\\"true\\" data-event-name=\\"ui.dropdown-p-personal\\" class=\\"vector-menu-checkbox\\">
<label id=\\"p-personal-label\\" for=\\"p-personal-checkbox\\" class=\\"vector-menu-heading\\">
<span class=\\"vector-menu-heading-label\\">Personal tools</span>
</label>
<div class=\\"vector-menu-content\\">
<ul class=\\"vector-menu-content-list\\">
<li id=\\"pt-userpage\\" class=\\"user-links-collapsible-item mw-list-item\\"><a class=\\"mw-ui-icon mw-ui-icon-before mw-ui-icon-userAvatar mw-ui-icon-wikimedia-userAvatar\\" href=\\"/wiki/User:Admin\\" title=\\"Your user page [.]\\" accesskey=\\".\\"><span>Admin</span></a></li>
<li id=\\"pt-mytalk\\" class=\\"mw-list-item\\"><a class=\\"mw-ui-icon mw-ui-icon-before mw-ui-icon-userTalk mw-ui-icon-wikimedia-userTalk\\" href=\\"/wiki/User_talk:Admin\\" title=\\"Your talk page [n]\\" accesskey=\\"n\\"><span>Talk</span></a></li>
@ -20,9 +21,10 @@ exports[`UserLinks renders 1`] = `
<li id=\\"pt-mycontris\\" class=\\"mw-list-item\\"><a class=\\"mw-ui-icon mw-ui-icon-before mw-ui-icon-userContributions mw-ui-icon-wikimedia-userContributions\\" href=\\"/wiki/Special:Contributions/Admin\\" title=\\"A list of your contributions [y]\\" accesskey=\\"y\\"><span>Contributions</span></a></li>
<li id=\\"pt-custom\\" class=\\"mw-list-item mw-list-item-js\\">Gadget added item</li>
</ul>
<div id=\\"pt-logout\\" class=\\"vector-user-menu-logout\\">
</div>
</div>
</div>
</nav>
</div></nav>
"
`;

View file

@ -3,9 +3,8 @@ const fs = require( 'fs' );
const tocContainerTemplate = fs.readFileSync( 'includes/templates/TableOfContentsContainer.mustache', 'utf8' );
const stickyHeaderTemplate = fs.readFileSync( 'includes/templates/StickyHeader.mustache', 'utf8' );
const buttonTemplate = fs.readFileSync( 'includes/templates/Button.mustache', 'utf8' );
const dropdownTemplate = fs.readFileSync( 'includes/templates/Dropdown.mustache', 'utf8' );
const sticky = require( '../../resources/skins.vector.es6/stickyHeader.js' );
const { userLinksHTML } = require( './userLinksData.js' );
const { userLinksHTML, dropdownPartials } = require( './userLinksData.js' );
const defaultButtonsTemplateData = [ {
href: '#',
@ -89,11 +88,10 @@ const templateData = {
'data-buttons': defaultButtonsTemplateData.concat( editButtonsTemplateData )
};
const renderedHTML = mustache.render( stickyHeaderTemplate, templateData, {
const renderedHTML = mustache.render( stickyHeaderTemplate, templateData, Object.assign( {}, dropdownPartials, {
Button: buttonTemplate,
Dropdown: dropdownTemplate,
SearchBox: '<div> </div>' // ignore SearchBox for this test
} );
} ) );
beforeEach( () => {
document.body.innerHTML = renderedHTML;

View file

@ -2,6 +2,8 @@ const mustache = require( 'mustache' );
const fs = require( 'fs' );
const userLinksTemplate = fs.readFileSync( 'includes/templates/UserLinks.mustache', 'utf8' );
const dropdownTemplate = fs.readFileSync( 'includes/templates/Dropdown.mustache', 'utf8' );
const dropdownOpenTemplate = fs.readFileSync( 'includes/templates/Dropdown/Open.mustache', 'utf8' );
const dropdownCloseTemplate = fs.readFileSync( 'includes/templates/Dropdown/Close.mustache', 'utf8' );
const templateData = {
'is-wide': false,
@ -35,10 +37,15 @@ const templateData = {
}
};
const renderedHTML = mustache.render( userLinksTemplate, templateData, {
const dropdownPartials = {
'Dropdown/Open': dropdownOpenTemplate,
'Dropdown/Close': dropdownCloseTemplate,
Dropdown: dropdownTemplate
} );
};
const renderedHTML = mustache.render( userLinksTemplate, templateData, dropdownPartials );
module.exports = {
dropdownPartials,
userLinksHTML: renderedHTML
};