diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php
index 23c6686..f896c14 100644
--- a/includes/ServiceWiring.php
+++ b/includes/ServiceWiring.php
@@ -1,6 +1,29 @@
function ( MediaWikiServices $services ) {
return ContentHandler::getForTitle( RequestContext::getMain()->getTitle() );
},
+ 'Minerva.Menu.MainDirector' => function ( MediaWikiServices $services ) {
+ $context = RequestContext::getMain();
+ /** @var SkinOptions $options */
+ $options = $services->getService( 'Minerva.SkinOptions' );
+ $showMobileOptions = $options->get( SkinOptions::OPTION_MOBILE_OPTIONS );
+ $user = $context->getUser();
+ $definitions = new Definitions( $context, $services->getSpecialPageFactory() );
+ $builder = $options->get( SkinOptions::OPTION_AMC ) ?
+ new AdvancedBuilder( $showMobileOptions, $user, $definitions ) :
+ new DefaultBuilder( $showMobileOptions, $user, $definitions );
+
+ return new Director( $builder );
+ },
'Minerva.SkinUserPageHelper' => function ( MediaWikiServices $services ) {
return new SkinUserPageHelper( RequestContext::getMain()->getTitle() );
},
diff --git a/includes/menu/Definitions.php b/includes/menu/Definitions.php
new file mode 100644
index 0000000..9844bab
--- /dev/null
+++ b/includes/menu/Definitions.php
@@ -0,0 +1,332 @@
+user = $context->getUser();
+ $this->context = $context;
+ $this->specialPageFactory = $factory;
+ }
+
+ /**
+ * Inserts the Contributions menu item into the menu.
+ *
+ * @param Group $group
+ * @throws MWException
+ */
+ public function insertContributionsMenuItem( Group $group ) {
+ $group->insert( 'contribs' )
+ ->addComponent(
+ $this->context->msg( 'mobile-frontend-main-menu-contributions' )->escaped(),
+ SpecialPage::getTitleFor( 'Contributions', $this->user->getName() )->getLocalUrl(),
+ MinervaUI::iconClass( 'contributions', 'before' ),
+ [ 'data-event-name' => 'contributions' ]
+ );
+ }
+
+ /**
+ * Inserts the Watchlist menu item into the menu for a logged in user
+ *
+ * @param Group $group
+ * @throws MWException
+ */
+ public function insertWatchlistMenuItem( Group $group ) {
+ $watchTitle = SpecialPage::getTitleFor( 'Watchlist' );
+
+ // Watchlist link
+ $watchlistQuery = [];
+ // Avoid fatal when MobileFrontend not available (T171241)
+ if ( class_exists( 'SpecialMobileWatchlist' ) ) {
+ $view = $this->user->getOption( SpecialMobileWatchlist::VIEW_OPTION_NAME, false );
+ $filter = $this->user->getOption( SpecialMobileWatchlist::FILTER_OPTION_NAME, false );
+ if ( $view ) {
+ $watchlistQuery['watchlistview'] = $view;
+ }
+ if ( $filter && $view === 'feed' ) {
+ $watchlistQuery['filter'] = $filter;
+ }
+ }
+
+ $group->insert( 'watchlist' )
+ ->addComponent(
+ $this->context->msg( 'mobile-frontend-main-menu-watchlist' )->escaped(),
+ $watchTitle->getLocalURL( $watchlistQuery ),
+ MinervaUI::iconClass( 'watchlist', 'before' ),
+ [ 'data-event-name' => 'watchlist' ]
+ );
+ }
+
+ /**
+ * Creates a login or logout button
+ *
+ * @param Group $group
+ * @throws MWException
+ */
+ public function insertLogInOutMenuItem( Group $group ) {
+ $query = [];
+ $returntoquery = [];
+ $request = $this->context->getRequest();
+
+ if ( !$request->wasPosted() ) {
+ $returntoquery = $request->getValues();
+ unset( $returntoquery['title'] );
+ unset( $returntoquery['returnto'] );
+ unset( $returntoquery['returntoquery'] );
+ }
+ $title = $this->context->getTitle();
+ // Don't ever redirect back to the login page (bug 55379)
+ if ( !$title->isSpecial( 'Userlogin' ) ) {
+ $query[ 'returnto' ] = $title->getPrefixedText();
+ }
+
+ if ( $this->user->isLoggedIn() ) {
+ if ( !empty( $returntoquery ) ) {
+ $query[ 'returntoquery' ] = wfArrayToCgi( $returntoquery );
+ }
+ $url = SpecialPage::getTitleFor( 'Userlogout' )->getLocalURL( $query );
+ $username = $this->user->getName();
+
+ $group->insert( 'auth', false )
+ ->addComponent(
+ $username,
+ Title::newFromText( $username, NS_USER )->getLocalUrl(),
+ MinervaUI::iconClass( 'profile', 'before', 'truncated-text primary-action' ),
+ [ 'data-event-name' => 'profile' ]
+ )
+ ->addComponent(
+ $this->context->msg( 'mobile-frontend-main-menu-logout' )->escaped(),
+ $url,
+ MinervaUI::iconClass(
+ 'logout', 'element', 'secondary-action truncated-text' ),
+ [ 'data-event-name' => 'logout' ]
+ );
+ } else {
+ // unset campaign on login link so as not to interfere with A/B tests
+ unset( $returntoquery['campaign'] );
+ $query[ 'returntoquery' ] = wfArrayToCgi( $returntoquery );
+ $url = $this->getLoginUrl( $query );
+ $group->insert( 'auth', false )
+ ->addComponent(
+ $this->context->msg( 'mobile-frontend-main-menu-login' )->escaped(),
+ $url,
+ MinervaUI::iconClass( 'login', 'before' ),
+ [ 'data-event-name' => 'login' ]
+ );
+ }
+ }
+
+ /**
+ * Build and insert Home link
+ * @param Group $group
+ */
+ public function insertHomeItem( Group $group ) {
+ // Home link
+ $group->insert( 'home' )
+ ->addComponent(
+ $this->context->msg( 'mobile-frontend-home-button' )->escaped(),
+ Title::newMainPage()->getLocalUrl(),
+ MinervaUI::iconClass( 'home', 'before' ),
+ [ 'data-event-name' => 'home' ]
+ );
+ }
+
+ /**
+ * Build and insert Random link
+ * @param Group $group
+ * @throws MWException
+ */
+ public function insertRandomItem( Group $group ) {
+ // Random link
+ $group->insert( 'random' )
+ ->addComponent( $this->context->msg( 'mobile-frontend-random-button' )->escaped(),
+ SpecialPage::getTitleFor( 'Randompage' )->getLocalUrl() . '#/random',
+ MinervaUI::iconClass( 'random', 'before' ), [
+ 'id' => 'randomButton',
+ 'data-event-name' => 'random',
+ ] );
+ }
+
+ /**
+ * If Nearby is supported, build and inject the Nearby link
+ * @param Group $group
+ * @throws MWException
+ */
+ public function insertNearbyIfSupported( Group $group ) {
+ // Nearby link (if supported)
+ if ( $this->specialPageFactory->exists( 'Nearby' ) ) {
+ $group->insert( 'nearby', $isJSOnly = true )
+ ->addComponent(
+ $this->context->msg( 'mobile-frontend-main-menu-nearby' )->escaped(),
+ SpecialPage::getTitleFor( 'Nearby' )->getLocalURL(),
+ MinervaUI::iconClass( 'nearby', 'before', 'nearby' ),
+ [ 'data-event-name' => 'nearby' ]
+ );
+ }
+ }
+
+ /**
+ * Build and insert the Settings link
+ * @param Group $group
+ * @throws MWException
+ */
+ public function insertMobileOptionsItem( Group $group ) {
+ $title = $this->context->getTitle();
+ $returnToTitle = $title->getPrefixedText();
+ $group->insert( 'settings' )
+ ->addComponent(
+ $this->context->msg( 'mobile-frontend-main-menu-settings' )->escaped(),
+ SpecialPage::getTitleFor( 'MobileOptions' )->
+ getLocalURL( [ 'returnto' => $returnToTitle ] ),
+ MinervaUI::iconClass( 'settings', 'before' ),
+ [ 'data-event-name' => 'settings' ]
+ );
+ }
+
+ /**
+ * Build and insert the Preferences link
+ * @param Group $group
+ * @throws MWException
+ */
+ public function insertPreferencesItem( Group $group ) {
+ $group->insert( 'preferences' )
+ ->addComponent(
+ $this->context->msg( 'preferences' )->escaped(),
+ SpecialPage::getTitleFor( 'Preferences' )->getLocalURL(),
+ MinervaUI::iconClass( 'settings', 'before' ),
+ [ 'data-event-name' => 'preferences' ]
+ );
+ }
+
+ /**
+ * Build and insert About page link
+ * @param Group $group
+ */
+ public function insertAboutItem( Group $group ) {
+ $title = Title::newFromText( $this->context->msg( 'aboutpage' )->inContentLanguage()->text() );
+ $msg = $this->context->msg( 'aboutsite' );
+ if ( $title && !$msg->isDisabled() ) {
+ $group->insert( 'about' )
+ ->addComponent( $msg->text(), $title->getLocalUrl() );
+ }
+ }
+
+ /**
+ * Build and insert Disclaimers link
+ * @param Group $group
+ */
+ public function insertDisclaimersItem( Group $group ) {
+ $title = Title::newFromText( $this->context->msg( 'disclaimerpage' )
+ ->inContentLanguage()->text() );
+ $msg = $this->context->msg( 'disclaimers' );
+ if ( $title && !$msg->isDisabled() ) {
+ $group->insert( 'disclaimers' )
+ ->addComponent( $msg->text(), $title->getLocalUrl() );
+ }
+ }
+
+ /**
+ * Build and insert the RecentChanges link
+ * @param Group $group
+ * @throws MWException
+ */
+ public function insertRecentChanges( Group $group ) {
+ $title = SpecialPage::getTitleFor( 'Recentchanges' );
+
+ $group->insert( 'recentchanges' )
+ ->addComponent(
+ $this->context->msg( 'recentchanges' )->escaped(),
+ $title->getLocalURL(),
+ MinervaUI::iconClass( 'recentchanges', 'before' ),
+ [ 'data-event-name' => 'recentchanges' ]
+ );
+ }
+
+ /**
+ * Build and insert the SpecialPages link
+ * @param Group $group
+ * @throws MWException
+ */
+ public function insertSpecialPages( Group $group ) {
+ $group->insert( 'specialpages' )
+ ->addComponent(
+ $this->context->msg( 'specialpages' )->escaped(),
+ SpecialPage::getTitleFor( 'Specialpages' )->getLocalURL(),
+ MinervaUI::iconClass( 'specialpages', 'before' ),
+ [ 'data-event-name' => 'specialpages' ]
+ );
+ }
+
+ /**
+ * Build and insert the CommunityPortal link
+ * @param Group $group
+ * @throws MWException
+ */
+ public function insertCommunityPortal( Group $group ) {
+ /// placeholder for a follow-up patch @see T216152
+ }
+
+ /**
+ * Prepares a url to the Special:UserLogin with query parameters
+ *
+ * @param array $query
+ * @return string
+ * @throws MWException
+ */
+ private function getLoginUrl( $query ) {
+ return SpecialPage::getTitleFor( 'Userlogin' )->getLocalURL( $query );
+ }
+
+}
diff --git a/includes/skins/MenuBuilder.php b/includes/menu/Group.php
similarity index 87%
rename from includes/skins/MenuBuilder.php
rename to includes/menu/Group.php
index 6ce1874..9bcdcce 100644
--- a/includes/skins/MenuBuilder.php
+++ b/includes/menu/Group.php
@@ -18,19 +18,28 @@
* @file
*/
-namespace MediaWiki\Minerva;
+namespace MediaWiki\Minerva\Menu;
use DomainException;
/**
* Model for a menu that can be presented in a skin.
*/
-class MenuBuilder {
+class Group {
/**
* @var MenuEntry[]
*/
private $entries = [];
+ /**
+ * Return entries count
+ *
+ * @return int
+ */
+ public function hasEntries() {
+ return count( $this->entries ) > 0;
+ }
+
/**
* Get all entries represented as plain old PHP arrays.
*
@@ -116,3 +125,9 @@ class MenuBuilder {
return $entry;
}
}
+
+/**
+ * make sure BlueSpiceMultiUpload and GrowthExperiments use the new class
+ * @TODO remove after updating all extensions that still depend upon MenuBuilder
+ */
+class_alias( 'MediaWiki\Minerva\Menu\Group', 'MediaWiki\Minerva\MenuBuilder' );
diff --git a/includes/menu/Main/AdvancedBuilder.php b/includes/menu/Main/AdvancedBuilder.php
new file mode 100644
index 0000000..bbdcece
--- /dev/null
+++ b/includes/menu/Main/AdvancedBuilder.php
@@ -0,0 +1,68 @@
+getDiscoveryTools(),
+ $this->getPersonalTools(),
+ $this->getSiteTools(),
+ $this->getConfigurationTools(),
+ ];
+ }
+
+ /**
+ * Prepares a list of links that have the purpose of discovery in the main navigation menu
+ * @return Group
+ * @throws FatalError
+ * @throws MWException
+ */
+ public function getSiteTools() {
+ $group = new Group();
+
+ $this->definitions->insertRecentChanges( $group );
+ $this->definitions->insertSpecialPages( $group );
+ $this->definitions->insertCommunityPortal( $group );
+
+ // Allow other extensions to add or override tools
+ Hooks::run( 'MobileMenu', [ 'sitetools', &$group ] );
+ return $group;
+ }
+}
diff --git a/includes/menu/Main/DefaultBuilder.php b/includes/menu/Main/DefaultBuilder.php
new file mode 100644
index 0000000..fca41f7
--- /dev/null
+++ b/includes/menu/Main/DefaultBuilder.php
@@ -0,0 +1,152 @@
+showMobileOptions = $showMobileOptions;
+ $this->user = $user;
+ $this->definitions = $definitions;
+ }
+
+ /**
+ * @return Group[]
+ * @throws FatalError
+ * @throws MWException
+ */
+ public function getGroups() {
+ return [
+ $this->getDiscoveryTools(),
+ $this->getPersonalTools(),
+ $this->getConfigurationTools(),
+ ];
+ }
+
+ /**
+ * Prepares a list of links that have the purpose of discovery in the main navigation menu
+ * @return Group
+ * @throws FatalError
+ * @throws MWException
+ */
+ protected function getDiscoveryTools() {
+ $group = new Group();
+
+ $this->definitions->insertHomeItem( $group );
+ $this->definitions->insertRandomItem( $group );
+ $this->definitions->insertNearbyIfSupported( $group );
+
+ // Allow other extensions to add or override tools
+ Hooks::run( 'MobileMenu', [ 'discovery', &$group ] );
+ return $group;
+ }
+
+ /**
+ * Builds the personal tools menu item group.
+ *
+ * ... by adding the Watchlist, Settings, and Log{in,out} menu items in the given order.
+ *
+ * @return Group
+ * @throws FatalError
+ * @throws MWException
+ */
+ protected function getPersonalTools() {
+ $group = new Group();
+
+ $this->definitions->insertLogInOutMenuItem( $group );
+
+ if ( $this->user->isLoggedIn() ) {
+ $this->definitions->insertWatchlistMenuItem( $group );
+ $this->definitions->insertContributionsMenuItem( $group );
+ }
+
+ // Allow other extensions to add or override tools
+ Hooks::run( 'MobileMenu', [ 'personal', &$group ] );
+ return $group;
+ }
+
+ /**
+ * Like SkinMinerva#getDiscoveryTools
and #getPersonalTools
, create
+ * a group of configuration-related menu items. Currently, only the Settings menu item is in the
+ * group.
+ *
+ * @return Group
+ * @throws MWException
+ */
+ protected function getConfigurationTools() {
+ $group = new Group();
+
+ $this->showMobileOptions ?
+ $this->definitions->insertMobileOptionsItem( $group ) :
+ $this->definitions->insertPreferencesItem( $group );
+
+ return $group;
+ }
+
+ /**
+ * Returns an array of sitelinks to add into the main menu footer.
+ * @return Group Collection of site links
+ * @throws MWException
+ */
+ public function getSiteLinks() {
+ $group = new Group();
+
+ $this->definitions->insertAboutItem( $group );
+ $this->definitions->insertDisclaimersItem( $group );
+ // Allow other extensions to add or override tools
+ Hooks::run( 'MobileMenu', [ 'sitelinks', &$group ] );
+ return $group;
+ }
+
+}
diff --git a/includes/menu/Main/Director.php b/includes/menu/Main/Director.php
new file mode 100644
index 0000000..40f6d00
--- /dev/null
+++ b/includes/menu/Main/Director.php
@@ -0,0 +1,74 @@
+builder = $builder;
+ }
+
+ /**
+ * Returns a data representation of the main menus
+ * @return array
+ */
+ public function getMenuData() {
+ if ( $this->menuData === null ) {
+ $this->menuData = $this->buildMenu();
+ }
+ return $this->menuData;
+ }
+
+ /**
+ * Build the menu data array that can be passed to views/javascript
+ * @return array
+ */
+ private function buildMenu() {
+ $menuData = [
+ 'groups' => [],
+ 'sitelinks' => $this->builder->getSiteLinks()->getEntries()
+ ];
+ foreach ( $this->builder->getGroups() as $group ) {
+ if ( $group->hasEntries() ) {
+ $menuData['groups'][] = $group->getEntries();
+ }
+ }
+ return $menuData;
+ }
+
+}
diff --git a/includes/menu/Main/IBuilder.php b/includes/menu/Main/IBuilder.php
new file mode 100644
index 0000000..e81424e
--- /dev/null
+++ b/includes/menu/Main/IBuilder.php
@@ -0,0 +1,36 @@
+skinOptions = MediaWikiServices::getInstance()->getService( 'Minerva.SkinOptions' );
}
+ /**
+ * Initalized main menu. Please use getter.
+ * @return MainMenuDirector
+ *
+ */
+ private $mainMenu;
+
+ /**
+ * Build the Main Menu Director by passing the skin options
+ *
+ * @return MainMenuDirector
+ */
+ protected function getMainMenu() {
+ if ( !$this->mainMenu ) {
+ $this->mainMenu = MediaWikiServices::getInstance()->getService( 'Minerva.Menu.MainDirector' );
+ }
+ return $this->mainMenu;
+ }
+
/**
* Returns the site name for the footer, either as a text or tag
* @return string
+ * @throws ConfigException
*/
public function getSitename() {
$config = $this->getConfig();
@@ -118,7 +139,7 @@ class SkinMinerva extends SkinTemplate {
$tpl->set( 'unstyledContent', $out->getProperty( 'unstyledContent' ) );
// Set the links for the main menu
- $tpl->set( 'menu_data', $this->getMenuData() );
+ $tpl->set( 'menu_data', $this->getMainMenu()->getMenuData() );
// Set the links for page secondary actions
$tpl->set( 'secondary_actions', $this->getSecondaryActions( $tpl ) );
@@ -428,122 +449,6 @@ class SkinMinerva extends SkinTemplate {
] );
}
}
-
- /**
- * Inserts the Contributions menu item into the menu.
- *
- * @param MenuBuilder $menu
- * @param User $user The user to whom the contributions belong
- */
- private function insertContributionsMenuItem( MenuBuilder $menu, User $user ) {
- $menu->insert( 'contribs' )
- ->addComponent(
- $this->msg( 'mobile-frontend-main-menu-contributions' )->escaped(),
- SpecialPage::getTitleFor( 'Contributions', $user->getName() )->getLocalUrl(),
- MinervaUI::iconClass( 'contributions', 'before' ),
- [ 'data-event-name' => 'contributions' ]
- );
- }
-
- /**
- * Inserts the Watchlist menu item into the menu for a logged in user
- *
- * @param MenuBuilder $menu
- * @param User $user that must be logged in
- */
- protected function insertWatchlistMenuItem( MenuBuilder $menu, User $user ) {
- $watchTitle = SpecialPage::getTitleFor( 'Watchlist' );
-
- // Watchlist link
- $watchlistQuery = [];
- // Avoid fatal when MobileFrontend not available (T171241)
- if ( class_exists( 'SpecialMobileWatchlist' ) ) {
- $view = $user->getOption( SpecialMobileWatchlist::VIEW_OPTION_NAME, false );
- $filter = $user->getOption( SpecialMobileWatchlist::FILTER_OPTION_NAME, false );
- if ( $view ) {
- $watchlistQuery['watchlistview'] = $view;
- }
- if ( $filter && $view === 'feed' ) {
- $watchlistQuery['filter'] = $filter;
- }
- }
-
- $menu->insert( 'watchlist' )
- ->addComponent(
- $this->msg( 'mobile-frontend-main-menu-watchlist' )->escaped(),
- $watchTitle->getLocalURL( $watchlistQuery ),
- MinervaUI::iconClass( 'watchlist', 'before' ),
- [ 'data-event-name' => 'watchlist' ]
- );
- }
-
- /**
- * If the user is using a mobile device (or the UA presents itself as a mobile device), then the
- * Settings menu item is inserted into the menu; otherwise the Preferences menu item is inserted.
- *
- * @param MenuBuilder $menu
- */
- protected function insertSettingsMenuItem( MenuBuilder $menu ) {
- $returnToTitle = $this->getTitle()->getPrefixedText();
-
- // Links specifically for mobile mode
- if ( $this->skinOptions->get( SkinOptions::OPTION_MOBILE_OPTIONS ) ) {
- // Settings link
- $menu->insert( 'settings' )
- ->addComponent(
- $this->msg( 'mobile-frontend-main-menu-settings' )->escaped(),
- SpecialPage::getTitleFor( 'MobileOptions' )->
- getLocalURL( [ 'returnto' => $returnToTitle ] ),
- MinervaUI::iconClass( 'settings', 'before' ),
- [ 'data-event-name' => 'settings' ]
- );
-
- // Links specifically for desktop mode
- } else {
-
- // Preferences link
- $menu->insert( 'preferences' )
- ->addComponent(
- $this->msg( 'preferences' )->escaped(),
- SpecialPage::getTitleFor( 'Preferences' )->getLocalURL(),
- MinervaUI::iconClass( 'settings', 'before' ),
- [ 'data-event-name' => 'preferences' ]
- );
- }
- }
-
- /**
- * Builds the personal tools menu item group.
- *
- * ... by adding the Watchlist, Settings, and Log{in,out} menu items in the given order.
- *
- * @param MenuBuilder $menu
- */
- protected function buildPersonalTools( MenuBuilder $menu ) {
- $this->insertLogInOutMenuItem( $menu );
-
- $user = $this->getUser();
-
- if ( $user->isLoggedIn() ) {
- $this->insertWatchlistMenuItem( $menu, $user );
- $this->insertContributionsMenuItem( $menu, $user );
- }
- }
-
- /**
- * Prepares and returns urls and links personal to the given user
- * @return array
- */
- protected function getPersonalTools() {
- $menu = new MenuBuilder();
-
- $this->buildPersonalTools( $menu );
-
- // Allow other extensions to add or override tools
- Hooks::run( 'MobileMenu', [ 'personal', &$menu ] );
- return $menu->getEntries();
- }
-
/**
* Rewrites the language list so that it cannot be contaminated by other extensions with things
* other than languages
@@ -561,67 +466,6 @@ class SkinMinerva extends SkinTemplate {
$tpl->set( 'language_urls', $language_urls );
}
- /**
- * Like SkinMinerva#getDiscoveryTools
and #getPersonalTools
, create
- * a group of configuration-related menu items. Currently, only the Settings menu item is in the
- * group.
- *
- * @return array
- */
- private function getConfigurationTools() {
- $menu = new MenuBuilder();
-
- $this->insertSettingsMenuItem( $menu );
-
- return $menu->getEntries();
- }
-
- /**
- * Prepares a list of links that have the purpose of discovery in the main navigation menu
- * @return array
- */
- protected function getDiscoveryTools() {
- $config = $this->getConfig();
- $menu = new MenuBuilder();
- $factory = MediaWikiServices::getInstance()->getSpecialPageFactory();
-
- // Home link
- $menu->insert( 'home' )
- ->addComponent(
- $this->msg( 'mobile-frontend-home-button' )->escaped(),
- Title::newMainPage()->getLocalURL(),
- MinervaUI::iconClass( 'home', 'before' ),
- [ 'data-event-name' => 'home' ]
- );
-
- // Random link
- $menu->insert( 'random' )
- ->addComponent(
- $this->msg( 'mobile-frontend-random-button' )->escaped(),
- SpecialPage::getTitleFor( 'Randompage' )->getLocalURL() . '#/random',
- MinervaUI::iconClass( 'random', 'before' ),
- [
- 'id' => 'randomButton',
- 'data-event-name' => 'random',
- ]
- );
-
- // Nearby link (if supported)
- if ( $factory->exists( 'Nearby' ) ) {
- $menu->insert( 'nearby', $isJSOnly = true )
- ->addComponent(
- $this->msg( 'mobile-frontend-main-menu-nearby' )->escaped(),
- SpecialPage::getTitleFor( 'Nearby' )->getLocalURL(),
- MinervaUI::iconClass( 'nearby', 'before', 'nearby' ),
- [ 'data-event-name' => 'nearby' ]
- );
- }
-
- // Allow other extensions to add or override tools
- Hooks::run( 'MobileMenu', [ 'discovery', &$menu ] );
- return $menu->getEntries();
- }
-
/**
* Prepares a url to the Special:UserLogin with query parameters
* @param array $query
@@ -631,64 +475,6 @@ class SkinMinerva extends SkinTemplate {
return SpecialPage::getTitleFor( 'Userlogin' )->getLocalURL( $query );
}
- /**
- * Creates a login or logout button
- *
- * @param MenuBuilder $menu
- */
- protected function insertLogInOutMenuItem( MenuBuilder $menu ) {
- $query = [];
- $returntoquery = [];
-
- if ( !$this->getRequest()->wasPosted() ) {
- $returntoquery = $this->getRequest()->getValues();
- unset( $returntoquery['title'] );
- unset( $returntoquery['returnto'] );
- unset( $returntoquery['returntoquery'] );
- }
- $title = $this->getTitle();
- // Don't ever redirect back to the login page (bug 55379)
- if ( !$title->isSpecial( 'Userlogin' ) ) {
- $query[ 'returnto' ] = $title->getPrefixedText();
- }
-
- $user = $this->getUser();
- if ( $user->isLoggedIn() ) {
- if ( !empty( $returntoquery ) ) {
- $query[ 'returntoquery' ] = wfArrayToCgi( $returntoquery );
- }
- $url = SpecialPage::getTitleFor( 'Userlogout' )->getLocalURL( $query );
- $username = $user->getName();
-
- $menu->insert( 'auth', false )
- ->addComponent(
- $username,
- Title::newFromText( $username, NS_USER )->getLocalURL(),
- MinervaUI::iconClass( 'profile', 'before', 'truncated-text primary-action' ),
- [ 'data-event-name' => 'profile' ]
- )
- ->addComponent(
- $this->msg( 'mobile-frontend-main-menu-logout' )->escaped(),
- $url,
- MinervaUI::iconClass(
- 'logout', 'element', 'secondary-action truncated-text' ),
- [ 'data-event-name' => 'logout' ]
- );
- } else {
- // unset campaign on login link so as not to interfere with A/B tests
- unset( $returntoquery['campaign'] );
- $query[ 'returntoquery' ] = wfArrayToCgi( $returntoquery );
- $url = $this->getLoginUrl( $query );
- $menu->insert( 'auth', false )
- ->addComponent(
- $this->msg( 'mobile-frontend-main-menu-login' )->escaped(),
- $url,
- MinervaUI::iconClass( 'login', 'before' ),
- [ 'data-event-name' => 'login' ]
- );
- }
- }
-
/**
* Get a history link which describes author and relative time of last edit
* @param Title $title The Title object of the page being viewed
@@ -930,34 +716,6 @@ class SkinMinerva extends SkinTemplate {
$tpl->set( 'internalBanner', '' );
}
- /**
- * Returns an array of sitelinks to add into the main menu footer.
- * @return array Array of site links
- */
- protected function getSiteLinks() {
- $menu = new MenuBuilder();
-
- // About link
- $title = Title::newFromText( $this->msg( 'aboutpage' )->inContentLanguage()->text() );
- $msg = $this->msg( 'aboutsite' );
- if ( $title && !$msg->isDisabled() ) {
- $menu->insert( 'about' )
- ->addComponent( $msg->text(), $title->getLocalURL() );
- }
-
- // Disclaimers link
- $title = Title::newFromText( $this->msg( 'disclaimerpage' )->inContentLanguage()->text() );
- $msg = $this->msg( 'disclaimers' );
- if ( $title && !$msg->isDisabled() ) {
- $menu->insert( 'disclaimers' )
- ->addComponent( $msg->text(), $title->getLocalURL() );
- }
-
- // Allow other extensions to add or override tools
- Hooks::run( 'MobileMenu', [ 'sitelinks', &$menu ] );
- return $menu->getEntries();
- }
-
/**
* Returns an array with details for a language button.
* @return array
@@ -1232,23 +990,6 @@ class SkinMinerva extends SkinTemplate {
&& $contentHandler->supportsDirectApiEditing();
}
- /**
- * Returns a data representation of the main menus
- * @return array
- */
- protected function getMenuData() {
- $data = [
- 'groups' => [
- $this->getDiscoveryTools(),
- $this->getPersonalTools(),
- $this->getConfigurationTools(),
- ],
- 'sitelinks' => $this->getSiteLinks(),
- ];
-
- return $data;
- }
-
/**
* Returns array of config variables that should be added only to this skin
* for use in JavaScript.
@@ -1258,7 +999,7 @@ class SkinMinerva extends SkinTemplate {
$vars = [
'wgMinervaFeatures' => $this->skinOptions->getAll(),
'wgMinervaDownloadNamespaces' => $this->getConfig()->get( 'MinervaDownloadNamespaces' ),
- 'wgMinervaMenuData' => $this->getMenuData(),
+ 'wgMinervaMenuData' => $this->getMainMenu()->getMenuData(),
];
return $vars;
diff --git a/resources/skins.minerva.mainMenu.icons/recentchanges.svg b/resources/skins.minerva.mainMenu.icons/recentchanges.svg
new file mode 100644
index 0000000..cb357ba
--- /dev/null
+++ b/resources/skins.minerva.mainMenu.icons/recentchanges.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/skins.minerva.mainMenu.icons/specialpages.svg b/resources/skins.minerva.mainMenu.icons/specialpages.svg
new file mode 100644
index 0000000..d4fc074
--- /dev/null
+++ b/resources/skins.minerva.mainMenu.icons/specialpages.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/skin.json b/skin.json
index d304877..04eceb3 100644
--- a/skin.json
+++ b/skin.json
@@ -67,14 +67,17 @@
"ValidSkinNames": {
"minerva": "MinervaNeue"
},
+ "AutoloadNamespaces": {
+ "MediaWiki\\Minerva\\Menu\\": "includes/menu/"
+ },
"AutoloadClasses": {
"MinervaUI": "includes/MinervaUI.php",
"MinervaHooks": "includes/MinervaHooks.php",
"MinervaTemplate": "includes/skins/MinervaTemplate.php",
"SkinMinerva": "includes/skins/SkinMinerva.php",
"SkinMinervaNeue": "includes/skins/SkinMinerva.php",
- "MediaWiki\\Minerva\\MenuBuilder": "includes/skins/MenuBuilder.php",
- "MediaWiki\\Minerva\\MenuEntry": "includes/skins/MenuEntry.php",
+ "MediaWiki\\Minerva\\Menu\\Group": "includes/menu/Group.php",
+ "MediaWiki\\Minerva\\MenuBuilder": "includes/menu/Group.php",
"MediaWiki\\Minerva\\ResourceLoaderLessVarFileModule": "includes/ResourceLoaderLessVarFileModule.php",
"MediaWiki\\Minerva\\SkinOptions": "includes/SkinOptions.php",
"MediaWiki\\Minerva\\SkinUserPageHelper": "includes/skins/SkinUserPageHelper.php"
@@ -341,7 +344,9 @@
"random": "resources/skins.minerva.mainMenu.icons/random.svg",
"settings": "resources/skins.minerva.mainMenu.icons/settings.svg",
"watchlist": "resources/skins.minerva.mainMenu.icons/watchlist.svg",
- "contributions": "resources/skins.minerva.mainMenu.icons/contributions.svg"
+ "contributions": "resources/skins.minerva.mainMenu.icons/contributions.svg",
+ "recentchanges": "resources/skins.minerva.mainMenu.icons/recentchanges.svg",
+ "specialpages": "resources/skins.minerva.mainMenu.icons/specialpages.svg"
}
},
"skins.minerva.mainMenu.styles": {
diff --git a/tests/phpunit/MenuBuilderTest.php b/tests/phpunit/menu/GroupTest.php
similarity index 68%
rename from tests/phpunit/MenuBuilderTest.php
rename to tests/phpunit/menu/GroupTest.php
index 2f3bc96..3983c3f 100644
--- a/tests/phpunit/MenuBuilderTest.php
+++ b/tests/phpunit/menu/GroupTest.php
@@ -1,14 +1,14 @@
'Home',
'href' => '/Main_page',
@@ -23,22 +23,22 @@ class MenuBuilderTest extends \PHPUnit\Framework\TestCase {
];
/**
- * @covers \MediaWiki\Minerva\MenuBuilder::getEntries
+ * @covers ::getEntries
*/
public function testItShouldntHaveEntriesByDefault() {
- $menu = new MenuBuilder();
+ $menu = new Group();
$this->assertEmpty( $menu->getEntries() );
}
/**
- * @covers \MediaWiki\Minerva\MenuBuilder::insert
- * @covers \MediaWiki\Minerva\MenuBuilder::search
- * @covers \MediaWiki\Minerva\MenuBuilder::getEntries
- * @covers \MediaWiki\Minerva\MenuEntry::addComponent
+ * @covers ::insert
+ * @covers ::search
+ * @covers ::getEntries
+ * @covers \MediaWiki\Minerva\Menu\MenuEntry::addComponent
*/
public function testInsertingAnEntry() {
- $menu = new MenuBuilder();
+ $menu = new Group();
$menu->insert( 'home' )
->addComponent(
$this->homeComponent['text'],
@@ -60,13 +60,13 @@ class MenuBuilderTest extends \PHPUnit\Framework\TestCase {
}
/**
- * @covers \MediaWiki\Minerva\MenuBuilder::insert
- * @covers \MediaWiki\Minerva\MenuBuilder::search
- * @covers \MediaWiki\Minerva\MenuBuilder::getEntries
- * @covers \MediaWiki\Minerva\MenuEntry::addComponent
+ * @covers ::insert
+ * @covers ::search
+ * @covers ::getEntries
+ * @covers \MediaWiki\Minerva\Menu\MenuEntry::addComponent
*/
public function testInsertingAnEntryAfterAnother() {
- $menu = new MenuBuilder();
+ $menu = new Group();
$menu->insert( 'home' )
->addComponent(
$this->homeComponent['text'],
@@ -113,12 +113,12 @@ class MenuBuilderTest extends \PHPUnit\Framework\TestCase {
/**
* @expectedException \DomainException
* @expectedExceptionMessage The "home" entry doesn't exist.
- * @covers \MediaWiki\Minerva\MenuBuilder::insertAfter
- * @covers \MediaWiki\Minerva\MenuBuilder::search
- * @covers \MediaWiki\Minerva\MenuEntry::addComponent
+ * @covers ::insertAfter
+ * @covers ::search
+ * @covers \MediaWiki\Minerva\Menu\MenuEntry::addComponent
*/
public function testInsertAfterWhenTargetEntryDoesntExist() {
- $menu = new MenuBuilder();
+ $menu = new Group();
$menu->insertAfter( 'home', 'nearby' )
->addComponent(
$this->nearbyComponent['text'],
@@ -130,10 +130,10 @@ class MenuBuilderTest extends \PHPUnit\Framework\TestCase {
/**
* @expectedException \DomainException
* @expectedExceptionMessage The "car" entry already exists.
- * @covers \MediaWiki\Minerva\MenuBuilder::insertAfter
+ * @covers ::insertAfter
*/
public function testInsertAfterWithAnEntryWithAnExistingName() {
- $menu = new MenuBuilder();
+ $menu = new Group();
$menu->insert( 'home' );
$menu->insert( 'car' );
$menu->insertAfter( 'home', 'car' );
@@ -142,20 +142,20 @@ class MenuBuilderTest extends \PHPUnit\Framework\TestCase {
/**
* @expectedException \DomainException
* @expectedExceptionMessage The "home" entry already exists.
- * @covers \MediaWiki\Minerva\MenuBuilder::insert
+ * @covers ::insert
*/
public function testInsertingAnEntryWithAnExistingName() {
- $menu = new MenuBuilder();
+ $menu = new Group();
$menu->insert( 'home' );
$menu->insert( 'home' );
}
/**
- * @covers \MediaWiki\Minerva\MenuBuilder::insert
- * @covers \MediaWiki\Minerva\MenuBuilder::insertAfter
+ * @covers ::insert
+ * @covers ::insertAfter
*/
public function testInsertingAnEntryAfterAnotherOne() {
- $menu = new MenuBuilder();
+ $menu = new Group();
$menu->insert( 'first' );
$menu->insert( 'last' );
$menu->insertAfter( 'first', 'middle' );
@@ -167,9 +167,9 @@ class MenuBuilderTest extends \PHPUnit\Framework\TestCase {
}
/**
- * @covers \MediaWiki\Minerva\MenuBuilder::insert
- * @covers \MediaWiki\Minerva\MenuBuilder::getEntries
- * @covers \MediaWiki\Minerva\MenuEntry::addComponent
+ * @covers ::insert
+ * @covers ::getEntries
+ * @covers \MediaWiki\Minerva\Menu\MenuEntry::addComponent
*/
public function testinsertingAnEntryWithMultipleComponents() {
$authLoginComponent = [
@@ -185,7 +185,7 @@ class MenuBuilderTest extends \PHPUnit\Framework\TestCase {
'mw-ui-icon mw-ui-icon-element secondary-logout secondary-action truncated-text',
];
- $menu = new MenuBuilder();
+ $menu = new Group();
$menu->insert( 'auth' )
->addComponent(
$authLoginComponent['text'],
@@ -212,12 +212,12 @@ class MenuBuilderTest extends \PHPUnit\Framework\TestCase {
}
/**
- * @covers \MediaWiki\Minerva\MenuBuilder::insert
- * @covers \MediaWiki\Minerva\MenuBuilder::getEntries
- * @covers \MediaWiki\Minerva\MenuEntry::addComponent
+ * @covers ::insert
+ * @covers ::getEntries
+ * @covers \MediaWiki\Minerva\Menu\MenuEntry::addComponent
*/
public function testInsertingAJavascriptOnlyEntry() {
- $menu = new MenuBuilder();
+ $menu = new Group();
$menu->insert( 'nearby', $isJSOnly = true )
->addComponent(
$this->nearbyComponent['text'],
@@ -236,18 +236,4 @@ class MenuBuilderTest extends \PHPUnit\Framework\TestCase {
$this->assertEquals( $expectedEntries, $menu->getEntries() );
}
- /**
- * @covers \MediaWiki\Minerva\MenuEntry::__construct
- * @covers \MediaWiki\Minerva\MenuEntry::getName()
- * @covers \MediaWiki\Minerva\MenuEntry::isJSOnly()
- * @covers \MediaWiki\Minerva\MenuEntry::getComponents()
- */
- public function testMenuEntryConstruction() {
- $name = 'test';
- $isJSOnly = true;
- $entry = new MenuEntry( $name, $isJSOnly );
- $this->assertSame( $name, $entry->getName() );
- $this->assertSame( $isJSOnly, $entry->isJSOnly() );
- $this->assertSame( [], $entry->getComponents() );
- }
}
diff --git a/tests/phpunit/menu/MenuEntryTest.php b/tests/phpunit/menu/MenuEntryTest.php
new file mode 100644
index 0000000..418e4a5
--- /dev/null
+++ b/tests/phpunit/menu/MenuEntryTest.php
@@ -0,0 +1,27 @@
+assertSame( $name, $entry->getName() );
+ $this->assertSame( $isJSOnly, $entry->isJSOnly() );
+ $this->assertSame( [], $entry->getComponents() );
+ }
+}