diff --git a/core/core.services.yml b/core/core.services.yml
index a8278352d9cf37089abf2141ac571b17121c4fb2..9467fa67c7d0c052e6ef578a957064ed3dffd2b6 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -388,7 +388,7 @@ services:
class: Drupal\Core\EventSubscriber\ViewSubscriber
tags:
- { name: event_subscriber }
- arguments: ['@content_negotiation']
+ arguments: ['@content_negotiation', '@title_resolver']
private_key:
class: Drupal\Core\PrivateKey
arguments: ['@state']
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 1d24dd501296b58a2634ba8cb83975fec0eaa55e..b1ca7c03505a1602d6fa560c1fae5ebaf3b390d8 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1503,6 +1503,7 @@ function theme_enable($theme_list) {
\Drupal::service('router.builder')->rebuild();
menu_router_rebuild();
+ \Drupal::cache('cache')->deleteTags(array('local_task' => 1));
drupal_theme_rebuild();
// Invoke hook_themes_enabled() after the themes have been enabled.
@@ -1539,6 +1540,7 @@ function theme_disable($theme_list) {
list_themes(TRUE);
\Drupal::service('router.builder')->rebuild();
menu_router_rebuild();
+ \Drupal::cache('cache')->deleteTags(array('local_task' => 1));
drupal_theme_rebuild();
// Invoke hook_themes_disabled after the themes have been disabled.
diff --git a/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
index ae1d0834ba7ca67ec88c6ac65d1c912142664ad2..7e4318d50b17bea8e08f1894e59eb4261926c825 100644
--- a/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
@@ -7,6 +7,8 @@
namespace Drupal\Core\EventSubscriber;
+use Drupal\Core\Controller\TitleResolverInterface;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\KernelEvents;
@@ -27,8 +29,24 @@ class ViewSubscriber implements EventSubscriberInterface {
protected $negotiation;
- public function __construct(ContentNegotiation $negotiation) {
+ /**
+ * The title resolver.
+ *
+ * @var \Drupal\Core\Controller\TitleResolverInterface
+ */
+ protected $titleResolver;
+
+ /**
+ * Constructs a new ViewSubscriber.
+ *
+ * @param \Drupal\Core\ContentNegotiation $negotiation
+ * The content negotiation.
+ * @param \Drupal\Core\Controller\TitleResolverInterface $title_resolver
+ * The title resolver.
+ */
+ public function __construct(ContentNegotiation $negotiation, TitleResolverInterface $title_resolver) {
$this->negotiation = $negotiation;
+ $this->titleResolver = $title_resolver;
}
/**
@@ -154,6 +172,13 @@ public function onIframeUpload(GetResponseForControllerResultEvent $event) {
*/
public function onHtml(GetResponseForControllerResultEvent $event) {
$page_callback_result = $event->getControllerResult();
+ $request = $event->getRequest();
+
+ // If no title was returned fall back to one defined in the route.
+ if (!isset($page_callback_result['#title'])) {
+ $page_callback_result['#title'] = $this->titleResolver->getTitle($request, $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT));
+ }
+
return new Response(drupal_render_page($page_callback_result));
}
diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
index 016bddd2865f484ad822c33165e11bf5008c5ac5..0d17aa3da4ff0cd4f660cb5219911babc3f8a093 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
@@ -115,7 +115,7 @@ public function __construct(ControllerResolverInterface $controller_resolver, Re
$this->routeProvider = $route_provider;
$this->accessManager = $access_manager;
$this->alterInfo($module_handler, 'local_tasks');
- $this->setCacheBackend($cache, $language_manager, 'local_task_plugins', array('local_task' => TRUE));
+ $this->setCacheBackend($cache, $language_manager, 'local_task_plugins', array('local_task' => 1));
}
/**
@@ -200,7 +200,7 @@ public function getLocalTasksForRoute($route_name) {
'parents' => $parents,
'children' => $children,
);
- $this->cacheBackend->set($this->cacheKey . ':' . $route_name, $data, CacheBackendInterface::CACHE_PERMANENT, array('local_task'));
+ $this->cacheBackend->set($this->cacheKey . ':' . $route_name, $data, CacheBackendInterface::CACHE_PERMANENT, $this->cacheTags);
}
// Create a plugin instance for each element of the hierarchy.
foreach ($tab_root_ids as $root_id) {
diff --git a/core/modules/action/action.local_tasks.yml b/core/modules/action/action.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b1d0b61829c7a0a8a8217eee9cf7e780511e2592
--- /dev/null
+++ b/core/modules/action/action.local_tasks.yml
@@ -0,0 +1,4 @@
+action.admin:
+ route_name: action.admin
+ title: 'Manage actions'
+ tab_root_id: action.admin
diff --git a/core/modules/action/action.module b/core/modules/action/action.module
index a1f2a144082a72ae163380662bd3b89cb4a4b728..39fd8555f8cd8ff972a7971da78b6106adcdd0f6 100644
--- a/core/modules/action/action.module
+++ b/core/modules/action/action.module
@@ -53,26 +53,6 @@ function action_menu() {
'description' => 'Manage the actions defined for your site.',
'route_name' => 'action.admin',
);
- $items['admin/config/system/actions/manage'] = array(
- 'title' => 'Manage actions',
- 'description' => 'Manage the actions defined for your site.',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['admin/config/system/actions/add'] = array(
- 'title' => 'Create an advanced action',
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- 'route_name' => 'action.admin_add',
- );
- $items['admin/config/system/actions/configure'] = array(
- 'title' => 'Configure an advanced action',
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- 'route_name' => 'action.admin_configure',
- );
- $items['admin/config/system/actions/configure/%/delete'] = array(
- 'title' => 'Delete action',
- 'description' => 'Delete an action.',
- 'route_name' => 'action.delete',
- );
return $items;
}
diff --git a/core/modules/action/tests/Drupal/action/Tests/Menu/ActionLocalTasksTest.php b/core/modules/action/tests/Drupal/action/Tests/Menu/ActionLocalTasksTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..891db5bb868a1b0bbc234acf8efd3704b39bc551
--- /dev/null
+++ b/core/modules/action/tests/Drupal/action/Tests/Menu/ActionLocalTasksTest.php
@@ -0,0 +1,40 @@
+ 'Action local tasks test',
+ 'description' => 'Test action local tasks.',
+ 'group' => 'Action',
+ );
+ }
+
+ public function setUp() {
+ $this->moduleList = array('action' => 'core/modules/action/action.info.yml');
+ parent::setUp();
+ }
+
+ /**
+ * Tests local task existence.
+ */
+ public function testActionLocalTasks() {
+ $this->assertLocalTasks('action.admin', array(array('action.admin')));
+ }
+
+}
diff --git a/core/modules/aggregator/aggregator.local_tasks.yml b/core/modules/aggregator/aggregator.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4de9e517b3f787683cd3b041aa3e1df1b701481a
--- /dev/null
+++ b/core/modules/aggregator/aggregator.local_tasks.yml
@@ -0,0 +1,37 @@
+aggregator.admin_overview:
+ route_name: aggregator.admin_overview
+ title: 'List'
+ tab_root_id: aggregator.admin_overview
+aggregator.admin_settings:
+ route_name: aggregator.admin_settings
+ title: 'Settings'
+ weight: 100
+ tab_root_id: aggregator.admin_overview
+
+aggregator.category_view:
+ route_name: aggregator.category_view
+ tab_root_id: aggregator.category_view
+ title: 'View'
+aggregator.categorize_category_form:
+ route_name: aggregator.categorize_category_form
+ tab_root_id: aggregator.category_view
+ title: Categorize
+aggregator.category_edit:
+ route_name: aggregator.category_edit
+ tab_root_id: aggregator.category_view
+ title: Configure
+ weight: 10
+
+aggregator.feed_view:
+ route_name: aggregator.feed_view
+ tab_root_id: aggregator.feed_view
+ title: View
+aggregator.categorize_feed_form:
+ route_name: aggregator.categorize_feed_form
+ tab_root_id: aggregator.feed_view
+ title: 'Categorize'
+aggregator.feed_configure:
+ route_name: aggregator.feed_configure
+ tab_root_id: aggregator.feed_view
+ title: 'Configure'
+ weight: 10
diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module
index 8938c19e000befec2ae65bb04bbe87a7b4db13b9..045c156aeb0d4eb219a87c1b4bdc89c2356ada1e 100644
--- a/core/modules/aggregator/aggregator.module
+++ b/core/modules/aggregator/aggregator.module
@@ -120,17 +120,6 @@ function aggregator_menu() {
'title' => 'Update items',
'route_name' => 'aggregator.feed_refresh',
);
- $items['admin/config/services/aggregator/list'] = array(
- 'title' => 'List',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['admin/config/services/aggregator/settings'] = array(
- 'title' => 'Settings',
- 'description' => 'Configure the behavior of the feed aggregator, including when to discard feed items and how to present feed items and categories.',
- 'route_name' => 'aggregator.admin_settings',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 100,
- );
$items['aggregator'] = array(
'title' => 'Feed aggregator',
'weight' => 5,
@@ -149,41 +138,11 @@ function aggregator_menu() {
'title arguments' => array(2),
'route_name' => 'aggregator.category_view',
);
- $items['aggregator/categories/%aggregator_category/view'] = array(
- 'title' => 'View',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['aggregator/categories/%aggregator_category/categorize'] = array(
- 'title' => 'Categorize',
- 'type' => MENU_LOCAL_TASK,
- 'route_name' => 'aggregator.categorize_category_form',
- );
- $items['aggregator/categories/%aggregator_category/configure'] = array(
- 'title' => 'Configure',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 10,
- 'route_name' => 'aggregator.category_edit',
- );
$items['aggregator/sources/%aggregator_feed'] = array(
'title callback' => 'entity_page_label',
'title arguments' => array(2),
'route_name' => 'aggregator.feed_view',
);
- $items['aggregator/sources/%aggregator_feed/view'] = array(
- 'title' => 'View',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['aggregator/sources/%aggregator_feed/categorize'] = array(
- 'title' => 'Categorize',
- 'route_name' => 'aggregator.categorize_feed_form',
- 'type' => MENU_LOCAL_TASK,
- );
- $items['aggregator/sources/%aggregator_feed/configure'] = array(
- 'title' => 'Configure',
- 'route_name' => 'aggregator.feed_configure',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 10,
- );
$items['admin/config/services/aggregator/edit/feed/%aggregator_feed'] = array(
'title' => 'Edit feed',
'route_name' => 'aggregator.feed_edit',
diff --git a/core/modules/aggregator/tests/Drupal/aggregator/Tests/Menu/AggregatorLocalTasksTest.php b/core/modules/aggregator/tests/Drupal/aggregator/Tests/Menu/AggregatorLocalTasksTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..67bedd87cfa124d421ad4dc01144f17e486b2b60
--- /dev/null
+++ b/core/modules/aggregator/tests/Drupal/aggregator/Tests/Menu/AggregatorLocalTasksTest.php
@@ -0,0 +1,100 @@
+ 'Aggregator local tasks test',
+ 'description' => 'Test existence of aggregator local tasks.',
+ 'group' => 'Aggregator',
+ );
+ }
+
+ public function setUp() {
+ $this->moduleList = array('aggregator' => 'core/modules/aggregator/aggregator.info.yml');
+ parent::setUp();
+ }
+
+ /**
+ * Tests local task existence.
+ *
+ * @dataProvider getAggregatorAdminRoutes
+ */
+ public function testAggregatorAdminLocalTasks($route) {
+ $this->assertLocalTasks($route, array(
+ 0 => array('aggregator.admin_overview', 'aggregator.admin_settings'),
+ ));
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function getAggregatorAdminRoutes() {
+ return array(
+ array('aggregator.admin_overview'),
+ array('aggregator.admin_settings'),
+ );
+ }
+
+ /**
+ * Checks aggregator category tasks.
+ *
+ * @dataProvider getAggregatorCategoryRoutes
+ */
+ public function testAggregatorCategoryLocalTasks($route) {
+ $this->assertLocalTasks($route, array(
+ 0 => array('aggregator.category_view', 'aggregator.categorize_category_form', 'aggregator.category_edit'),
+ ));
+ ;
+ }
+
+ /**
+ * Provides a list of category routes to test.
+ */
+ public function getAggregatorCategoryRoutes() {
+ return array(
+ array('aggregator.category_view'),
+ array('aggregator.categorize_category_form'),
+ array('aggregator.category_edit'),
+ );
+ }
+
+ /**
+ * Checks aggregator source tasks.
+ *
+ * @dataProvider getAggregatorSourceRoutes
+ */
+ public function testAggregatorSourceLocalTasks($route) {
+ $this->assertLocalTasks($route, array(
+ 0 => array('aggregator.feed_view', 'aggregator.categorize_feed_form', 'aggregator.feed_configure'),
+ ));
+ ;
+ }
+
+ /**
+ * Provides a list of source routes to test.
+ */
+ public function getAggregatorSourceRoutes() {
+ return array(
+ array('aggregator.feed_view'),
+ array('aggregator.categorize_feed_form'),
+ array('aggregator.feed_configure'),
+ );
+ }
+
+}
diff --git a/core/modules/block/block.local_tasks.yml b/core/modules/block/block.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3fdea89d937a1595269dc673c5d371a88b8b2eaf
--- /dev/null
+++ b/core/modules/block/block.local_tasks.yml
@@ -0,0 +1,16 @@
+block.admin_edit:
+ title: 'Configure block'
+ route_name: block.admin_edit
+ tab_root_id: block.admin_edit
+
+# Per theme block layout pages.
+block.admin_display:
+ title: 'Block Layout'
+ route_name: block.admin_display
+ tab_root_id: block.admin_display
+block.admin_display_theme:
+ title: 'Block Layout'
+ route_name: block.admin_display_theme
+ tab_root_id: block.admin_display
+ tab_parent_id: block.admin_display
+ derivative: 'Drupal\block\Plugin\Derivative\ThemeLocalTask'
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index 6786cc0e9944d4a17f111f963c22ab89f5b3f49e..4d9643088657bd2ef7e515a166b85f4e0e77359e 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -99,16 +99,11 @@ function block_permission() {
* @todo Clarify the documentation for the per-plugin block admin links.
*/
function block_menu() {
- $default_theme = \Drupal::config('system.theme')->get('default');
$items['admin/structure/block'] = array(
'title' => 'Block layout',
'description' => 'Configure what block content appears in your site\'s sidebars and other regions.',
'route_name' => 'block.admin_display',
);
- $items['admin/structure/block/list'] = array(
- 'title' => 'Block layout',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
$items['admin/structure/block/manage/%block'] = array(
'title' => 'Configure block',
'route_name' => 'block.admin_edit',
@@ -116,7 +111,7 @@ function block_menu() {
$items['admin/structure/block/manage/%block/configure'] = array(
'title' => 'Configure block',
'type' => MENU_DEFAULT_LOCAL_TASK,
- 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+ 'context' => MENU_CONTEXT_INLINE,
);
$items['admin/structure/block/add/%/%'] = array(
'title' => 'Place block',
@@ -126,15 +121,9 @@ function block_menu() {
// Block administration is tied to the theme and plugin definition so
// that the plugin can appropriately attach to this URL structure.
// @todo D8: Use dynamic % arguments instead of static, hard-coded theme names
- // and plugin IDs to decouple the routes from these dependencies and allow
- // hook_menu_local_tasks() to check for the untranslated tab_parent path.
+ // and plugin IDs to decouple the routes from these dependencies.
// @see http://drupal.org/node/1067408
foreach (list_themes() as $key => $theme) {
- $items["admin/structure/block/list/$key"] = array(
- 'title' => check_plain($theme->info['name']),
- 'type' => $key == $default_theme ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
- 'route_name' => "block.admin_display_$key",
- );
$items["admin/structure/block/demo/$key"] = array(
'route_name' => 'block.admin_demo',
'type' => MENU_CALLBACK,
diff --git a/core/modules/block/block.routing.yml b/core/modules/block/block.routing.yml
index 87ed0baa95a6235261823a6e3a404b7ccfa9076b..9c5a380824e0d7dfd25a5cdfbd0c6e13c5fecae1 100644
--- a/core/modules/block/block.routing.yml
+++ b/core/modules/block/block.routing.yml
@@ -28,6 +28,14 @@ block.admin_display:
requirements:
_permission: 'administer blocks'
+block.admin_display_theme:
+ path: 'admin/structure/block/list/{theme}'
+ defaults:
+ _controller: '\Drupal\block\Controller\BlockListController::listing'
+ requirements:
+ _access_theme: 'TRUE'
+ _permission: 'administer blocks'
+
block.admin_add:
path: '/admin/structure/block/add/{plugin_id}/{theme}'
defaults:
diff --git a/core/modules/block/block.services.yml b/core/modules/block/block.services.yml
index c6704bc7af7bdf523721f8606b818fc23445d951..b6bf1f41d373427fe61239426e9ceb29a5956aeb 100644
--- a/core/modules/block/block.services.yml
+++ b/core/modules/block/block.services.yml
@@ -9,7 +9,3 @@ services:
factory_method: get
factory_service: cache_factory
arguments: [block]
- block.route_subscriber:
- class: Drupal\block\Routing\RouteSubscriber
- tags:
- - { name: event_subscriber}
diff --git a/core/modules/block/custom_block/custom_block.local_actions.yml b/core/modules/block/custom_block/custom_block.local_actions.yml
index 531668eed0a7c537b4b54e9d8a09d5192616a1f2..b12329c281831c2889883d4fd86d9034dbf90aa8 100644
--- a/core/modules/block/custom_block/custom_block.local_actions.yml
+++ b/core/modules/block/custom_block/custom_block.local_actions.yml
@@ -9,3 +9,6 @@ custom_block_add_action:
title: 'Add custom block'
appears_on:
- block.admin_display
+ - block.admin_display_theme
+ class: \Drupal\custom_block\Plugin\Menu\LocalAction\CustomBlockAddLocalAction
+
diff --git a/core/modules/block/custom_block/custom_block.local_tasks.yml b/core/modules/block/custom_block/custom_block.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9bee9a4c64fcc519a3d136e853749d8ad9a88c1d
--- /dev/null
+++ b/core/modules/block/custom_block/custom_block.local_tasks.yml
@@ -0,0 +1,29 @@
+custom_block.list:
+ title: 'Custom block library'
+ route_name: custom_block.list
+ tab_root_id: block.admin_display
+custom_block.list_sub:
+ title: Blocks
+ route_name: custom_block.list
+ tab_root_id: block.admin_display
+ tab_parent_id: custom_block.list
+custom_block.type_list:
+ title: Types
+ route_name: custom_block.type_list
+ tab_root_id: block.admin_display
+ tab_parent_id: custom_block.list
+
+custom_block.edit:
+ title: Edit
+ route_name: custom_block.edit
+ tab_root_id: custom_block.edit
+custom_block.delete:
+ title: Delete
+ route_name: custom_block.delete
+ tab_root_id: custom_block.edit
+
+# Default tab for custom block type editing.
+custom_block.type_edit:
+ title: 'Edit'
+ route_name: custom_block.type_edit
+ tab_root_id: custom_block.type_edit
diff --git a/core/modules/block/custom_block/custom_block.module b/core/modules/block/custom_block/custom_block.module
index d55d27971ba080f18c3869e7d9445177214160a3..03d984000b516e47b2ed7fcbfd99686619cb610a 100644
--- a/core/modules/block/custom_block/custom_block.module
+++ b/core/modules/block/custom_block/custom_block.module
@@ -54,23 +54,6 @@ function custom_block_menu_local_tasks(&$data, $route_name) {
);
}
}
-
- $routes = array_map(function ($theme) {
- return "block.admin_display_$theme";
- }, array_keys(list_themes()));
- if (in_array($route_name, $routes)) {
- // @todo Move to a LocalAction plugin when https://drupal.org/node/2045267
- // allows local actions to work with query strings.
- $item = menu_get_item('block/add');
- if ($item['access']) {
- // Add a destination parameter.
- $item['localized_options']['query']['theme'] = \Drupal::request()->attributes->get('theme');
- $data['actions']['block/add'] = array(
- '#theme' => 'menu_local_action',
- '#link' => $item,
- );
- }
- }
}
/**
@@ -81,42 +64,22 @@ function custom_block_menu() {
'title' => 'Custom block library',
'description' => 'Manage custom blocks.',
'route_name' => 'custom_block.list',
- 'type' => MENU_LOCAL_TASK | MENU_NORMAL_ITEM,
- );
- $items['admin/structure/block/custom-blocks/list'] = array(
- 'title' => 'Blocks',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['admin/structure/block/custom-blocks/types'] = array(
- 'title' => 'Types',
- 'route_name' => 'custom_block.type_list',
- 'type' => MENU_LOCAL_TASK,
- );
- $items['admin/structure/block/custom-blocks/types/add'] = array(
- 'route_name' => 'custom_block.type_add',
- 'type' => MENU_SIBLING_LOCAL_TASK,
- 'weight' => 1,
+ 'type' => MENU_NORMAL_ITEM,
);
+
$items['admin/structure/block/custom-blocks/manage/%custom_block_type'] = array(
'title' => 'Edit custom block type',
'title callback' => 'entity_page_label',
'title arguments' => array(5),
'route_name' => 'custom_block.type_edit',
);
- $items['admin/structure/block/custom-blocks/manage/%custom_block_type/edit'] = array(
- 'title' => 'Edit',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- );
+
$items['block/add'] = array(
- 'title' => 'Add custom block',
- 'route_name' => 'custom_block.add_page',
- );
- $items['block/add/%custom_block_type'] = array(
'title' => 'Add custom block',
'description' => 'Add custom block',
- 'route_name' => 'custom_block.add_form'
+ 'route_name' => 'custom_block.add_page',
);
+
// There has to be a base-item in order for contextual links to work.
$items['block/%custom_block'] = array(
'title' => 'Edit',
@@ -126,7 +89,7 @@ function custom_block_menu() {
'title' => 'Edit',
'weight' => 0,
'type' => MENU_DEFAULT_LOCAL_TASK,
- 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+ 'context' => MENU_CONTEXT_INLINE,
);
$items['block/%custom_block/delete'] = array(
'title' => 'Delete',
diff --git a/core/modules/block/custom_block/custom_block.routing.yml b/core/modules/block/custom_block/custom_block.routing.yml
index ca9586a46f771f08c199533ae4288839e933be5a..f395409faaffc151df174e164e507a574183f1be 100644
--- a/core/modules/block/custom_block/custom_block.routing.yml
+++ b/core/modules/block/custom_block/custom_block.routing.yml
@@ -33,7 +33,6 @@ custom_block.edit:
_entity_form: 'custom_block.edit'
requirements:
_entity_access: 'custom_block.update'
- custom_block: \d+
custom_block.delete:
path: '/block/{custom_block}/delete'
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php
index e37328ddcad4b36038ded334dcf58804fe146321..12f2b7218d87119b75f05be73b91599837b2836a 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Derivative/CustomBlock.php
@@ -8,6 +8,7 @@
namespace Drupal\custom_block\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DerivativeBase;
+use Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface;
/**
* Retrieves block plugin definitions for all custom blocks.
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..c2b773a4b60a84433759694fd2860310854a8cb9
--- /dev/null
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Menu/LocalAction/CustomBlockAddLocalAction.php
@@ -0,0 +1,30 @@
+attributes->has('theme')) {
+ $options['query']['theme'] = $request->attributes->get('theme');
+ }
+ return $options;
+ }
+
+}
diff --git a/core/modules/block/custom_block/tests/Drupal/custom_blocks/Tests/Menu/CustomBlockLocalTasksTest.php b/core/modules/block/custom_block/tests/Drupal/custom_blocks/Tests/Menu/CustomBlockLocalTasksTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..96866fd4efbfdcc81e12a736a181b1d457506c8b
--- /dev/null
+++ b/core/modules/block/custom_block/tests/Drupal/custom_blocks/Tests/Menu/CustomBlockLocalTasksTest.php
@@ -0,0 +1,64 @@
+ 'Custom Block local tasks test',
+ 'description' => 'Test custom_block local tasks.',
+ 'group' => 'Block',
+ );
+ }
+
+ public function setUp() {
+ $this->moduleList = array(
+ 'block' => 'core/modules/block/block.info.yml',
+ 'custom_block' => 'core/modules/block/custom_block/custom_block.info.yml',
+ );
+ parent::setUp();
+ }
+
+ /**
+ * Checks custom_block listing local tasks.
+ *
+ * @dataProvider getCustomBlockListingRoutes
+ */
+ public function testCustomBlockListLocalTasks($route) {
+ //
+ $this->assertLocalTasks($route, array(
+ 0 => array(
+ 'block.admin_display',
+ 'custom_block.list',
+ ),
+ 1 => array(
+ 'custom_block.list_sub',
+ 'custom_block.type_list',
+ )
+ ));
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function getCustomBlockListingRoutes() {
+ return array(
+ array('custom_block.list', 'custom_block.type_list'),
+ );
+ }
+
+}
diff --git a/core/modules/block/lib/Drupal/block/Plugin/Derivative/ThemeLocalTask.php b/core/modules/block/lib/Drupal/block/Plugin/Derivative/ThemeLocalTask.php
new file mode 100644
index 0000000000000000000000000000000000000000..77a223570f64101c3e11312a3255283ab2825eff
--- /dev/null
+++ b/core/modules/block/lib/Drupal/block/Plugin/Derivative/ThemeLocalTask.php
@@ -0,0 +1,69 @@
+config = $config_factory->get('system.theme');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container, $base_plugin_id) {
+ return new static($container->get('config.factory'));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDerivativeDefinitions(array $base_plugin_definition) {
+ $default_theme = $this->config->get('default');
+
+ foreach (list_themes() as $theme_name => $theme) {
+ if ($theme->status) {
+ $this->derivatives[$theme_name] = $base_plugin_definition;
+ $this->derivatives[$theme_name]['title'] = $theme->info['name'];
+ $this->derivatives[$theme_name]['route_parameters'] = array('theme' => $theme_name);
+ }
+ // Default task!
+ if ($default_theme == $theme_name) {
+ $this->derivatives[$theme_name]['route_name'] = 'block.admin_display';
+ // Emulate default logic because without the base plugin id we can't set the
+ // change the tab_root_id.
+ $this->derivatives[$theme_name]['weight'] = -10;
+
+ unset($this->derivatives[$theme_name]['route_parameters']);
+ }
+ }
+ return $this->derivatives;
+ }
+
+}
diff --git a/core/modules/block/tests/Drupal/block/Tests/Menu/BlockLocalTasksTest.php b/core/modules/block/tests/Drupal/block/Tests/Menu/BlockLocalTasksTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..59b26f89488b19a9f8bcd40571e03d09356301fb
--- /dev/null
+++ b/core/modules/block/tests/Drupal/block/Tests/Menu/BlockLocalTasksTest.php
@@ -0,0 +1,91 @@
+ 'Block local tasks test',
+ 'description' => 'Test block local tasks.',
+ 'group' => 'Block',
+ );
+ }
+
+ public function setUp() {
+ $this->moduleList = array('block' => 'core/modules/block/block.info.yml');
+ parent::setUp();
+
+ $config_factory = $this->getConfigFactoryStub(array('system.theme' => array(
+ 'default' => 'test_c',
+ )));
+ \Drupal::getContainer()->set('config.factory', $config_factory);
+ }
+
+ /**
+ * Tests the admin edit local task.
+ */
+ public function testBlockAdminLocalTasks() {
+ $this->assertLocalTasks('block.admin_edit', array(array('block.admin_edit')));
+ }
+
+ /**
+ * Tests the block admin display local tasks.
+ *
+ * @dataProvider providerTestBlockAdminDisplay
+ */
+ public function testBlockAdminDisplay($route, $expected) {
+ $this->assertLocalTasks($route, $expected);
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function providerTestBlockAdminDisplay() {
+ return array(
+ array('block.admin_display', array(array('block.admin_display'), array('block.admin_display_theme:test_b', 'block.admin_display_theme:test_c'))),
+ array('block.admin_display_theme', array(array('block.admin_display'), array('block.admin_display_theme:test_b', 'block.admin_display_theme:test_c'))),
+ );
+ }
+
+}
+
+}
+
+namespace {
+ if (!function_exists('list_themes')) {
+ function list_themes() {
+ $themes = array();
+ $themes['test_a'] = (object) array(
+ 'status' => 0,
+ );
+ $themes['test_b'] = (object) array(
+ 'status' => 1,
+ 'info' => array(
+ 'name' => 'test_b',
+ ),
+ );
+ $themes['test_c'] = (object) array(
+ 'status' => 1,
+ 'info' => array(
+ 'name' => 'test_c',
+ ),
+ );
+
+ return $themes;
+ }
+ }
+}
diff --git a/core/modules/book/book.local_tasks.yml b/core/modules/book/book.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f0f84644712f41eefc8f3cd0c3f3ac6f678e4ab1
--- /dev/null
+++ b/core/modules/book/book.local_tasks.yml
@@ -0,0 +1,15 @@
+book.admin:
+ route_name: book.admin
+ title: 'List'
+ tab_root_id: book.admin
+book.settings:
+ route_name: book.settings
+ title: 'Settings'
+ tab_root_id: book.admin
+ weight: 100
+
+book.outline:
+ route_name: book.outline
+ tab_root_id: node.view
+ title: Outline
+ weight: 2
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index 169876daf01cf8655e39e2053490b04994d74887..cd7d71487f0c9f525211f519f00de04e6077ad1e 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -171,28 +171,11 @@ function book_menu() {
'description' => "Manage your site's book outlines.",
'route_name' => 'book.admin',
);
- $items['admin/structure/book/list'] = array(
- 'title' => 'List',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['admin/structure/book/settings'] = array(
- 'title' => 'Settings',
- 'route_name' => 'book.settings',
- 'access arguments' => array('administer site configuration'),
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 100,
- );
$items['book'] = array(
'title' => 'Books',
'route_name' => 'book.render',
'type' => MENU_SUGGESTED_ITEM,
);
- $items['node/%node/outline'] = array(
- 'title' => 'Outline',
- 'route_name' => 'book.outline',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 2,
- );
$items['node/%node/outline/remove'] = array(
'title' => 'Remove from outline',
'route_name' => 'book.remove',
diff --git a/core/modules/book/tests/Drupal/book/Tests/Menu/BookLocalTasksTest.php b/core/modules/book/tests/Drupal/book/Tests/Menu/BookLocalTasksTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2f8d7491611fe1f55b16629d1f71485ff291f234
--- /dev/null
+++ b/core/modules/book/tests/Drupal/book/Tests/Menu/BookLocalTasksTest.php
@@ -0,0 +1,79 @@
+ 'Book local tasks test',
+ 'description' => 'Test existence of book local tasks.',
+ 'group' => 'Book',
+ );
+ }
+
+ public function setUp() {
+ $this->moduleList = array(
+ 'book' => 'core/modules/book/book.info.yml',
+ 'node' => 'core/modules/node/node.info.yml',
+ );
+ parent::setUp();
+ }
+
+ /**
+ * Tests local task existence.
+ *
+ * @dataProvider getBookAdminRoutes
+ */
+ public function testBookAdminLocalTasks($route) {
+
+ $this->assertLocalTasks($route, array(
+ 0 => array('book.admin', 'book.settings'),
+ ));
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function getBookAdminRoutes() {
+ return array(
+ array('book.admin'),
+ array('book.settings'),
+ );
+ }
+
+ /**
+ * Tests local task existence.
+ *
+ * @dataProvider getBookNodeRoutes
+ */
+ public function testBookNodeLocalTasks($route) {
+ $this->assertLocalTasks($route, array(
+ 0 => array('book.outline', 'node.view', 'node.page_edit', 'node.delete_confirm', 'node.revision_overview',),
+ ));
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function getBookNodeRoutes() {
+ return array(
+ array('node.view'),
+ array('book.outline'),
+ );
+ }
+
+}
diff --git a/core/modules/comment/lib/Drupal/comment/CommentFormController.php b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
index efb0e8e2ea024a2d58eecc810e193bdf15767c0a..6c9bf18760ea1ddb4ebd71042e97207dbeeb62e8 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentFormController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentFormController.php
@@ -355,8 +355,8 @@ public function submit(array $form, array &$form_state) {
*/
public function preview(array $form, array &$form_state) {
$comment = $this->entity;
- drupal_set_title(t('Preview comment'), PASS_THROUGH);
$form_state['comment_preview'] = comment_preview($comment);
+ $form_state['comment_preview']['#title'] = $this->t('Preview comment');
$form_state['rebuild'] = TRUE;
}
diff --git a/core/modules/config/config.local_tasks.yml b/core/modules/config/config.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..98ee75bb8257a7906ff96868b71b8707a734a96b
--- /dev/null
+++ b/core/modules/config/config.local_tasks.yml
@@ -0,0 +1,15 @@
+config.sync:
+ route_name: config.sync
+ tab_root_id: config.sync
+ title: 'Synchronize'
+ weight: 0
+config.export:
+ route_name: config.export
+ tab_root_id: config.sync
+ title: Export
+ weight: 1
+config.import:
+ route_name: config.import
+ title: Import
+ tab_root_id: config.sync
+ weight: 2
diff --git a/core/modules/config/config.module b/core/modules/config/config.module
index 5e93c02fe88ae35e5ac73dbe106c699e57515f8a..76deec4df1e88ab2b7e33a20635784d2adc84a10 100644
--- a/core/modules/config/config.module
+++ b/core/modules/config/config.module
@@ -64,37 +64,8 @@ function config_menu() {
$items['admin/config/development/configuration'] = array(
'title' => 'Configuration management',
'description' => 'Import, export, or synchronize your site configuration.',
- 'route_name' => 'config_management',
- );
- $items['admin/config/development/configuration/sync'] = array(
- 'title' => 'Synchronize',
- 'description' => 'Synchronize configuration changes.',
'route_name' => 'config.sync',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => 0,
- );
- $items['admin/config/development/configuration/export'] = array(
- 'title' => 'Export',
- 'description' => 'Export your site configuration',
- 'route_name' => 'config.export',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 1,
- );
- $items['admin/config/development/configuration/import'] = array(
- 'title' => 'Import',
- 'description' => 'Import configuration for your site',
- 'route_name' => 'config.import',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 2,
- );
- $items['admin/config/development/configuration/sync/diff/%'] = array(
- 'title' => 'Configuration file diff',
- 'description' => 'Diff between active and staged configuration.',
- 'route_name' => 'config.diff',
- );
- $items['admin/config/development/configuration/sync/import'] = array(
- 'title' => 'Import',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
);
+
return $items;
}
diff --git a/core/modules/config/config.routing.yml b/core/modules/config/config.routing.yml
index 9bff7a1b727aa737f04971038c9415fdf2634fb7..23b241118dadbab0344eee4abf84de3c2118df66 100644
--- a/core/modules/config/config.routing.yml
+++ b/core/modules/config/config.routing.yml
@@ -1,14 +1,15 @@
-config.diff:
- path: '/admin/config/development/configuration/sync/diff/{config_file}'
+config.sync:
+ path: '/admin/config/development/configuration'
defaults:
- _content: '\Drupal\config\Controller\ConfigController::diff'
+ _form: '\Drupal\config\Form\ConfigSync'
+ _title: 'Synchronize'
requirements:
_permission: 'synchronize configuration'
-config_management:
- path: '/admin/config/development/configuration'
+config.diff:
+ path: '/admin/config/development/configuration/sync/diff/{config_file}'
defaults:
- _form: '\Drupal\config\Form\ConfigSync'
+ _content: '\Drupal\config\Controller\ConfigController::diff'
requirements:
_permission: 'synchronize configuration'
@@ -34,11 +35,3 @@ config.import:
_title: 'Import'
requirements:
_permission: 'import configuration'
-
-config.sync:
- path: '/admin/config/development/configuration/sync'
- defaults:
- _form: '\Drupal\config\Form\ConfigSync'
- _title: 'Synchronize'
- requirements:
- _permission: 'synchronize configuration'
diff --git a/core/modules/config/lib/Drupal/config/Controller/ConfigController.php b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php
index e030b46ca368078404dd776ff743a2839c099ad9..a1e8510d730482120065611cf001ebd94f5b0f9c 100644
--- a/core/modules/config/lib/Drupal/config/Controller/ConfigController.php
+++ b/core/modules/config/lib/Drupal/config/Controller/ConfigController.php
@@ -121,7 +121,7 @@ public function diff($config_file) {
),
),
'#title' => "Back to 'Synchronize configuration' page.",
- '#href' => 'admin/config/development/configuration/sync',
+ '#href' => 'admin/config/development/configuration',
);
return $build;
diff --git a/core/modules/config/lib/Drupal/config/Form/ConfigImportForm.php b/core/modules/config/lib/Drupal/config/Form/ConfigImportForm.php
index 310091932c75b404828d4da0d03232a626f02ae7..2d5c4a882a1f958c5469dad5887ca90cb5478a3d 100644
--- a/core/modules/config/lib/Drupal/config/Form/ConfigImportForm.php
+++ b/core/modules/config/lib/Drupal/config/Form/ConfigImportForm.php
@@ -96,7 +96,7 @@ public function submitForm(array &$form, array &$form_state) {
}
$archiver->extractList($files, config_get_config_directory(CONFIG_STAGING_DIRECTORY));
drupal_set_message($this->t('Your configuration files were successfully uploaded, ready for import.'));
- $form_state['redirect'] = 'admin/config/development/configuration/sync';
+ $form_state['redirect'] = 'admin/config/development/configuration';
}
catch (\Exception $e) {
form_set_error('import_tarball', $this->t('Could not extract the contents of the tar file. The error message is @message', array('@message' => $e->getMessage())));
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php
index 58fc2d5c09bfe9d9f61b863c9568755f733a204b..0148011bf4a4f25fa6a58c51d870f4a648fe4344 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigImportUITest.php
@@ -41,7 +41,7 @@ function testImport() {
$storage = $this->container->get('config.storage');
$staging = $this->container->get('config.storage.staging');
- $this->drupalGet('admin/config/development/configuration/sync');
+ $this->drupalGet('admin/config/development/configuration');
$this->assertText('There are no configuration changes.');
$this->assertNoFieldById('edit-submit', t('Import all'));
@@ -65,7 +65,7 @@ function testImport() {
$this->assertIdentical($staging->exists($dynamic_name), TRUE, $dynamic_name . ' found.');
// Verify that both appear as ready to import.
- $this->drupalGet('admin/config/development/configuration/sync');
+ $this->drupalGet('admin/config/development/configuration');
$this->assertText($name);
$this->assertText($dynamic_name);
$this->assertFieldById('edit-submit', t('Import all'));
@@ -98,7 +98,7 @@ function testImportLock() {
$this->prepareSiteNameUpdate($new_site_name);
// Verify that there are configuration differences to import.
- $this->drupalGet('admin/config/development/configuration/sync');
+ $this->drupalGet('admin/config/development/configuration');
$this->assertNoText(t('There are no configuration changes.'));
// Acquire a fake-lock on the import mechanism.
diff --git a/core/modules/config/tests/Drupal/config/Tests/Menu/ConfigLocalTasksTest.php b/core/modules/config/tests/Drupal/config/Tests/Menu/ConfigLocalTasksTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ad00f103ffaba9aa1b8dbe57a18bfec7d589a365
--- /dev/null
+++ b/core/modules/config/tests/Drupal/config/Tests/Menu/ConfigLocalTasksTest.php
@@ -0,0 +1,53 @@
+ 'Config local tasks test',
+ 'description' => 'Test existence of config local tasks.',
+ 'group' => 'config',
+ );
+ }
+
+ public function setUp() {
+ $this->moduleList = array('config' => 'core/modules/config/config.info.yml');
+ parent::setUp();
+ }
+
+ /**
+ * Tests config local tasks existence.
+ *
+ * @dataProvider getConfigAdminRoutes
+ */
+ public function testConfigAdminLocalTasks($route, $expected) {
+ $this->assertLocalTasks($route, $expected);
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function getConfigAdminRoutes() {
+ return array(
+ array('config.sync', array(array('config.sync', 'config.export', 'config.import'))),
+ array('config.export', array(array('config.sync', 'config.export', 'config.import'))),
+ array('config.import', array(array('config.sync', 'config.export', 'config.import'))),
+ );
+ }
+
+}
diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 661aac9290c92e91e559fd9c8acc524d2efedd71..b31b8d8cb2bb917d6ef5a8d19aca56d2c7d63aac 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -5,6 +5,7 @@
* Allows entities to be translated into different languages.
*/
+use Drupal\content_translation\Plugin\Derivative\ContentTranslationLocalTasks;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityFormControllerInterface;
use Drupal\Core\Entity\EntityInterface;
@@ -276,6 +277,15 @@ function content_translation_menu_alter(array &$items) {
}
}
+/**
+ * Implements hook_local_tasks_alter().
+ */
+function content_translation_local_tasks_alter(&$local_tasks) {
+ // Alters in tab_root_id onto the content translation local task.
+ $derivative = ContentTranslationLocalTasks::create(\Drupal::getContainer(), 'content_translation.local_tasks');
+ $derivative->alterLocalTasks($local_tasks);
+}
+
/**
* Strips out menu loaders from the given path.
*
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Plugin/ContentTranslationLocalTasks.php b/core/modules/content_translation/lib/Drupal/content_translation/Plugin/ContentTranslationLocalTasks.php
index 50c4c60a4e2f1dea40a0e2456367bfafc2ebe68b..172b6be1b584a364901a16f20837eaaa1e3e758c 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Plugin/ContentTranslationLocalTasks.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Plugin/ContentTranslationLocalTasks.php
@@ -15,27 +15,4 @@
*/
class ContentTranslationLocalTasks extends LocalTaskDefault {
- /**
- * {@inheritdoc}
- */
- public function getRouteParameters(Request $request) {
- $parameters = parent::getRouteParameters($request);
- $entity_type = $this->pluginDefinition['entity_type'];
- if ($raw_variables = $request->attributes->get('_raw_variables')) {
- // When the entity type is in the path, populate 'entity' for any dynamic
- // local tasks.
- if ($raw_variables->has($entity_type)) {
- $entity = $raw_variables->get($entity_type);
- $parameters['entity'] = $entity;
- }
- // When 'entity' is in the path, populate the parameters with the value
- // for the actual entity type.
- elseif ($raw_variables->has('entity')) {
- $entity = $raw_variables->get('entity');
- $parameters[$entity_type] = $entity;
- }
- }
- return $parameters;
- }
-
}
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Plugin/Derivative/ContentTranslationLocalTasks.php b/core/modules/content_translation/lib/Drupal/content_translation/Plugin/Derivative/ContentTranslationLocalTasks.php
index 1cc9e66ab08b3756132711cea560ca32e0781beb..558bdfdac8a0e509a9145aa63cc005a7ce634f1a 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Plugin/Derivative/ContentTranslationLocalTasks.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Plugin/Derivative/ContentTranslationLocalTasks.php
@@ -32,17 +32,27 @@ class ContentTranslationLocalTasks extends DerivativeBase implements ContainerDe
*/
protected $routeProvider;
+ /**
+ * The base plugin ID
+ *
+ * @var string
+ */
+ protected $basePluginId;
+
/**
* Constructs a new ContentTranslationLocalTasks.
*
+ * @param string $base_plugin_id
+ * The base plugin ID.
* @param \Drupal\Core\Entity\EntityManager $entity_manager
* The entity manager.
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
* The route provider.
*/
- public function __construct(EntityManager $entity_manager, RouteProviderInterface $route_provider) {
+ public function __construct($base_plugin_id, EntityManager $entity_manager, RouteProviderInterface $route_provider) {
$this->entityManager = $entity_manager;
$this->routeProvider = $route_provider;
+ $this->basePluginId = $base_plugin_id;
}
/**
@@ -50,6 +60,7 @@ public function __construct(EntityManager $entity_manager, RouteProviderInterfac
*/
public static function create(ContainerInterface $container, $base_plugin_id) {
return new static(
+ $base_plugin_id,
$container->get('entity.manager'),
$container->get('router.route_provider')
);
@@ -60,33 +71,74 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
*/
public function getDerivativeDefinitions(array $base_plugin_definition) {
// Create tabs for all possible entity types.
+ foreach ($this->entityManager->getDefinitions() as $entity_type => $entity_info) {
+ if ($entity_info['translatable'] && isset($entity_info['translation'])) {
+ // Find the route name for the translation overview.
+ $translation_route_name = "content_translation.translation_overview_$entity_type";
+ $translation_tab = $translation_route_name;
+
+ $this->derivatives[$translation_tab] = $base_plugin_definition + array(
+ 'entity_type' => $entity_type,
+ );
+ $this->derivatives[$translation_tab]['title'] = 'Translate';
+ $this->derivatives[$translation_tab]['route_name'] = $translation_route_name;
+ }
+ }
+ return parent::getDerivativeDefinitions($base_plugin_definition);
+ }
+
+ /**
+ * Alters the local tasks to find the proper tab_root_id for each task.
+ */
+ public function alterLocalTasks(array &$local_tasks) {
foreach ($this->entityManager->getDefinitions() as $entity_type => $entity_info) {
if ($entity_info['translatable'] && isset($entity_info['translation'])) {
$path = '/' . preg_replace('/%(.*)/', '{$1}', $entity_info['menu_base_path']);
if ($routes = $this->routeProvider->getRoutesByPattern($path)->all()) {
// Find the route name for the entity page.
$entity_route_name = key($routes);
- $entity_tab = $entity_route_name . '_tab';
+
// Find the route name for the translation overview.
$translation_route_name = "content_translation.translation_overview_$entity_type";
- $translation_tab = $translation_route_name . '_tab';
-
- // Both tabs will have the same root and entity type.
- $common_tab_settings = array(
- 'tab_root_id' => $entity_tab,
- 'entity_type' => $entity_type,
- );
- $this->derivatives[$entity_tab] = $base_plugin_definition + $common_tab_settings;
- $this->derivatives[$entity_tab]['title'] = t('Edit');
- $this->derivatives[$entity_tab]['route_name'] = $entity_route_name;
-
- $this->derivatives[$translation_tab] = $base_plugin_definition + $common_tab_settings;
- $this->derivatives[$translation_tab]['title'] = t('Translate');
- $this->derivatives[$translation_tab]['route_name'] = $translation_route_name;
+ $translation_tab = $this->basePluginId . ':' . $translation_route_name;
+
+ $local_tasks[$translation_tab]['tab_root_id'] = $this->getTaskFromRoute($entity_route_name, $local_tasks);
}
}
}
- return parent::getDerivativeDefinitions($base_plugin_definition);
}
+ /**
+ * Find the local task ID of the parent route given the route name.
+ *
+ * @param string $route_name
+ * The route name of the parent local task.
+ * @param array $local_tasks
+ * An array of all local task definitions.
+ *
+ * @return bool|string
+ * Returns the local task ID of the parent task, otherwise return FALSE.
+ */
+ protected function getTaskFromRoute($route_name, &$local_tasks) {
+ $local_task = FALSE;
+ foreach ($local_tasks as $plugin_id => $local_task) {
+ if ($local_task['route_name'] == $route_name) {
+ $local_task = $plugin_id;
+ break;
+ }
+ }
+
+ return $local_task;
+ }
+
+ /**
+ * Translates a string to the current language or to a given language.
+ *
+ * See the t() documentation for details.
+ *
+ * @todo Move to derivative base. https://drupal.org/node/2112575
+ */
+ public function t($string, array $args = array(), array $options = array()) {
+ \Drupal::translation()->translate($string, $args, $options);
+ }
}
diff --git a/core/modules/content_translation/tests/Drupal/content_translation/Tests/Menu/ContentTranslationLocalTasksTest.php b/core/modules/content_translation/tests/Drupal/content_translation/Tests/Menu/ContentTranslationLocalTasksTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..cde6985a964f637ac8eb73aaf1b1b6374f822de2
--- /dev/null
+++ b/core/modules/content_translation/tests/Drupal/content_translation/Tests/Menu/ContentTranslationLocalTasksTest.php
@@ -0,0 +1,110 @@
+ 'Content translation local tasks test',
+ 'description' => 'Test content translation local tasks.',
+ 'group' => 'Content Translation',
+ );
+ }
+
+ public function setUp() {
+ $this->moduleList = array(
+ 'content_translation' => 'core/modules/content_translation/content_translation.info.yml',
+ 'node' => 'core/modules/node/node.info.yml',
+ );
+ parent::setUp();
+
+ // Entity manager stub for derivative building.
+ $entity_manager = $this->getMockBuilder('Drupal\Core\Entity\EntityManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $entity_manager->expects($this->any())
+ ->method('getDefinitions')
+ ->will($this->returnValue(array(
+ 'node' => array(
+ 'translatable' => true,
+ 'translation' => array(
+ 'content_translation' => array(
+ // things.
+ ),
+ ),
+ 'menu_base_path' => 'node/%node',
+ ),
+ )));
+ \Drupal::getContainer()->set('entity.manager', $entity_manager);
+
+ // Route provider for injecting node.view into derivative lookup.
+ $collection = $this->getMockBuilder('Symfony\Component\Routing\RouteCollection')
+ ->disableOriginalConstructor()
+ ->setMethods(array('all'))
+ ->getMock();
+ $collection->expects($this->any())
+ ->method('all')
+ ->will($this->returnValue(array('node.view' => array())));
+ $route_provider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface');
+ $route_provider->expects($this->any())
+ ->method('getRoutesByPattern')
+ ->will($this->returnValue($collection));
+ \Drupal::getContainer()->set('router.route_provider', $route_provider);
+
+ // Stub for t().
+ $string_translation = $this->getMock('Drupal\Core\StringTranslation\TranslationInterface');
+ $string_translation->expects($this->any())
+ ->method('translate')
+ ->will($this->returnCallback(function($string) {return $string;}));
+ \Drupal::getContainer()->set('string_translation', $string_translation);
+
+ // Load the content_translation.module file in order to run the alter hook.
+ require_once DRUPAL_ROOT . '/core/modules/content_translation/content_translation.module';
+ }
+
+ /**
+ * Tests the block admin display local tasks.
+ *
+ * @dataProvider providerTestBlockAdminDisplay
+ */
+ public function testBlockAdminDisplay($route, $expected) {
+ $this->assertLocalTasks($route, $expected);
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function providerTestBlockAdminDisplay() {
+ return array(
+ array('node.view', array(array(
+ 'content_translation.local_tasks:content_translation.translation_overview_node',
+ 'node.view',
+ 'node.page_edit',
+ 'node.delete_confirm',
+ 'node.revision_overview',
+ ))),
+ array('content_translation.translation_overview_node', array(array(
+ 'content_translation.local_tasks:content_translation.translation_overview_node',
+ 'node.view',
+ 'node.page_edit',
+ 'node.delete_confirm',
+ 'node.revision_overview',
+ ))),
+ );
+ }
+
+}
diff --git a/core/modules/field_ui/field_ui.local_tasks.yml b/core/modules/field_ui/field_ui.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e690491757fb14d3493fcc3b0658675c13a50c10
--- /dev/null
+++ b/core/modules/field_ui/field_ui.local_tasks.yml
@@ -0,0 +1,4 @@
+field_ui.list:
+ title: Entities
+ route_name: field_ui.list
+ tab_root_id: field_ui.list
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 0d81232edf6029f92af5241fb849969851b35ee0..dc0d38f64c3886dbf602b9659f13317ab1be3a23 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -60,10 +60,6 @@ function field_ui_menu() {
'route_name' => 'field_ui.list',
'type' => MENU_NORMAL_ITEM,
);
- $items['admin/reports/fields/list'] = array(
- 'title' => 'Entities',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
// Create tabs for all possible bundles.
foreach (entity_get_info() as $entity_type => $entity_info) {
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/FieldUIRouteTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/FieldUIRouteTest.php
index 669b58e999920e9db7aacb5adb13aef316f2ecde..d3764a4ea7331e89068df8da95db1065f8f17b06 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/FieldUIRouteTest.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/FieldUIRouteTest.php
@@ -51,7 +51,7 @@ public function testFieldUIRoutes() {
//$this->assertText('No fields are present yet.');
$this->drupalGet('admin/structure/types/manage/article/fields');
- $this->assertTitle('Article | Drupal');
+ $this->assertTitle('Manage fields | Drupal');
}
}
diff --git a/core/modules/forum/forum.local_tasks.yml b/core/modules/forum/forum.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4cd9dcbde440e8f00e5533b30b215fce2480c81b
--- /dev/null
+++ b/core/modules/forum/forum.local_tasks.yml
@@ -0,0 +1,9 @@
+forum.overview:
+ route_name: forum.overview
+ tab_root_id: forum.overview
+ title: List
+forum.settings:
+ route_name: forum.settings
+ tab_root_id: forum.overview
+ title: Settings
+ weight: 100
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 392e4b409b4d214ae5c5b4afdc5fd6f850691a3e..1d30fcb4bcd59a10492a191d527fb6d0884f6343 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -119,17 +119,6 @@ function forum_menu() {
'description' => 'Control forum hierarchy settings.',
'route_name' => 'forum.overview',
);
- $items['admin/structure/forum/list'] = array(
- 'title' => 'List',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['admin/structure/forum/settings'] = array(
- 'title' => 'Settings',
- 'weight' => 100,
- 'type' => MENU_LOCAL_TASK,
- 'parent' => 'admin/structure/forum',
- 'route_name' => 'forum.settings',
- );
$items['admin/structure/forum/edit/container/%taxonomy_term'] = array(
'title' => 'Edit container',
'route_name' => 'forum.edit_container',
diff --git a/core/modules/language/language.local_tasks.yml b/core/modules/language/language.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..690d3f897061325956ff87bfa6ca7b6ecaabc39f
--- /dev/null
+++ b/core/modules/language/language.local_tasks.yml
@@ -0,0 +1,19 @@
+system.date_format_language_overview:
+ title: 'Localize'
+ route_name: system.date_format_language_overview
+ tab_root_id: system.date_format_list
+ weight: -8
+
+language.admin_overview:
+ title: 'List'
+ route_name: language.admin_overview
+ tab_root_id: language.admin_overview
+language.negotiation:
+ title: 'Detection and selection'
+ route_name: language.negotiation
+ tab_root_id: language.admin_overview
+
+language.edit:
+ title: 'Edit'
+ route_name: language.edit
+ tab_root_id: language.edit
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 75fd237e0ba5afd5e69382edb6c31681881ecf11..e5aa96ae1195c38b6915ac3bebc4ac2b209df933 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -73,51 +73,6 @@ function language_menu() {
'route_name' => 'language.admin_overview',
'weight' => -10,
);
- $items['admin/config/regional/language/list'] = array(
- 'title' => 'List',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['admin/config/regional/language/add'] = array(
- 'route_name' => 'language.add',
- 'type' => MENU_SIBLING_LOCAL_TASK,
- );
- $items['admin/config/regional/language/edit/%language'] = array(
- 'title' => 'Edit language',
- 'route_name' => 'language.edit',
- );
- $items['admin/config/regional/language/edit/%language/edit'] = array(
- 'title' => 'Edit',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- );
-
- // Language negotiation.
- $items['admin/config/regional/language/detection'] = array(
- 'title' => 'Detection and selection',
- 'route_name' => 'language.negotiation',
- 'weight' => 10,
- 'type' => MENU_LOCAL_TASK,
- );
- $items['admin/config/regional/language/detection/url'] = array(
- 'title' => 'URL language detection configuration',
- 'route_name' => 'language.negotiation_url',
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- );
- $items['admin/config/regional/language/detection/session'] = array(
- 'title' => 'Session language detection configuration',
- 'route_name' => 'language.negotiation_session',
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- );
- $items['admin/config/regional/language/detection/browser'] = array(
- 'title' => 'Browser language detection configuration',
- 'route_name' => 'language.negotiation_browser',
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- );
- $items['admin/config/regional/language/detection/selected'] = array(
- 'title' => 'Selected language detection configuration',
- 'route_name' => 'language.negotiation_selected',
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- );
// Content language settings.
$items['admin/config/regional/content-language'] = array(
diff --git a/core/modules/language/language.routing.yml b/core/modules/language/language.routing.yml
index ff7a4e77e50ba6e4d90a2f6e1cf5c93ca7f2343c..3b76d565abd3bdb1e9bfcd9a60e7afe28f26710e 100644
--- a/core/modules/language/language.routing.yml
+++ b/core/modules/language/language.routing.yml
@@ -30,6 +30,7 @@ language.edit:
path: '/admin/config/regional/language/edit/{language_entity}'
defaults:
_entity_form: 'language_entity.edit'
+ _title: 'Edit language'
requirements:
_entity_access: 'language_entity.update'
diff --git a/core/modules/language/tests/Drupal/language/Tests/Menu/LanguageLocalTasks.php b/core/modules/language/tests/Drupal/language/Tests/Menu/LanguageLocalTasks.php
new file mode 100644
index 0000000000000000000000000000000000000000..36ea4697d0174c5fcb5d0e03156050ce1b1fda03
--- /dev/null
+++ b/core/modules/language/tests/Drupal/language/Tests/Menu/LanguageLocalTasks.php
@@ -0,0 +1,73 @@
+ 'Language local tasks test',
+ 'description' => 'Test existence of language local tasks.',
+ 'group' => 'Language',
+ );
+ }
+
+ public function setUp() {
+ $this->moduleList = array(
+ 'language' => 'core/modules/language/language.info.yml',
+ );
+ parent::setUp();
+ }
+
+ /**
+ * Tests language admin overview local tasks existence.
+ *
+ * @dataProvider getLanguageAdminOverviewRoutes
+ */
+ public function testLanguageAdminLocalTasks($route, $expected) {
+ $this->assertLocalTasks($route, $expected);
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function getLanguageAdminOverviewRoutes() {
+ return array(
+ array('language.admin_overview', array(array('language.admin_overview', 'language.negotiation'))),
+ array('language.negotiation', array(array('language.admin_overview', 'language.negotiation'))),
+ );
+ }
+
+ /**
+ * Tests language edit local tasks existence.
+ */
+ public function testLanguageEditLocalTasks() {
+ $this->assertLocalTasks('language.edit', array(
+ 0 => array('language.edit'),
+ ));
+ }
+
+ /**
+ * Tests language date format local tasks.
+ */
+ public function testLanguageDateLocalTasks() {
+ $this->assertLocalTasks('system.date_format_language_overview', array(
+ 0 => array('system.date_format_language_overview'),
+ ));
+ }
+
+
+}
diff --git a/core/modules/locale/locale.local_tasks.yml b/core/modules/locale/locale.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ade24ed23a9da71ac312660ce9047ee2fa0a6362
--- /dev/null
+++ b/core/modules/locale/locale.local_tasks.yml
@@ -0,0 +1,22 @@
+locale.translate_page:
+ route_name: locale.translate_page
+ tab_root_id: locale.translate_page
+ title: Translate
+
+locale.translate_import:
+ route_name: locale.translate_import
+ tab_root_id: locale.translate_page
+ title: Import
+ weight: 20
+
+locale.translate_export:
+ route_name: locale.translate_export
+ tab_root_id: locale.translate_page
+ title: Export
+ weight: 30
+
+locale.settings:
+ route_name: locale.settings
+ tab_root_id: locale.translate_page
+ title: Settings
+ weight: 100
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 18602392936759acb20a7cc9ec9e8a6b28339105..30f134e5954771c874f300046a1742f2be5534e7 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -176,28 +176,7 @@ function locale_menu() {
'route_name' => 'locale.translate_page',
'weight' => -5,
);
- $items['admin/config/regional/translate/translate'] = array(
- 'title' => 'Translate',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['admin/config/regional/translate/import'] = array(
- 'title' => 'Import',
- 'route_name' => 'locale.translate_import',
- 'weight' => 20,
- 'type' => MENU_LOCAL_TASK,
- );
- $items['admin/config/regional/translate/export'] = array(
- 'title' => 'Export',
- 'route_name' => 'locale.translate_export',
- 'weight' => 30,
- 'type' => MENU_LOCAL_TASK,
- );
- $items['admin/config/regional/translate/settings'] = array(
- 'title' => 'Settings',
- 'route_name' => 'locale.settings',
- 'weight' => 100,
- 'type' => MENU_LOCAL_TASK,
- );
+
$items['admin/reports/translations'] = array(
'title' => 'Available translation updates',
'route_name' => 'locale.translate_status',
diff --git a/core/modules/locale/tests/Drupal/locale/Tests/Menu/LocaleLocalTasksTest.php b/core/modules/locale/tests/Drupal/locale/Tests/Menu/LocaleLocalTasksTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..4c188318fbf63cd92f0e72e72f963debe6e3d851
--- /dev/null
+++ b/core/modules/locale/tests/Drupal/locale/Tests/Menu/LocaleLocalTasksTest.php
@@ -0,0 +1,59 @@
+ 'Locale local tasks test',
+ 'description' => 'Test locale local tasks.',
+ 'group' => 'Locale',
+ );
+ }
+
+ public function setUp() {
+ $this->moduleList = array(
+ 'locale' => 'core/modules/locale/locale.info.yml',
+ );
+ parent::setUp();
+ }
+
+ /**
+ * Checks locale listing local tasks.
+ *
+ * @dataProvider getLocalePageRoutes
+ */
+ public function testLocalePageLocalTasks($route) {
+ $tasks = array(
+ 0 => array('locale.translate_page', 'locale.translate_import', 'locale.translate_export','locale.settings'),
+ );
+ $this->assertLocalTasks($route, $tasks);
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function getLocalePageRoutes() {
+ return array(
+ array('locale.translate_page'),
+ array('locale.translate_import'),
+ array('locale.translate_export'),
+ array('locale.settings'),
+ );
+ }
+
+}
diff --git a/core/modules/node/node.local_tasks.yml b/core/modules/node/node.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..24d9ef22c1349355dbcf4617d8bd9f9995ad2007
--- /dev/null
+++ b/core/modules/node/node.local_tasks.yml
@@ -0,0 +1,18 @@
+node.view:
+ route_name: node.view
+ tab_root_id: node.view
+ title: 'View'
+node.page_edit:
+ route_name: node.page_edit
+ tab_root_id: node.view
+ title: Edit
+node.delete_confirm:
+ route_name: node.delete_confirm
+ tab_root_id: node.view
+ title: Delete
+ weight: 10
+node.revision_overview:
+ route_name: node.revision_overview
+ tab_root_id: node.view
+ title: 'Revisions'
+ weight: 20
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 511a494363ce2ee23fd966f4ffa3ca8e2efbe480..4fe16458bf4950579d50e9bdc8153ef8f1522f9c 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -981,15 +981,11 @@ function node_menu() {
// overridden by a menu link.
'route_name' => 'node.view',
);
- $items['node/%node/view'] = array(
- 'title' => 'View',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
$items['node/%node/edit'] = array(
'title' => 'Edit',
'route_name' => 'node.page_edit',
'type' => MENU_LOCAL_TASK,
- 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+ 'context' => MENU_CONTEXT_INLINE,
);
$items['node/%node/delete'] = array(
'title' => 'Delete',
@@ -998,12 +994,6 @@ function node_menu() {
'type' => MENU_LOCAL_TASK,
'context' => MENU_CONTEXT_INLINE,
);
- $items['node/%node/revisions'] = array(
- 'title' => 'Revisions',
- 'route_name' => 'node.revision_overview',
- 'weight' => 20,
- 'type' => MENU_LOCAL_TASK,
- );
$items['node/%node/revisions/%node_revision/view'] = array(
'title' => 'Revisions',
'route_name' => 'node.revision_show',
diff --git a/core/modules/shortcut/shortcut.local_tasks.yml b/core/modules/shortcut/shortcut.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..edfeaeb1da68ae4305fd9bcf9b4dfd02cd60d007
--- /dev/null
+++ b/core/modules/shortcut/shortcut.local_tasks.yml
@@ -0,0 +1,4 @@
+shortcut.overview:
+ route_name: shortcut.overview
+ tab_root_id: user.view
+ title: 'Shortcuts'
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index 302d17bf6dfcc015c64a223ddbdc3cceb93d80aa..dc9bd86b3f5991a6246d7d92b97733eba7bd6ccf 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -119,11 +119,6 @@ function shortcut_menu() {
'title' => 'Delete shortcut',
'route_name' => 'shortcut.link_delete',
);
- $items['user/%user/shortcuts'] = array(
- 'title' => 'Shortcuts',
- 'route_name' => 'shortcut.overview',
- 'type' => MENU_LOCAL_TASK,
- );
return $items;
}
diff --git a/core/modules/shortcut/tests/Drupal/shortcut/Tests/Menu/ShortcutLocalTasksTest.php b/core/modules/shortcut/tests/Drupal/shortcut/Tests/Menu/ShortcutLocalTasksTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ff8bd7efdb726ec6692030b3f973c3e05d897515
--- /dev/null
+++ b/core/modules/shortcut/tests/Drupal/shortcut/Tests/Menu/ShortcutLocalTasksTest.php
@@ -0,0 +1,59 @@
+ 'Shortcut local tasks test',
+ 'description' => 'Test shortcut local tasks.',
+ 'group' => 'Shortcut',
+ );
+ }
+
+ public function setUp() {
+ $this->moduleList = array(
+ 'shortcut' => 'core/modules/shortcut/shortcut.info.yml',
+ 'user' => 'core/modules/user/user.info.yml',
+ );
+ parent::setUp();
+ }
+
+ /**
+ * Checks shortcut listing local tasks.
+ *
+ * @dataProvider getShortcutPageRoutes
+ */
+ public function testShortcutPageLocalTasks($route) {
+ $tasks = array(
+ 0 => array('shortcut.overview', 'user.view', 'user.edit',),
+ );
+ $this->assertLocalTasks($route, $tasks);
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function getShortcutPageRoutes() {
+ return array(
+ array('user.view'),
+ array('user.edit'),
+ array('shortcut.overview'),
+ );
+ }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Form/ThemeSettingsForm.php b/core/modules/system/lib/Drupal/system/Form/ThemeSettingsForm.php
index ff52b5cb9e4fa4781881a971c5b8672dabcf63e0..8c4659511d0b15991947712fe68b1a5c0ce083e7 100644
--- a/core/modules/system/lib/Drupal/system/Form/ThemeSettingsForm.php
+++ b/core/modules/system/lib/Drupal/system/Form/ThemeSettingsForm.php
@@ -65,25 +65,25 @@ public function getFormId() {
/**
* {@inheritdoc}
*
- * @param string $theme_name
+ * @param string $theme
* The theme name.
*/
- public function buildForm(array $form, array &$form_state, $theme_name = '') {
+ public function buildForm(array $form, array &$form_state, $theme = '') {
$form = parent::buildForm($form, $form_state);
$themes = list_themes();
// Deny access if the theme is disabled or not found.
- if (!empty($theme_name) && (empty($themes[$theme_name]) || !$themes[$theme_name]->status)) {
+ if (!empty($theme) && (empty($themes[$theme]) || !$themes[$theme]->status)) {
throw new NotFoundHttpException();
}
// Default settings are defined in theme_get_setting() in includes/theme.inc
- if ($theme_name) {
- $var = 'theme_' . $theme_name . '_settings';
- $config_key = $theme_name . '.settings';
+ if ($theme) {
+ $var = 'theme_' . $theme . '_settings';
+ $config_key = $theme . '.settings';
$themes = list_themes();
- $features = $themes[$theme_name]->info['features'];
+ $features = $themes[$theme]->info['features'];
}
else {
$var = 'theme_settings';
@@ -129,8 +129,8 @@ public function buildForm(array $form, array &$form_state, $theme_name = '') {
'#description' => t('Enable or disable the display of certain page elements.'),
);
foreach ($toggles as $name => $title) {
- if ((!$theme_name) || in_array($name, $features)) {
- $form['theme_settings']['toggle_' . $name] = array('#type' => 'checkbox', '#title' => $title, '#default_value' => theme_get_setting('features.' . $name, $theme_name));
+ if ((!$theme) || in_array($name, $features)) {
+ $form['theme_settings']['toggle_' . $name] = array('#type' => 'checkbox', '#title' => $title, '#default_value' => theme_get_setting('features.' . $name, $theme));
// Disable checkboxes for features not supported in the current configuration.
if (isset($disabled['toggle_' . $name])) {
$form['theme_settings']['toggle_' . $name]['#disabled'] = TRUE;
@@ -145,7 +145,7 @@ public function buildForm(array $form, array &$form_state, $theme_name = '') {
}
// Logo settings, only available when file.module is enabled.
- if ((!$theme_name) || in_array('logo', $features) && $this->moduleHandler->moduleExists('file')) {
+ if ((!$theme) || in_array('logo', $features) && $this->moduleHandler->moduleExists('file')) {
$form['logo'] = array(
'#type' => 'details',
'#title' => t('Logo image settings'),
@@ -160,7 +160,7 @@ public function buildForm(array $form, array &$form_state, $theme_name = '') {
$form['logo']['default_logo'] = array(
'#type' => 'checkbox',
'#title' => t('Use the default logo supplied by the theme'),
- '#default_value' => theme_get_setting('logo.use_default', $theme_name),
+ '#default_value' => theme_get_setting('logo.use_default', $theme),
'#tree' => FALSE,
);
$form['logo']['settings'] = array(
@@ -175,7 +175,7 @@ public function buildForm(array $form, array &$form_state, $theme_name = '') {
$form['logo']['settings']['logo_path'] = array(
'#type' => 'textfield',
'#title' => t('Path to custom logo'),
- '#default_value' => theme_get_setting('logo.path', $theme_name),
+ '#default_value' => theme_get_setting('logo.path', $theme),
);
$form['logo']['settings']['logo_upload'] = array(
'#type' => 'file',
@@ -185,7 +185,7 @@ public function buildForm(array $form, array &$form_state, $theme_name = '') {
);
}
- if ((!$theme_name) || in_array('favicon', $features) && $this->moduleHandler->moduleExists('file')) {
+ if ((!$theme) || in_array('favicon', $features) && $this->moduleHandler->moduleExists('file')) {
$form['favicon'] = array(
'#type' => 'details',
'#title' => t('Shortcut icon settings'),
@@ -201,7 +201,7 @@ public function buildForm(array $form, array &$form_state, $theme_name = '') {
$form['favicon']['default_favicon'] = array(
'#type' => 'checkbox',
'#title' => t('Use the default shortcut icon supplied by the theme'),
- '#default_value' => theme_get_setting('favicon.use_default', $theme_name),
+ '#default_value' => theme_get_setting('favicon.use_default', $theme),
);
$form['favicon']['settings'] = array(
'#type' => 'container',
@@ -215,7 +215,7 @@ public function buildForm(array $form, array &$form_state, $theme_name = '') {
$form['favicon']['settings']['favicon_path'] = array(
'#type' => 'textfield',
'#title' => t('Path to custom icon'),
- '#default_value' => theme_get_setting('favicon.path', $theme_name),
+ '#default_value' => theme_get_setting('favicon.path', $theme),
);
$form['favicon']['settings']['favicon_upload'] = array(
'#type' => 'file',
@@ -243,8 +243,8 @@ public function buildForm(array $form, array &$form_state, $theme_name = '') {
if ($original_path && isset($friendly_path)) {
$local_file = strtr($original_path, array('public:/' => PublicStream::basePath()));
}
- elseif ($theme_name) {
- $local_file = drupal_get_path('theme', $theme_name) . '/' . $default;
+ elseif ($theme) {
+ $local_file = drupal_get_path('theme', $theme) . '/' . $default;
}
else {
$local_file = path_to_theme() . '/' . $default;
@@ -258,32 +258,32 @@ public function buildForm(array $form, array &$form_state, $theme_name = '') {
}
}
- if ($theme_name) {
+ if ($theme) {
// Call engine-specific settings.
- $function = $themes[$theme_name]->prefix . '_engine_settings';
+ $function = $themes[$theme]->prefix . '_engine_settings';
if (function_exists($function)) {
$form['engine_specific'] = array(
'#type' => 'details',
'#title' => t('Theme-engine-specific settings'),
- '#description' => t('These settings only exist for the themes based on the %engine theme engine.', array('%engine' => $themes[$theme_name]->prefix)),
+ '#description' => t('These settings only exist for the themes based on the %engine theme engine.', array('%engine' => $themes[$theme]->prefix)),
);
$function($form, $form_state);
}
// Create a list which includes the current theme and all its base themes.
- if (isset($themes[$theme_name]->base_themes)) {
- $theme_keys = array_keys($themes[$theme_name]->base_themes);
- $theme_keys[] = $theme_name;
+ if (isset($themes[$theme]->base_themes)) {
+ $theme_keys = array_keys($themes[$theme]->base_themes);
+ $theme_keys[] = $theme;
}
else {
- $theme_keys = array($theme_name);
+ $theme_keys = array($theme);
}
// Save the name of the current theme (if any), so that we can temporarily
// override the current theme and allow theme_get_setting() to work
// without having to pass the theme name to it.
$default_theme = !empty($GLOBALS['theme_key']) ? $GLOBALS['theme_key'] : NULL;
- $GLOBALS['theme_key'] = $theme_name;
+ $GLOBALS['theme_key'] = $theme;
// Process the theme and all its base themes.
foreach ($theme_keys as $theme) {
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Derivative/ThemeLocalTask.php b/core/modules/system/lib/Drupal/system/Plugin/Derivative/ThemeLocalTask.php
new file mode 100644
index 0000000000000000000000000000000000000000..8a25fc33c84c60c307fca0a42bf2d5f80ec637a2
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Plugin/Derivative/ThemeLocalTask.php
@@ -0,0 +1,31 @@
+ $theme) {
+ if ($theme->status) {
+ $this->derivatives[$theme_name] = $base_plugin_definition;
+ $this->derivatives[$theme_name]['title'] = $theme->info['name'];
+ $this->derivatives[$theme_name]['route_parameters'] = array('theme' => $theme_name);
+ }
+ }
+ return $this->derivatives;
+ }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Routing/RouteSubscriber.php b/core/modules/system/lib/Drupal/system/Routing/RouteSubscriber.php
deleted file mode 100644
index de5304eda7e7426a6d867e356fc46ecc9d907967..0000000000000000000000000000000000000000
--- a/core/modules/system/lib/Drupal/system/Routing/RouteSubscriber.php
+++ /dev/null
@@ -1,34 +0,0 @@
-status)) {
- $route = new Route('admin/appearance/settings/' . $theme->name, array(
- '_form' => '\Drupal\system\Form\ThemeSettingsForm', 'theme_name' => $theme->name), array(
- '_permission' => 'administer themes',
- ));
- $collection->add('system.theme_settings_' . $theme->name, $route);
- }
- }
- }
-
-}
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index f1a428ff8dc0c1ade105fe7b5bbb69313d12bda4..6d7bc017a9443e62045e695778122c4e4a3e8420 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -213,7 +213,9 @@ function system_theme_default() {
// implementations, and doing the variable_set() before the theme_enable()
// could result in a race condition where the theme is default but not
// enabled.
+ \Drupal::service('router.builder')->rebuild();
menu_router_rebuild();
+ \Drupal::cache('cache')->deleteTags(array('local_task' => 1));
// The status message depends on whether an admin theme is currently in use:
// a value of 0 means the admin theme is set to be the default theme.
diff --git a/core/modules/system/system.local_tasks.yml b/core/modules/system/system.local_tasks.yml
index 575e515e3bebbe6280a27455837b0abaa1aa9253..3cf14ad2c3d4984f0f4a2b220565f685a02d3143 100644
--- a/core/modules/system/system.local_tasks.yml
+++ b/core/modules/system/system.local_tasks.yml
@@ -12,3 +12,52 @@ system.site_information_settings_tab:
route_name: system.site_information_settings
title: Settings
tab_root_id: system.site_information_settings_tab
+
+system.themes_page:
+ route_name: system.themes_page
+ title: 'List'
+ tab_root_id: system.themes_page
+system.theme_settings:
+ route_name: system.theme_settings
+ title: 'Settings'
+ tab_root_id: system.themes_page
+ weight: 100
+
+system.theme_settings_global:
+ route_name: system.theme_settings
+ title: 'Global settings'
+ tab_root_id: system.themes_page
+ tab_parent_id: system.theme_settings
+ weight: -100
+system.theme_settings_theme:
+ route_name: system.theme_settings_theme
+ title: 'Theme name'
+ tab_root_id: system.themes_page
+ tab_parent_id: system.theme_settings
+ derivative: Drupal\system\Plugin\Derivative\ThemeLocalTask
+
+system.modules_list:
+ route_name: system.modules_list
+ tab_root_id: system.modules_list
+ title: 'List'
+system.modules_uninstall:
+ route_name: system.modules_uninstall
+ tab_root_id: system.modules_list
+ title: 'Uninstall'
+ weight: 20
+
+system.admin:
+ route_name: system.admin
+ tab_root_id: system.admin
+ title: 'Tasks'
+ weight: -20
+system.admin_index:
+ route_name: system.admin_index
+ tab_root_id: system.admin
+ title: 'Index'
+ weight: -18
+
+system.date_format_list:
+ route_name: system.date_format_list
+ tab_root_id: system.date_format_list
+ title: 'List'
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index cdfddea4e5a599acb6f4cbeb6702e0c2e3051ddf..060839136fc12e961e161e18e1771b1efb9876ed 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -620,17 +620,6 @@ function system_menu() {
'weight' => 9,
'menu_name' => 'admin',
);
- $items['admin/tasks'] = array(
- 'title' => 'Tasks',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -20,
- );
- $items['admin/index'] = array(
- 'title' => 'Index',
- 'route_name' => 'system.admin_index',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => -18,
- );
// Menu items that are basically just menu blocks.
$items['admin/structure'] = array(
@@ -648,34 +637,6 @@ function system_menu() {
'position' => 'left',
'weight' => -6,
);
- $items['admin/appearance/list'] = array(
- 'title' => 'List',
- 'description' => 'Select and configure your theme',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'file' => 'system.admin.inc',
- );
- $items['admin/appearance/settings'] = array(
- 'title' => 'Settings',
- 'description' => 'Configure default and theme specific settings.',
- 'route_name' => 'system.theme_settings',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 100,
- );
- // Theme configuration local tasks.
- $items['admin/appearance/settings/global'] = array(
- 'title' => 'Global settings',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
-
- foreach (list_themes(TRUE) as $theme) {
- if (!empty($theme->status)) {
- $items['admin/appearance/settings/' . $theme->name] = array(
- 'title' => $theme->info['name'],
- 'route_name' => 'system.theme_settings_' . $theme->name,
- 'type' => MENU_LOCAL_TASK,
- );
- }
- }
// Modules.
$items['admin/modules'] = array(
@@ -684,26 +645,6 @@ function system_menu() {
'route_name' => 'system.modules_list',
'weight' => -2,
);
- $items['admin/modules/list'] = array(
- 'title' => 'List',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['admin/modules/list/confirm'] = array(
- 'title' => 'List',
- 'route_name' => 'system.modules_list_confirm',
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- );
- $items['admin/modules/uninstall'] = array(
- 'title' => 'Uninstall',
- 'route_name' => 'system.modules_uninstall',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 20,
- );
- $items['admin/modules/uninstall/confirm'] = array(
- 'title' => 'Uninstall',
- 'route_name' => 'system.modules_uninstall_confirm',
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- );
// Configuration.
$items['admin/config'] = array(
@@ -806,11 +747,6 @@ function system_menu() {
'description' => 'Allow users to edit a configured date format.',
'route_name' => 'system.date_format_edit',
);
- $items['admin/config/regional/date-time/formats/manage/%/edit'] = array(
- 'title' => 'Edit',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- );
// Search settings.
$items['admin/config/search'] = array(
@@ -890,7 +826,6 @@ function system_menu() {
$items['admin/config/regional/date-time/locale'] = array(
'title' => 'Localize',
'description' => 'Configure date formats for each locale',
- 'type' => MENU_LOCAL_TASK,
'weight' => -8,
'route_name' => 'system.date_format_language_overview',
);
diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml
index 4d1c90ac29f171b4ee56825d091fa1dd5a34bc6f..69374b182b742c3e7240fd031fe8d99c27fe45ea 100644
--- a/core/modules/system/system.routing.yml
+++ b/core/modules/system/system.routing.yml
@@ -324,6 +324,13 @@ system.theme_settings:
requirements:
_permission: 'administer themes'
+system.theme_settings_theme:
+ path: '/admin/appearance/settings/{theme}'
+ defaults:
+ _form: '\Drupal\system\Form\ThemeSettingsForm'
+ requirements:
+ _permission: 'administer themes'
+
'':
path: '/'
requirements:
diff --git a/core/modules/system/system.services.yml b/core/modules/system/system.services.yml
index 6a68e294a5d0dbf7f34f0167fb4e2edc6df833ea..3371dad2c684f60932e6919f4474afd2689e77ca 100644
--- a/core/modules/system/system.services.yml
+++ b/core/modules/system/system.services.yml
@@ -19,7 +19,3 @@ services:
class: Drupal\system\PathProcessor\PathProcessorFiles
tags:
- { name: path_processor_inbound, priority: 200 }
- system.route_subscriber:
- class: Drupal\system\Routing\RouteSubscriber
- tags:
- - { name: event_subscriber }
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.local_tasks.yml b/core/modules/system/tests/modules/entity_test/entity_test.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a411359c5474f4b5f38edc9b839f5bc490d883c9
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/entity_test.local_tasks.yml
@@ -0,0 +1,2 @@
+entity_test.local_tasks:
+ derivative: 'Drupal\entity_test\Plugin\Derivative\EntityTestLocalTasks'
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index 75f2851486998e4caf7606dc5ff4016ba7e3af2e..15a826915c996c9dc493bdc2f7ca22a8f91e308e 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -259,11 +259,6 @@ function entity_test_menu() {
'title arguments' => array('@type' => $entity_type),
'route_name' => "entity_test.edit_$entity_type",
);
-
- $items[$entity_type . '/manage/%' . $entity_type . '/edit'] = array(
- 'title' => 'Edit',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
}
return $items;
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Controller/EntityTestController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Controller/EntityTestController.php
index 053163bfaa59337f839a34ff12983d6a80f3611d..ad22414e3586b210c0fe312f187e445ee3612d21 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Controller/EntityTestController.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Controller/EntityTestController.php
@@ -8,6 +8,7 @@
namespace Drupal\entity_test\Controller;
use Drupal\Core\Entity\EntityInterface;
+use Symfony\Component\HttpFoundation\Request;
/**
* Controller routines for entity_test routes.
@@ -24,7 +25,8 @@ public function testAdd($entity_type) {
/**
* @todo Remove entity_test_edit()
*/
- public function testEdit(EntityInterface $entity) {
+ public function testEdit(Request $request) {
+ $entity = $request->attributes->get($request->attributes->get('_entity_type'));
return entity_test_edit($entity);
}
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Derivative/EntityTestLocalTasks.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Derivative/EntityTestLocalTasks.php
new file mode 100644
index 0000000000000000000000000000000000000000..2f0950d77700684a1d8d56b8e5c856a220c1dbb6
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Derivative/EntityTestLocalTasks.php
@@ -0,0 +1,35 @@
+derivatives = array();
+ $types = entity_test_entity_types();
+ $types[] = 'entity_test_render';
+
+ foreach($types as $entity_type) {
+ $this->derivatives[$entity_type] = array();
+ $this->derivatives[$entity_type]['tab_root_id'] = "entity_test.local_tasks:$entity_type";
+ $this->derivatives[$entity_type]['route_name'] = "entity_test.edit_$entity_type";
+ $this->derivatives[$entity_type]['title'] = 'Edit';
+ }
+
+ return parent::getDerivativeDefinitions($base_plugin_definition);
+ }
+
+}
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Routing/RouteSubscriber.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Routing/RouteSubscriber.php
index ae09b5536497f9820bce9a4b581590a6b05b9dd0..c7102e732a6cb906458b804cbaa13af4a8ed7321 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Routing/RouteSubscriber.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Routing/RouteSubscriber.php
@@ -32,8 +32,8 @@ protected function routes(RouteCollection $collection) {
$collection->add("entity_test.add_$entity_type", $route);
$route = new Route(
- "$entity_type/manage/{entity}",
- array('_content' => '\Drupal\entity_test\Controller\EntityTestController::testEdit'),
+ "$entity_type/manage/{" . $entity_type . '}',
+ array('_content' => '\Drupal\entity_test\Controller\EntityTestController::testEdit', '_entity_type' => $entity_type),
array('_permission' => 'administer entity_test content'),
array('parameters' => array(
'entity' => array('type' => 'entity:' . $entity_type),
diff --git a/core/modules/taxonomy/taxonomy.local_tasks.yml b/core/modules/taxonomy/taxonomy.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a04379e3a1e8da3afbf0ecd58de9496406397ae6
--- /dev/null
+++ b/core/modules/taxonomy/taxonomy.local_tasks.yml
@@ -0,0 +1,9 @@
+taxonomy.term_page:
+ title: 'View'
+ route_name: taxonomy.term_page
+ tab_root_id: taxonomy.term_page
+
+taxonomy.term_edit:
+ title: 'Edit'
+ route_name: taxonomy.term_edit
+ tab_root_id: taxonomy.term_page
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index e8dd6869532ecf2f37ef97e556e50ce0280371aa..9c896104bd7bfc2790a40d11d85a8401846a55a8 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -255,15 +255,11 @@ function taxonomy_menu() {
'title arguments' => array(2),
'route_name' => 'taxonomy.term_page',
);
- $items['taxonomy/term/%taxonomy_term/view'] = array(
- 'title' => 'View',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
$items['taxonomy/term/%taxonomy_term/edit'] = array(
'title' => 'Edit',
'route_name' => 'taxonomy.term_edit',
'type' => MENU_LOCAL_TASK,
- 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+ 'context' => MENU_CONTEXT_INLINE,
'weight' => 10,
);
$items['taxonomy/term/%taxonomy_term/delete'] = array(
diff --git a/core/modules/taxonomy/tests/Drupal/taxonomy/Tests/Menu/TaxonomyLocalTasksTest.php b/core/modules/taxonomy/tests/Drupal/taxonomy/Tests/Menu/TaxonomyLocalTasksTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6151cb26abbe5f561144624f686a01bd99ed8b5f
--- /dev/null
+++ b/core/modules/taxonomy/tests/Drupal/taxonomy/Tests/Menu/TaxonomyLocalTasksTest.php
@@ -0,0 +1,56 @@
+ 'Taxonomy local tasks test',
+ 'description' => 'Test existence of taxonomy local tasks.',
+ 'group' => 'Taxonomy',
+ );
+ }
+
+ public function setUp() {
+ $this->moduleList = array('taxonomy' => 'core/modules/taxonomy/taxonomy.info.yml');
+ parent::setUp();
+ }
+
+ /**
+ * Checks taxonomy edit local tasks.
+ *
+ * @dataProvider getTaxonomyPageRoutes
+ */
+ public function testTaxonomyPageLocalTasks($route, $subtask = array()) {
+ $tasks = array(
+ 0 => array('taxonomy.term_page', 'taxonomy.term_edit'),
+ );
+ if ($subtask) $tasks[] = $subtask;
+ $this->assertLocalTasks($route, $tasks);
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function getTaxonomyPageRoutes() {
+ return array(
+ array('taxonomy.term_page'),
+ array('taxonomy.term_edit'),
+ );
+ }
+
+}
diff --git a/core/modules/update/update.local_tasks.yml b/core/modules/update/update.local_tasks.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1281a2750ded91d3423c3ed379d4eb1da709c3b2
--- /dev/null
+++ b/core/modules/update/update.local_tasks.yml
@@ -0,0 +1,27 @@
+update.status:
+ route_name: update.status
+ tab_root_id: system.admin_reports
+ title: List
+update.settings:
+ route_name: update.settings
+ tab_root_id: system.admin_reports
+ tab_parent_id: update.status
+ title: Settings
+ weight: 50
+update.report_install:
+ route_name: update.report_install
+ tab_root_id: system.admin_reports
+ title: Update
+ weight: 10
+
+update.module_install:
+ route_name: update.module_install
+ tab_root_id: system.modules_list
+ title: Update
+ weight: 10
+
+update.theme_install:
+ route_name: update.theme_install
+ tab_root_id: system.themes_page
+ title: Update
+ weight: 10
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index 3c04664708c8739b042a3d05d35d28d71e483008..e6dbf70063e010d0e3b308331b88c62eb7654845 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -156,18 +156,6 @@ function update_menu() {
'route_name' => 'update.status',
'weight' => -50,
);
- $items['admin/reports/updates/list'] = array(
- 'title' => 'List',
- 'access arguments' => array('administer site configuration'),
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['admin/reports/updates/settings'] = array(
- 'title' => 'Settings',
- 'route_name' => 'update.settings',
- 'access arguments' => array('administer site configuration'),
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 50,
- );
// We want action links for updating projects at a few different locations:
// both the module and theme administration pages, and on the available
@@ -186,12 +174,6 @@ function update_menu() {
'weight' => 25,
'type' => MENU_LOCAL_ACTION,
);
- $items[$path . '/update'] = array(
- 'route_name' => "update.{$context}_update",
- 'weight' => 10,
- 'title' => 'Update',
- 'type' => MENU_LOCAL_TASK,
- );
}
// Customize the titles of the action links depending on where they appear.
// We use += array() to let the translation extractor find these menu titles.
diff --git a/core/modules/user/tests/Drupal/user/Tests/Menu/UserLocalTasksTest.php b/core/modules/user/tests/Drupal/user/Tests/Menu/UserLocalTasksTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a978178f2d3e81c71a96a8b8ce009a79d3f4f2c8
--- /dev/null
+++ b/core/modules/user/tests/Drupal/user/Tests/Menu/UserLocalTasksTest.php
@@ -0,0 +1,102 @@
+ 'User local tasks test',
+ 'description' => 'Test user local tasks.',
+ 'group' => 'User',
+ );
+ }
+
+ public function setUp() {
+ $this->moduleList = array('user' => 'core/modules/user/user.info.yml');
+ parent::setUp();
+ }
+
+ /**
+ * Tests local task existence.
+ *
+ * @dataProvider getUserAdminRoutes
+ */
+ public function testUserAdminLocalTasks($route, $expected) {
+ $this->assertLocalTasks($route, $expected);
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function getUserAdminRoutes() {
+ return array(
+ array('user.role_list', array(array('user.role_list_tab'))),
+ array('user.account_settings', array(array('user.account_settings_tab'))),
+ );
+ }
+
+ /**
+ * Checks user listing local tasks.
+ *
+ * @dataProvider getUserLoginRoutes
+ */
+ public function testUserLoginLocalTasks($route, $subtask = array()) {
+ $tasks = array(
+ 0 => array('user.page', 'user.register', 'user.pass',),
+ );
+ if ($subtask) {
+ $tasks[] = $subtask;
+ }
+ $this->assertLocalTasks($route, $tasks);
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function getUserLoginRoutes() {
+ return array(
+ array('user.page', array('user.login',)),
+ array('user.login', array('user.login',)),
+ array('user.register'),
+ array('user.pass'),
+ );
+ }
+
+ /**
+ * Checks user listing local tasks.
+ *
+ * @dataProvider getUserPageRoutes
+ */
+ public function testUserPageLocalTasks($route, $subtask = array()) {
+ $tasks = array(
+ 0 => array('user.view', 'user.edit',),
+ );
+ if ($subtask) $tasks[] = $subtask;
+ $this->assertLocalTasks($route, $tasks);
+ }
+
+ /**
+ * Provides a list of routes to test.
+ */
+ public function getUserPageRoutes() {
+ return array(
+ array('user.view'),
+ array('user.edit'),
+ );
+ }
+
+}
diff --git a/core/modules/user/user.local_tasks.yml b/core/modules/user/user.local_tasks.yml
index 0b40260dd945f16b61590db6b996fab5e38515d5..c69ac8e217ddc025b9832c642757b38f7cff58b3 100644
--- a/core/modules/user/user.local_tasks.yml
+++ b/core/modules/user/user.local_tasks.yml
@@ -2,7 +2,37 @@ user.role_list_tab:
route_name: user.role_list
title: 'Roles'
tab_root_id: user.role_list_tab
+
user.account_settings_tab:
route_name: user.account_settings
title: 'Settings'
tab_root_id: user.account_settings_tab
+
+user.page:
+ route_name: user.page
+ tab_root_id: user.page
+ title: 'Log in'
+ weight: -10
+user.register:
+ route_name: user.register
+ tab_root_id: user.page
+ title: 'Create new account'
+user.pass:
+ route_name: user.pass
+ tab_root_id: user.page
+ title: 'Request new password'
+# Other authentication methods may add pages below user/login/.
+user.login:
+ route_name: user.login
+ tab_root_id: user.page
+ tab_parent_id: user.page
+ title: 'Username and password'
+
+user.view:
+ route_name: user.view
+ tab_root_id: user.view
+ title: View
+user.edit:
+ route_name: user.edit
+ tab_root_id: user.view
+ title: Edit
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 0c7ac05e3932e37bbce5c5f396a7854c72c48f42..e25a4ac059ede756a606500e7bd11bf8a1218a94 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -738,27 +738,6 @@ function user_menu() {
'menu_name' => 'account',
);
- $items['user/login'] = array(
- 'title' => 'Log in',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- // Other authentication methods may add pages below user/login/.
- $items['user/login/default'] = array(
- 'title' => 'Username and password',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
-
- $items['user/register'] = array(
- 'title' => 'Create new account',
- 'type' => MENU_LOCAL_TASK,
- 'route_name' => 'user.register',
- );
-
- $items['user/password'] = array(
- 'title' => 'Request new password',
- 'route_name' => 'user.pass',
- 'type' => MENU_LOCAL_TASK,
- );
// Since menu_get_ancestors() does not support multiple placeholders in a row,
// this MENU_CALLBACK cannot be removed yet.
$items['user/reset/%/%/%'] = array(
@@ -836,10 +815,6 @@ function user_menu() {
'title arguments' => array(1),
'route_name' => 'user.view',
);
- $items['user/%user/view'] = array(
- 'title' => 'View',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
$items['user/%user/cancel'] = array(
'route_name' => 'user.cancel',
);
@@ -847,11 +822,6 @@ function user_menu() {
'title' => 'Confirm account cancellation',
'route_name' => 'user.cancel_confirm',
);
- $items['user/%user/edit'] = array(
- 'title' => 'Edit',
- 'route_name' => 'user.edit',
- 'type' => MENU_LOCAL_TASK,
- );
return $items;
}
diff --git a/core/modules/user/user.routing.yml b/core/modules/user/user.routing.yml
index 169343bb4b6e2f0a705737c3fa5b29885c610a16..eeb8d3d671558822dee36f9b3f5d169ff8a062d1 100644
--- a/core/modules/user/user.routing.yml
+++ b/core/modules/user/user.routing.yml
@@ -2,6 +2,7 @@ user.register:
path: '/user/register'
defaults:
_entity_form: 'user.register'
+ _title: 'Create new account'
requirements:
_access_user_register: 'TRUE'
@@ -108,6 +109,7 @@ user.pass:
path: '/user/password'
defaults:
_form: '\Drupal\user\Form\UserPasswordForm'
+ _title: 'Request new password'
requirements:
_access: 'TRUE'
@@ -124,13 +126,13 @@ user.view:
_entity_view: 'user.full'
_title_callback: 'Drupal\user\Controller\UserController::userTitle'
requirements:
- user: \d+
_entity_access: 'user.view'
user.login:
path: '/user/login'
defaults:
_form: '\Drupal\user\Form\UserLoginForm'
+ _title: 'Log in'
requirements:
_access: 'TRUE'
diff --git a/core/modules/views_ui/views_ui.local_tasks.yml b/core/modules/views_ui/views_ui.local_tasks.yml
index 68fc7dc81d41307e1da46e422b0db129601852ba..79747342eee13c1aea5e471d6cd2ff108122631f 100644
--- a/core/modules/views_ui/views_ui.local_tasks.yml
+++ b/core/modules/views_ui/views_ui.local_tasks.yml
@@ -20,3 +20,8 @@ views_ui.list_tab:
route_name: views_ui.list
title: List
tab_root_id: views_ui.list_tab
+
+views_ui.reports_fields:
+ route_name: views_ui.reports_fields
+ title: 'Used in views'
+ tab_root_id: field_ui.list
diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module
index 0f76cbd162f486f4e4cbb815644bb80210e7ba08..93742a43e039915ed90181fac9df329c2401e490 100644
--- a/core/modules/views_ui/views_ui.module
+++ b/core/modules/views_ui/views_ui.module
@@ -25,20 +25,6 @@ function views_ui_menu() {
'route_name' => 'views_ui.list',
);
- // @todo - remove all items of type MENU_VISIBLE_IN_BREADCRUMB
- // when there is a route-aware breadcrumb builder.
- $items['admin/structure/views/settings'] = array(
- 'title' => 'Settings',
- 'route_name' => 'views_ui.settings_basic',
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- );
-
- $items['admin/structure/views/settings/advanced'] = array(
- 'title' => 'Advanced',
- 'route_name' => 'views_ui.settings_advanced',
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- );
-
// The primary Edit View page. Secondary tabs for each Display are added in
// views_ui_menu_local_tasks_alter().
$items['admin/structure/views/view/%'] = array(
@@ -47,33 +33,7 @@ function views_ui_menu() {
$items['admin/structure/views/view/%/edit'] = array(
'title' => 'Edit view',
'type' => MENU_DEFAULT_LOCAL_TASK,
- 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
- );
- $items['admin/structure/views/view/%/preview/%'] = array(
- 'route_name' => 'views_ui.preview',
- 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- );
-
- // Additional pages for acting on a View.
-
- $items['admin/structure/views/view/%/break-lock'] = array(
- 'title' => 'Break lock',
- 'route_name' => 'views_ui.break_lock',
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- );
-
- // NoJS/AJAX callbacks that can use the default Views AJAX form system.
- $items['admin/structure/views/nojs/%/%'] = array(
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- );
-
- // A page in the Reports section to show usage of fields in all views
- $items['admin/reports/fields/views-fields'] = array(
- 'title' => 'Used in views',
- 'description' => 'Overview of fields used in all views.',
- 'route_name' => 'views_ui.reports_fields',
- 'type' => MENU_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_INLINE,
);
// A page in the Reports section to show usage of plugins in all views.
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalTaskIntegrationTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskIntegrationTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..61ee6013d8d503305dd0295daba3b4302aa8ead3
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskIntegrationTest.php
@@ -0,0 +1,139 @@
+getConfigFactoryStub(array());
+ $container->set('config.factory', $config_factory);
+ \Drupal::setContainer($container);
+ }
+
+ protected function tearDown() {
+ // Passes in an empty container.
+ $container = new ContainerBuilder();
+ \Drupal::setContainer($container);
+ }
+
+ /**
+ * Sets up the local task manager for the test.
+ */
+ protected function getLocalTaskManager($modules, $route_name, $route_params) {
+ $manager = $this
+ ->getMockBuilder('Drupal\Core\Menu\LocalTaskManager')
+ ->disableOriginalConstructor()
+ ->setMethods(NULL)
+ ->getMock();
+
+ $controllerResolver = $this->getMock('Symfony\Component\HttpKernel\Controller\ControllerResolverInterface');
+ $property = new \ReflectionProperty('Drupal\Core\Menu\LocalTaskManager', 'controllerResolver');
+ $property->setAccessible(TRUE);
+ $property->setValue($manager, $controllerResolver);
+
+ // todo mock a request with a route.
+ $request = $this->getMock('Symfony\Component\HttpFoundation\Request');
+ $property = new \ReflectionProperty('Drupal\Core\Menu\LocalTaskManager', 'request');
+ $property->setAccessible(TRUE);
+ $property->setValue($manager, $request);
+
+ $accessManager = $this->getMockBuilder('Drupal\Core\Access\AccessManager')
+ ->disableOriginalConstructor()
+ ->getMock(); $property = new \ReflectionProperty('Drupal\Core\Menu\LocalTaskManager', 'accessManager');
+ $property->setAccessible(TRUE);
+ $property->setValue($manager, $accessManager);
+
+ $module_handler = new ModuleHandler($modules);
+ $pluginDiscovery = new YamlDiscovery('local_tasks', $module_handler->getModuleDirectories());
+ $pluginDiscovery = new ContainerDerivativeDiscoveryDecorator($pluginDiscovery);
+ $property = new \ReflectionProperty('Drupal\Core\Menu\LocalTaskManager', 'discovery');
+ $property->setAccessible(TRUE);
+ $property->setValue($manager, $pluginDiscovery);
+
+ $method = new \ReflectionMethod('Drupal\Core\Menu\LocalTaskManager', 'alterInfo');
+ $method->setAccessible(TRUE);
+ $method->invoke($manager, $module_handler, 'local_tasks');
+
+ $plugin_stub = $this->getMock('Drupal\Core\Menu\LocalTaskInterface');
+ $factory = $this->getMock('Drupal\Component\Plugin\Factory\FactoryInterface');
+ $factory->expects($this->any())
+ ->method('createInstance')
+ ->will($this->returnValue($plugin_stub));
+ $property = new \ReflectionProperty('Drupal\Core\Menu\LocalTaskManager', 'factory');
+ $property->setAccessible(TRUE);
+ $property->setValue($manager, $factory);
+
+ $language_manager = $this->getMockBuilder('Drupal\Core\Language\LanguageManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $language_manager->expects($this->any())
+ ->method('getLanguage')
+ ->will($this->returnValue(new Language(array('id' => 'en'))));
+
+ $cache_backend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
+ $manager->setCacheBackend($cache_backend, $language_manager, 'local_task', array('local_task' => 1));
+
+ return $manager;
+ }
+
+ /**
+ * Tests integration for local tasks.
+ *
+ * @param $route_name
+ * Route name to base task building on.
+ * @param $expected_tasks
+ * A list of tasks groups by level expected at the given route
+ * @param array $route_params
+ * (optional) a list of route parameters used to resolve tasks.
+ */
+ protected function assertLocalTasks($route_name, $expected_tasks, $route_params = array()) {
+
+ $manager = $this->getLocalTaskManager($this->moduleList, $route_name, $route_params);
+
+ $tmp_tasks = $manager->getLocalTasksForRoute($route_name);
+
+ // At this point we're just testing existence so pull out keys and then
+ // compare.
+ //
+ // Deeper testing would require a functioning factory which because we are
+ // using the DefaultPluginManager base means we get into dependency soup
+ // because its factories create method and pulling services off the \Drupal
+ // container.
+ $tasks = array();
+ foreach ($tmp_tasks as $level => $level_tasks) {
+ $tasks[$level] = array_keys($level_tasks);
+ }
+ $this->assertEquals($expected_tasks, $tasks);
+ }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
index f10bb382536375bf1c0951cadba2c0ec8fc1f7de..049e3eebd667746e7ae5f030b6993a51babae0dc 100644
--- a/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
@@ -166,7 +166,7 @@ public function testGetLocalTaskForRouteWithEmptyCache() {
$this->cacheBackend->expects($this->at(3))
->method('set')
- ->with('local_task:en:menu_local_task_test_tasks_view', $expected_set, CacheBackendInterface::CACHE_PERMANENT, array('local_task'));
+ ->with('local_task:en:menu_local_task_test_tasks_view', $expected_set, CacheBackendInterface::CACHE_PERMANENT, array('local_task' => 1));
$local_tasks = $this->manager->getLocalTasksForRoute('menu_local_task_test_tasks_view');
$this->assertEquals($result, $local_tasks);
@@ -254,7 +254,7 @@ protected function setupLocalTaskManager() {
->method('getLanguage')
->will($this->returnValue(new Language(array('id' => 'en'))));
- $this->manager->setCacheBackend($this->cacheBackend, $language_manager, 'local_task');
+ $this->manager->setCacheBackend($this->cacheBackend, $language_manager, 'local_task', array('local_task' => 1));
}
/**