diff --git a/includes/Hooks.php b/includes/Hooks.php index 3f09e0b..d21b2b4 100644 --- a/includes/Hooks.php +++ b/includes/Hooks.php @@ -154,7 +154,7 @@ class Hooks { unset( $content_navigation['user-menu']['anonuserpage'] ); // Create account is pulled out into its own button. unset( $content_navigation['user-menu']['createaccount'] ); - // "Login" link is handled by UserMenu + // "Login" link is handled manually by Vector unset( $content_navigation['user-menu']['login'] ); } // Prefix user link items with associated icon. diff --git a/includes/SkinVector.php b/includes/SkinVector.php index 96219aa..92a8465 100644 --- a/includes/SkinVector.php +++ b/includes/SkinVector.php @@ -170,6 +170,71 @@ class SkinVector extends SkinMustache { ); } + /** + * Returns HTML for the create account button inside the anon user links + * @param string[] $returnto array of query strings used to build the login link + * @return string + */ + private function getCreateAccountHTML( $returnto ) { + $createAccountData = $this->buildCreateAccountData( $returnto ); + $createAccountData['single-id'] = 'pt-createaccount'; + $createAccountData['class'] = 'mw-ui-button mw-ui-quiet'; + $htmlCreateAccount = $this->makeLink( 'create-account', $createAccountData ); + + return $htmlCreateAccount; + } + + /** + * Returns HTML for the login button and learn more link inside the anon user menu + * @param string[] $returnto array of query strings used to build the login link + * @param bool $useCombinedLoginLink if a combined login/signup link will be used + * @return string + */ + private function getLoginHTML( $returnto, $useCombinedLoginLink ) { + // 'single-id' must be provided for `makeLink` to populate `title`, `accesskey` and other attributes + $loginData = $this->buildLoginData( $returnto, $useCombinedLoginLink ); + $loginData['single-id'] = 'pt-login'; + $loginData['class'] = 'vector-menu-content-item'; + + $learnMoreLinkData = [ + 'text' => $this->msg( 'vector-anon-user-menu-pages-learn' )->text(), + 'href' => Title::newFromText( 'Help:Introduction' )->getLocalURL(), + ]; + $learnMoreLink = $this->makeLink( '', $learnMoreLinkData ); + + $templateParser = $this->getTemplateParser(); + return $templateParser->processTemplate( 'UserLinks__login', [ + 'htmlLogin' => $this->makeLink( 'login', $loginData ), + 'msgLearnMore' => $this->msg( 'vector-anon-user-menu-pages' ), + 'htmlLearnMoreLink' => $this->msg( 'parentheses' )-> + rawParams( $learnMoreLink )-> + escaped() + ] ); + } + + /** + * Returns template data for UserLinks.mustache + * @param array $menuData existing menu template data to be transformed and copied for UserLinks + * @param bool $isAnon if the user is logged out, used to conditionally provide data + * @return array + */ + private function getUserLinksTemplateData( $menuData, $isAnon ) : array { + $returnto = $this->getReturnToParam(); + $useCombinedLoginLink = $this->useCombinedLoginLink(); + $htmlCreateAccount = $this->getCreateAccountHTML( $returnto ); + $userMenuData = $menuData[ 'data-user-menu' ]; + $userMenuData[ 'html-before-portal' ] = $this->getLoginHTML( $returnto, $useCombinedLoginLink ); + + return [ + 'is-anon' => $isAnon, + 'html-create-account' => $htmlCreateAccount, + 'data-user-interface-preferences' => $menuData[ 'data-user-interface-preferences' ], + 'data-notifications' => $menuData[ 'data-notifications' ], + 'data-user-page' => $menuData[ 'data-user-page' ], + 'data-user-menu' => $userMenuData + ]; + } + /** * @inheritDoc */ @@ -232,37 +297,13 @@ class SkinVector extends SkinMustache { 'mw-prefsection-rendering-skin-skin-prefs' )->getLinkURL( 'wprov=' . self::OPT_OUT_LINK_TRACKING_CODE ), ]; - } else { - $returnto = $this->getReturnToParam(); - $useCombinedLoginLink = $this->useCombinedLoginLink(); + } - // Get data for login and create account buttons for anon user menu - // 'single-id' must be provided for `makeLink` to populate `title`, `accesskey` and other attributes - $loginData = $this->buildLoginData( $returnto, $useCombinedLoginLink ); - $loginData['single-id'] = 'pt-login'; - $loginData['class'] = 'vector-menu-content-item'; - - $createAccountData = $this->buildCreateAccountData( $returnto ); - $createAccountData['single-id'] = 'pt-createaccount'; - $createAccountData['class'] = 'mw-ui-button mw-ui-quiet'; - - $learnMoreLinkData = [ - 'text' => $this->msg( 'vector-anon-user-menu-pages-learn' )->text(), - 'href' => Title::newFromText( 'Help:Introduction' )->getLocalURL(), - ]; - $learnMoreLink = $this->makeLink( '', $learnMoreLinkData ); - - $commonSkinData['data-userlinks'] = [ - 'html-create-account' => $this->makeLink( 'create-account', $createAccountData ), - - 'html-login' => $this->makeLink( 'login', $loginData, [ - 'link-class' => 'mw-ui-icon mw-ui-icon-before mw-ui-icon-wikimedia-logIn' - ] ), - - 'html-vector-anon-user-menu-pages-learn' => $this->msg( 'parentheses' )-> - rawParams( $learnMoreLink )-> - escaped(), - ]; + if ( $this->shouldConsolidateUserLinks() ) { + $commonSkinData['data-vector-user-links'] = $this->getUserLinksTemplateData( + $commonSkinData['data-portlets'], + $commonSkinData['is-anon'] + ); } return $commonSkinData; diff --git a/includes/templates/Header.mustache b/includes/templates/Header.mustache index 41f5c6b..932faf7 100644 --- a/includes/templates/Header.mustache +++ b/includes/templates/Header.mustache @@ -11,12 +11,12 @@ {{>Logo}} {{#data-search-box}}{{>SearchBox}}{{/data-search-box}} - {{#data-portlets}} {{^is-consolidated-user-links}} - {{#data-personal}}{{>Menu}}{{/data-personal}} + {{#data-portlets}} + {{#data-personal}}{{>Menu}}{{/data-personal}} + {{/data-portlets}} {{/is-consolidated-user-links}} {{#is-consolidated-user-links}} - {{>UserLinks}} + {{#data-vector-user-links}}{{>UserLinks}}{{/data-vector-user-links}} {{/is-consolidated-user-links}} - {{/data-portlets}} diff --git a/includes/templates/Menu.mustache b/includes/templates/Menu.mustache index 478d83b..af7d97e 100644 --- a/includes/templates/Menu.mustache +++ b/includes/templates/Menu.mustache @@ -11,6 +11,7 @@ {{label}}
+ {{{html-before-portal}}} {{{html-after-portal}}}
diff --git a/includes/templates/UserLinks.mustache b/includes/templates/UserLinks.mustache index f539a6d..d90270b 100644 --- a/includes/templates/UserLinks.mustache +++ b/includes/templates/UserLinks.mustache @@ -2,12 +2,12 @@ {{#data-user-interface-preferences}}{{>Menu}}{{/data-user-interface-preferences}} {{#is-anon}} {{/is-anon}} {{^is-anon}} {{#data-notifications}}{{>Menu}}{{/data-notifications}} {{#data-user-page}}{{>Menu}}{{/data-user-page}} {{/is-anon}} - {{#data-user-menu}}{{>UserMenu}}{{/data-user-menu}} + {{#data-user-menu}}{{>Menu}}{{/data-user-menu}} diff --git a/includes/templates/UserLinks__login.mustache b/includes/templates/UserLinks__login.mustache new file mode 100644 index 0000000..01fb8e4 --- /dev/null +++ b/includes/templates/UserLinks__login.mustache @@ -0,0 +1,6 @@ +
{{{htmlLogin}}}
+
+

+ {{{msgLearnMore}}} {{{htmlLearnMoreLink}}}: +

+
diff --git a/includes/templates/UserMenu.mustache b/includes/templates/UserMenu.mustache deleted file mode 100644 index b9c8237..0000000 --- a/includes/templates/UserMenu.mustache +++ /dev/null @@ -1,28 +0,0 @@ -{{! - See @typedef UserMenuDefinition - UserMenu is a copy of Menu and needs to be kept in sync -}} -{{! `role` is unnecessary but kept to support selectors in any gadgets or user styles. }} - diff --git a/stories/UserLinks.stories.data.js b/stories/UserLinks.stories.data.js index 84f3457..a95f4bf 100644 --- a/stories/UserLinks.stories.data.js +++ b/stories/UserLinks.stories.data.js @@ -4,7 +4,6 @@ import { menuTemplate } from './Menu.stories.data'; import userLinksTemplateLegacy from '!!raw-loader!../includes/templates/legacy/UserLinks.mustache'; import userLinksTemplate from '!!raw-loader!../includes/templates/UserLinks.mustache'; -import userMenuTemplate from '!!raw-loader!../includes/templates/UserMenu.mustache'; import { helperClassName, helperMakeMenuData } from './utils'; /** @@ -49,21 +48,30 @@ const PERSONAL_MENU_TEMPLATE_DATA = { loggedInWithULS }; -/** - * @type {UserLinksDataDefinition} - */ -const userLinksData = { - 'html-login': `Log in`, - 'html-vector-anon-user-menu-pages-learn': `(learn more)`, - 'html-create-account': `Create account` -}; - const additionalMenuData = { class: 'vector-user-menu vector-menu-dropdown', 'msg-vector-anon-user-menu-pages': `Pages for logged out editors`, 'heading-class': 'mw-ui-icon mw-ui-icon-element mw-ui-icon-wikimedia-ellipsis' }; +const loggedInData = { + 'is-anon': true +}; + +const loggedOutData = { + 'is-anon': true, + 'html-before-portlet': ` +
+ Log in +
+
+

+ Pages for logged out editors (learn more): +

+
+ ` +}; + /** * @type {UserLinksDefinition} */ @@ -71,8 +79,7 @@ const USER_LINKS_LOGGED_IN_TEMPLATE_DATA = { 'is-anon': false, 'data-user-page': helperMakeMenuData( 'user-page', USERNAME_ITEM ), 'data-notifications': helperMakeMenuData( 'notifications', ECHO_ITEMS ), - 'data-user-menu': helperMakeMenuData( 'new-personal', REST_ITEMS, Object.assign( additionalMenuData, { 'is-anon': false } ) ), - 'data-userlinks': userLinksData + 'data-user-menu': helperMakeMenuData( 'new-personal', REST_ITEMS, Object.assign( additionalMenuData, loggedInData ) ) }; /** @@ -80,8 +87,8 @@ const USER_LINKS_LOGGED_IN_TEMPLATE_DATA = { */ const USER_LINKS_LOGGED_OUT_TEMPLATE_DATA = { 'is-anon': true, - 'data-user-menu': helperMakeMenuData( 'new-personal', REST_ITEMS, Object.assign( additionalMenuData, { 'is-anon': true } ) ), - 'data-userlinks': userLinksData + 'html-create-account': `Create account`, + 'data-user-menu': helperMakeMenuData( 'new-personal', REST_ITEMS, Object.assign( additionalMenuData, loggedOutData ) ) }; export { @@ -90,6 +97,5 @@ export { USER_LINKS_LOGGED_OUT_TEMPLATE_DATA, menuTemplate, userLinksTemplateLegacy, - userLinksTemplate, - userMenuTemplate + userLinksTemplate }; diff --git a/stories/UserLinks.stories.js b/stories/UserLinks.stories.js index b696a54..ecede39 100644 --- a/stories/UserLinks.stories.js +++ b/stories/UserLinks.stories.js @@ -1,7 +1,7 @@ import mustache from 'mustache'; import { menuTemplate } from './Menu.stories.data'; import { PERSONAL_MENU_TEMPLATE_DATA, USER_LINKS_LOGGED_IN_TEMPLATE_DATA, USER_LINKS_LOGGED_OUT_TEMPLATE_DATA } from './UserLinks.stories.data'; -import { userLinksTemplateLegacy, userLinksTemplate, userMenuTemplate } from './UserLinks.stories.data'; +import { userLinksTemplateLegacy, userLinksTemplate } from './UserLinks.stories.data'; import '../resources/skins.vector.styles.legacy/components/UserLinks.less'; import '../resources/skins.vector.styles/components/UserLinks.less'; @@ -43,8 +43,7 @@ export const loggedInUserLinks = () => mustache.render( userLinksTemplate, USER_LINKS_LOGGED_IN_TEMPLATE_DATA, { - Menu: menuTemplate, - UserMenu: userMenuTemplate + Menu: menuTemplate } ); @@ -52,7 +51,6 @@ export const loggedOutUserLinks = () => mustache.render( userLinksTemplate, USER_LINKS_LOGGED_OUT_TEMPLATE_DATA, { - Menu: menuTemplate, - UserMenu: userMenuTemplate + Menu: menuTemplate } ); diff --git a/stories/types.js b/stories/types.js index 6ef423c..906f940 100644 --- a/stories/types.js +++ b/stories/types.js @@ -66,25 +66,12 @@ * @typedef {Object.} MenuDefinitions */ -/** - * @typedef {Object} UserLinksDataDefinition - * @property {string} html-login - * @property {string} html-create-account - * @property {string} html-vector-anon-user-menu-pages-learn - */ - -/** - * @typedef {MenuDefinition} UserMenuDefinition - * @property {boolean} is-anon - * @property {string} [msg-vector-anon-user-menu-pages] - * @property {UserLinksDataDefinition} [data-userlinks] - */ - /** * @typedef {Object} UserLinksDefinition * @property {boolean} is-anon + * @property {string} [html-create-account] + * @property {MenuDefinition} [data-user-interface-preferences] * @property {MenuDefinition} [data-notifications] * @property {MenuDefinition} [data-user-page] - * @property {UserMenuDefinition} data-user-menu - * @property {UserLinksDataDefinition} [data-userlinks] + * @property {MenuDefinition} data-user-menu */