diff --git a/core/includes/menu.inc b/core/includes/menu.inc index d578499..23aba4f 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -130,8 +130,8 @@ function menu_local_tasks($level = 0) { if (!\Drupal::request()->attributes->has('exception') && !empty($route_name)) { $manager = \Drupal::service('plugin.manager.menu.local_task'); $local_tasks = $manager->getTasksBuild($route_name); - foreach ($local_tasks as $level => $items) { - $data['tabs'][$level] = empty($data['tabs'][$level]) ? $items : array_merge($data['tabs'][$level], $items); + foreach ($local_tasks as $tab_level => $items) { + $data['tabs'][$tab_level] = empty($data['tabs'][$tab_level]) ? $items : array_merge($data['tabs'][$tab_level], $items); } } @@ -177,16 +177,6 @@ function menu_secondary_local_tasks() { } /** - * Returns the rendered local actions at the current level. - */ -function menu_get_local_actions() { - $links = menu_local_tasks(); - $route_name = Drupal::routeMatch()->getRouteName(); - $manager = \Drupal::service('plugin.manager.menu.local_action'); - return $manager->getActionsForRoute($route_name) + $links['actions']; -} - -/** * Returns the router path, or the path for a default local task's parent. */ function menu_tab_root_path() { diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 7400017..ca03450 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1362,14 +1362,6 @@ function template_preprocess_page(&$variables) { $variables['is_front'] = FALSE; $variables['db_is_active'] = FALSE; } - if (!defined('MAINTENANCE_MODE')) { - $variables['action_links'] = menu_get_local_actions(); - $variables['tabs'] = menu_local_tabs(); - } - else { - $variables['action_links'] = array(); - $variables['tabs'] = array(); - } if ($node = \Drupal::routeMatch()->getParameter('node')) { $variables['node'] = $node; diff --git a/core/lib/Drupal/Core/Extension/ThemeHandler.php b/core/lib/Drupal/Core/Extension/ThemeHandler.php index f53bb0c..d234a7e 100644 --- a/core/lib/Drupal/Core/Extension/ThemeHandler.php +++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php @@ -269,6 +269,8 @@ public function rebuildThemeData() { 'page_top' => 'Page top', 'page_bottom' => 'Page bottom', 'breadcrumb' => 'Breadcrumb', + 'tabs' => 'Page tabs', + 'actions' => 'Page actions', ), 'description' => '', 'features' => $this->defaultFeatures, diff --git a/core/lib/Drupal/Core/Menu/LocalActionManager.php b/core/lib/Drupal/Core/Menu/LocalActionManager.php index db6acef..bdee9f3 100644 --- a/core/lib/Drupal/Core/Menu/LocalActionManager.php +++ b/core/lib/Drupal/Core/Menu/LocalActionManager.php @@ -190,10 +190,11 @@ public function getActionsForRoute($route_appears) { 'url' => Url::fromRoute($route_name, $route_parameters), 'localized_options' => $plugin->getOptions($this->routeMatch), ), - '#access' => $this->accessManager->checkNamedRoute($route_name, $route_parameters, $this->account), + '#access' => $this->accessManager->checkNamedRoute($route_name, $route_parameters, $this->account, TRUE), '#weight' => $plugin->getWeight(), ); } + return $links; } diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php index 70b1102..a24f2c1 100644 --- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php +++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php @@ -302,8 +302,8 @@ public function getTasksBuild($current_route_name) { $route_parameters = $child->getRouteParameters($this->routeMatch); // Find out whether the user has access to the task. - $access = $this->accessManager->checkNamedRoute($route_name, $route_parameters, $this->account); - if ($access) { + $access = $this->accessManager->checkNamedRoute($route_name, $route_parameters, $this->account, TRUE); + if ($access->isAllowed()) { $active = $this->isRouteActive($current_route_name, $route_name, $route_parameters); // The plugin may have been set active in getLocalTasksForRoute() if @@ -326,6 +326,7 @@ public function getTasksBuild($current_route_name) { } } } + return $build; } diff --git a/core/modules/aggregator/src/Tests/AggregatorTestBase.php b/core/modules/aggregator/src/Tests/AggregatorTestBase.php index 3c5a452..2ef399f 100644 --- a/core/modules/aggregator/src/Tests/AggregatorTestBase.php +++ b/core/modules/aggregator/src/Tests/AggregatorTestBase.php @@ -28,7 +28,7 @@ * * @var array */ - public static $modules = array('node', 'aggregator', 'aggregator_test', 'views'); + public static $modules = ['block', 'node', 'aggregator', 'aggregator_test', 'views']; /** * {@inheritdoc} @@ -43,6 +43,7 @@ protected function setUp() { $this->adminUser = $this->drupalCreateUser(array('access administration pages', 'administer news feeds', 'access news feeds', 'create article content')); $this->drupalLogin($this->adminUser); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/block/src/Tests/BlockHiddenRegionTest.php b/core/modules/block/src/Tests/BlockHiddenRegionTest.php index b5abe7c..e8b53b5 100644 --- a/core/modules/block/src/Tests/BlockHiddenRegionTest.php +++ b/core/modules/block/src/Tests/BlockHiddenRegionTest.php @@ -42,6 +42,7 @@ protected function setUp() { $this->drupalLogin($this->adminUser); $this->drupalPlaceBlock('search_form_block'); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/block/src/Tests/NonDefaultBlockAdminTest.php b/core/modules/block/src/Tests/NonDefaultBlockAdminTest.php index 563d12d..07418e0 100644 --- a/core/modules/block/src/Tests/NonDefaultBlockAdminTest.php +++ b/core/modules/block/src/Tests/NonDefaultBlockAdminTest.php @@ -24,6 +24,15 @@ class NonDefaultBlockAdminTest extends WebTestBase { public static $modules = array('block'); /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('system_page_tabs_block'); + } + + /** * Test non-default theme admin. */ function testNonDefaultBlockAdmin() { diff --git a/core/modules/block_content/src/Tests/BlockContentTestBase.php b/core/modules/block_content/src/Tests/BlockContentTestBase.php index 82139c0..900c90a 100644 --- a/core/modules/block_content/src/Tests/BlockContentTestBase.php +++ b/core/modules/block_content/src/Tests/BlockContentTestBase.php @@ -60,6 +60,7 @@ protected function setUp() { } $this->adminUser = $this->drupalCreateUser($this->permissions); + $this->drupalPlaceBlock('system_page_actions_block'); } /** diff --git a/core/modules/comment/src/Tests/CommentTestBase.php b/core/modules/comment/src/Tests/CommentTestBase.php index 8ebc4e7..f181808 100644 --- a/core/modules/comment/src/Tests/CommentTestBase.php +++ b/core/modules/comment/src/Tests/CommentTestBase.php @@ -27,7 +27,7 @@ * * @var array */ - public static $modules = array('comment', 'node', 'history', 'field_ui', 'datetime'); + public static $modules = ['block', 'comment', 'node', 'history', 'field_ui', 'datetime']; /** * An administrative user with permission to configure comment settings. @@ -86,6 +86,7 @@ protected function setUp() { // Create a test node authored by the web user. $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'uid' => $this->webUser->id())); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/config/src/Tests/ConfigEntityListTest.php b/core/modules/config/src/Tests/ConfigEntityListTest.php index 73571ce..406cd1e 100644 --- a/core/modules/config/src/Tests/ConfigEntityListTest.php +++ b/core/modules/config/src/Tests/ConfigEntityListTest.php @@ -23,7 +23,7 @@ class ConfigEntityListTest extends WebTestBase { * * @var array */ - public static $modules = array('config_test'); + public static $modules = ['block', 'config_test']; /** * {@inheritdoc} @@ -33,6 +33,7 @@ protected function setUp() { // Delete the override config_test entity since it is not required by this // test. \Drupal::entityManager()->getStorage('config_test')->load('override')->delete(); + $this->drupalPlaceBlock('system_page_actions_block'); } /** diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationListUiTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationListUiTest.php index 4ceec20..366e3bb 100644 --- a/core/modules/config_translation/src/Tests/ConfigTranslationListUiTest.php +++ b/core/modules/config_translation/src/Tests/ConfigTranslationListUiTest.php @@ -80,6 +80,7 @@ protected function setUp() { $this->config('locale.settings') ->set('translation.import_enabled', TRUE) ->save(); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationOverviewTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationOverviewTest.php index a2f6a6c..2a7553e 100644 --- a/core/modules/config_translation/src/Tests/ConfigTranslationOverviewTest.php +++ b/core/modules/config_translation/src/Tests/ConfigTranslationOverviewTest.php @@ -23,7 +23,7 @@ class ConfigTranslationOverviewTest extends WebTestBase { * * @var array */ - public static $modules = array('contact', 'config_translation', 'views', 'views_ui', 'contextual', 'config_test', 'config_translation_test'); + public static $modules = ['block', 'contact', 'config_translation', 'views', 'views_ui', 'contextual', 'config_test', 'config_translation_test']; /** * Languages to enable. @@ -58,6 +58,7 @@ protected function setUp() { ConfigurableLanguage::createFromLangcode($langcode)->save(); } $this->localeStorage = $this->container->get('locale.storage'); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php index c7218df..ecdffce 100644 --- a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php +++ b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php @@ -28,7 +28,7 @@ class ConfigTranslationUiTest extends WebTestBase { * * @var array */ - public static $modules = array('node', 'contact', 'contact_test', 'config_translation', 'config_translation_test', 'views', 'views_ui', 'contextual', 'filter', 'filter_test'); + public static $modules = ['block', 'node', 'contact', 'contact_test', 'config_translation', 'config_translation_test', 'views', 'views_ui', 'contextual', 'filter', 'filter_test']; /** * Languages to enable. @@ -100,6 +100,7 @@ protected function setUp() { ConfigurableLanguage::createFromLangcode($langcode)->save(); } $this->localeStorage = $this->container->get('locale.storage'); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/contact/src/Tests/ContactSitewideTest.php b/core/modules/contact/src/Tests/ContactSitewideTest.php index c815d35..a8e5ecf 100644 --- a/core/modules/contact/src/Tests/ContactSitewideTest.php +++ b/core/modules/contact/src/Tests/ContactSitewideTest.php @@ -39,6 +39,7 @@ class ContactSitewideTest extends WebTestBase { protected function setUp() { parent::setUp(); $this->drupalPlaceBlock('system_breadcrumb_block'); + $this->drupalPlaceBlock('system_page_actions_block'); } /** diff --git a/core/modules/contact/src/Tests/ContactStorageTest.php b/core/modules/contact/src/Tests/ContactStorageTest.php index 5d62e10..f18d10e 100644 --- a/core/modules/contact/src/Tests/ContactStorageTest.php +++ b/core/modules/contact/src/Tests/ContactStorageTest.php @@ -28,13 +28,14 @@ class ContactStorageTest extends ContactSitewideTest { * * @var array */ - public static $modules = array( + public static $modules = [ + 'block', 'text', 'contact', 'field_ui', 'contact_storage_test', 'contact_test', - ); + ]; /** * Tests configuration options and the site-wide contact form. diff --git a/core/modules/field_ui/src/Tests/EntityDisplayModeTest.php b/core/modules/field_ui/src/Tests/EntityDisplayModeTest.php index 7b7fe12..5f497a8 100644 --- a/core/modules/field_ui/src/Tests/EntityDisplayModeTest.php +++ b/core/modules/field_ui/src/Tests/EntityDisplayModeTest.php @@ -19,9 +19,18 @@ class EntityDisplayModeTest extends WebTestBase { /** * Modules to enable. * - * @var array + * @var string[] */ - public static $modules = array('entity_test', 'field_ui'); + public static $modules = ['block', 'entity_test', 'field_ui']; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('system_page_actions_block'); + } /** * Tests the EntityViewMode user interface. diff --git a/core/modules/field_ui/src/Tests/FieldUIRouteTest.php b/core/modules/field_ui/src/Tests/FieldUIRouteTest.php index 332a87d..9f44c86 100644 --- a/core/modules/field_ui/src/Tests/FieldUIRouteTest.php +++ b/core/modules/field_ui/src/Tests/FieldUIRouteTest.php @@ -23,7 +23,7 @@ class FieldUIRouteTest extends WebTestBase { * * @var string[] */ - public static $modules = array('entity_test', 'field_ui'); + public static $modules = ['block', 'entity_test', 'field_ui']; /** * {@inheritdoc} @@ -32,6 +32,7 @@ protected function setUp() { parent::setUp(); $this->drupalLogin($this->rootUser); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/field_ui/src/Tests/ManageFieldsTest.php b/core/modules/field_ui/src/Tests/ManageFieldsTest.php index 3b90bff..1d18de2 100644 --- a/core/modules/field_ui/src/Tests/ManageFieldsTest.php +++ b/core/modules/field_ui/src/Tests/ManageFieldsTest.php @@ -66,7 +66,10 @@ class ManageFieldsTest extends WebTestBase { */ protected function setUp() { parent::setUp(); + $this->drupalPlaceBlock('system_breadcrumb_block'); + $this->drupalPlaceBlock('system_page_actions_block'); + $this->drupalPlaceBlock('system_page_tabs_block'); // Create a test user. $admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer node fields', 'administer node form display', 'administer node display', 'administer taxonomy', 'administer taxonomy_term fields', 'administer taxonomy_term display', 'administer users', 'administer account settings', 'administer user display', 'bypass node access')); diff --git a/core/modules/filter/src/Tests/FilterAdminTest.php b/core/modules/filter/src/Tests/FilterAdminTest.php index 112c486..a12cefe 100644 --- a/core/modules/filter/src/Tests/FilterAdminTest.php +++ b/core/modules/filter/src/Tests/FilterAdminTest.php @@ -22,7 +22,7 @@ class FilterAdminTest extends WebTestBase { /** * {@inheritdoc} */ - public static $modules = array('filter', 'node'); + public static $modules = ['block', 'filter', 'node']; /** * An user with administration permissions. @@ -105,6 +105,7 @@ protected function setUp() { user_role_grant_permissions('authenticated', array($basic_html_format->getPermissionName())); user_role_grant_permissions('anonymous', array($restricted_html_format->getPermissionName())); $this->drupalLogin($this->adminUser); + $this->drupalPlaceBlock('system_page_actions_block'); } /** diff --git a/core/modules/filter/src/Tests/FilterFormatAccessTest.php b/core/modules/filter/src/Tests/FilterFormatAccessTest.php index 32d5d04..aa45bbd 100644 --- a/core/modules/filter/src/Tests/FilterFormatAccessTest.php +++ b/core/modules/filter/src/Tests/FilterFormatAccessTest.php @@ -24,7 +24,7 @@ class FilterFormatAccessTest extends WebTestBase { * * @var array */ - public static $modules = array('filter', 'node'); + public static $modules = ['block', 'filter', 'node']; /** * A user with administrative permissions. @@ -114,6 +114,7 @@ protected function setUp() { $this->secondAllowedFormat->getPermissionName(), $this->disallowedFormat->getPermissionName(), )); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/forum/src/Tests/ForumTest.php b/core/modules/forum/src/Tests/ForumTest.php index 9440179..cb591a4 100644 --- a/core/modules/forum/src/Tests/ForumTest.php +++ b/core/modules/forum/src/Tests/ForumTest.php @@ -113,6 +113,7 @@ protected function setUp() { 'access comments', )); $this->drupalPlaceBlock('help_block', array('region' => 'help')); + $this->drupalPlaceBlock('system_page_actions_block'); } /** diff --git a/core/modules/language/src/Tests/LanguagePathMonolingualTest.php b/core/modules/language/src/Tests/LanguagePathMonolingualTest.php index d3aa814..5e741c7 100644 --- a/core/modules/language/src/Tests/LanguagePathMonolingualTest.php +++ b/core/modules/language/src/Tests/LanguagePathMonolingualTest.php @@ -21,7 +21,7 @@ class LanguagePathMonolingualTest extends WebTestBase { * * @var array */ - public static $modules = array('language', 'path'); + public static $modules = ['block', 'language', 'path']; protected function setUp() { parent::setUp(); @@ -56,6 +56,7 @@ protected function setUp() { // Set language detection to URL. $edit = array('language_interface[enabled][language-url]' => TRUE); $this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings')); + $this->drupalPlaceBlock('system_page_actions_block'); } /** diff --git a/core/modules/language/src/Tests/LanguageTourTest.php b/core/modules/language/src/Tests/LanguageTourTest.php index 98418b6..03d2b16 100644 --- a/core/modules/language/src/Tests/LanguageTourTest.php +++ b/core/modules/language/src/Tests/LanguageTourTest.php @@ -28,7 +28,7 @@ class LanguageTourTest extends TourTestBase { * * @var array */ - public static $modules = array('language', 'tour'); + public static $modules = ['block', 'language', 'tour']; /** * {@inheritdoc} @@ -37,6 +37,7 @@ protected function setUp() { parent::setUp(); $this->adminUser = $this->drupalCreateUser(array('administer languages', 'access tour')); $this->drupalLogin($this->adminUser); + $this->drupalPlaceBlock('system_page_actions_block'); } /** diff --git a/core/modules/node/src/Tests/PageEditTest.php b/core/modules/node/src/Tests/PageEditTest.php index 582ab6f..6ee5722 100644 --- a/core/modules/node/src/Tests/PageEditTest.php +++ b/core/modules/node/src/Tests/PageEditTest.php @@ -16,11 +16,19 @@ class PageEditTest extends NodeTestBase { protected $webUser; protected $adminUser; + /** + * Modules to enable. + * + * @var array + */ + public static $modules = ['block', 'node', 'datetime']; + protected function setUp() { parent::setUp(); $this->webUser = $this->drupalCreateUser(array('edit own page content', 'create page content')); $this->adminUser = $this->drupalCreateUser(array('bypass node access', 'administer nodes')); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php b/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php index a99ea45..273673e 100644 --- a/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php +++ b/core/modules/search/src/Tests/SearchConfigSettingsFormTest.php @@ -58,6 +58,7 @@ protected function setUp() { // Enable the search block. $this->drupalPlaceBlock('search_form_block'); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/search/src/Tests/SearchPageTextTest.php b/core/modules/search/src/Tests/SearchPageTextTest.php index 4614baf..5d0f8ed 100644 --- a/core/modules/search/src/Tests/SearchPageTextTest.php +++ b/core/modules/search/src/Tests/SearchPageTextTest.php @@ -23,11 +23,19 @@ class SearchPageTextTest extends SearchTestBase { */ protected $searchingUser; + /** + * Modules to enable. + * + * @var array + */ + public static $modules = ['block', 'node', 'search', 'dblog']; + protected function setUp() { parent::setUp(); // Create user. $this->searchingUser = $this->drupalCreateUser(array('search content', 'access user profiles', 'use advanced search')); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/shortcut/src/Tests/ShortcutSetsTest.php b/core/modules/shortcut/src/Tests/ShortcutSetsTest.php index db98745..0e1c33c 100644 --- a/core/modules/shortcut/src/Tests/ShortcutSetsTest.php +++ b/core/modules/shortcut/src/Tests/ShortcutSetsTest.php @@ -18,6 +18,22 @@ class ShortcutSetsTest extends ShortcutTestBase { /** + * Modules to enable. + * + * @var string[] + */ + public static $modules = ['block']; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('system_page_actions_block'); + } + + /** * Tests creating a shortcut set. */ function testShortcutSetAdd() { diff --git a/core/modules/simpletest/src/Tests/BrowserTest.php b/core/modules/simpletest/src/Tests/BrowserTest.php index d43f63b..ecf9a28 100644 --- a/core/modules/simpletest/src/Tests/BrowserTest.php +++ b/core/modules/simpletest/src/Tests/BrowserTest.php @@ -24,6 +24,22 @@ class BrowserTest extends WebTestBase { protected static $cookieSet = FALSE; /** + * Modules to enable. + * + * @var string[] + */ + public static $modules = ['block']; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('system_page_tabs_block'); + } + + /** * Test \Drupal\simpletest\WebTestBase::getAbsoluteUrl(). */ function testGetAbsoluteUrl() { diff --git a/core/modules/system/config/schema/system.schema.yml b/core/modules/system/config/schema/system.schema.yml index 7cde50d..dfa4fd1 100644 --- a/core/modules/system/config/schema/system.schema.yml +++ b/core/modules/system/config/schema/system.schema.yml @@ -353,6 +353,17 @@ block.settings.system_menu_block:*: type: integer label: 'Maximum number of levels' +block.settings.system_page_tabs_block: + type: block_settings + label: 'Tabs block' + mapping: + primary_tasks: + type: integer + label: 'Whether primary tabs is shown' + secondary_tasks: + type: integer + label: 'Whether secondary tabs is shown' + condition.plugin.request_path: type: condition.plugin mapping: diff --git a/core/modules/system/src/Plugin/Block/SystemPageActionsBlock.php b/core/modules/system/src/Plugin/Block/SystemPageActionsBlock.php new file mode 100644 index 0000000..ff71680 --- /dev/null +++ b/core/modules/system/src/Plugin/Block/SystemPageActionsBlock.php @@ -0,0 +1,122 @@ +localActionManager = $local_action_manager; + $this->routeMatch = $route_match; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('plugin.manager.menu.local_action'), + $container->get('current_route_match') + ); + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return ['label_display' => FALSE]; + } + + /** + * {@inheritdoc} + */ + public function build() { + $build = []; + $links = menu_local_tasks(); + $route_name = $this->routeMatch->getRouteName(); + $action_links = $this->localActionManager->getActionsForRoute($route_name) + $links['actions']; + if (empty($action_links)) { + return []; + } + + $build['action_links'] = $action_links; + + return $build; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $form = parent::buildConfigurationForm($form, $form_state); + + // The "Page actions" block is never cacheable, due to access checking. + $form['cache']['#disabled'] = TRUE; + $form['cache']['#description'] = $this->t('This block is never cacheable because access checking is needed, it is not configurable.'); + $form['cache']['max_age']['#value'] = 0; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function getCacheMaxAge() { + // @todo Make me cacheable now that https://drupal.org/node/2287071 has landed. + return 0; + } + + + +} diff --git a/core/modules/system/src/Plugin/Block/SystemPageTabsBlock.php b/core/modules/system/src/Plugin/Block/SystemPageTabsBlock.php new file mode 100644 index 0000000..5939e85 --- /dev/null +++ b/core/modules/system/src/Plugin/Block/SystemPageTabsBlock.php @@ -0,0 +1,138 @@ + FALSE, + 'primary_tasks' => TRUE, + 'secondary_tasks' => TRUE, + ]; + } + + /** + * {@inheritdoc} + */ + public function build() { + $config = $this->configuration; + + $tabs = [ + '#theme' => 'menu_local_tasks', + ]; + if ($config['primary_tasks']) { + $tabs += [ + '#primary' => menu_primary_local_tasks(), + ]; + } + if ($config['secondary_tasks']) { + $tabs += [ + '#secondary' => menu_secondary_local_tasks(), + ]; + } + if (empty($tabs['#primary']) && empty($tabs['#secondary'])) { + return []; + } + $build['tabs'] = $tabs; + return $build; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $form = parent::buildConfigurationForm($form, $form_state); + + $form['cache']['#disabled'] = TRUE; + $form['cache']['#description'] = $this->t('This block is never cacheable because access checking is needed, it is not configurable.'); + $form['cache']['max_age']['#value'] = 0; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function getCacheMaxAge() { + // @todo Make cacheable now that https://drupal.org/node/2287071 has landed. + return 0; + } + + /** + * {@inheritdoc} + */ + public function getCacheContexts() { + return ['route.name']; + } + + /** + * {@inheritdoc} + */ + public function blockForm($form, FormStateInterface $form_state) { + $config = $this->configuration; + $defaults = $this->defaultConfiguration(); + + $form['levels'] = array( + '#type' => 'details', + '#title' => $this->t('Shown tabs'), + '#description' => $this->t('Select local tasks being shown in the block'), + // Open if not set to defaults. + '#open' => $defaults['primary_tasks'] !== $config['primary_tasks'] || $defaults['secondary_tasks'] !== $config['secondary_tasks'], + ); + $form['levels']['primary_tasks'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Show primary tabs'), + '#default_value' => $config['primary_tasks'], + ]; + $form['levels']['secondary_tasks'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Show secondary tabs'), + '#default_value' => $config['secondary_tasks'], + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function blockSubmit($form, FormStateInterface $form_state) { + $this->configuration['primary_tasks'] = $form_state->getValue(['levels', 'primary_tasks']); + $this->configuration['secondary_tasks'] = $form_state->getValue(['levels', 'secondary_tasks']); + } + +} diff --git a/core/modules/system/src/Tests/Menu/LocalActionTest.php b/core/modules/system/src/Tests/Menu/LocalActionTest.php index c049198..7fd2f2f 100644 --- a/core/modules/system/src/Tests/Menu/LocalActionTest.php +++ b/core/modules/system/src/Tests/Menu/LocalActionTest.php @@ -18,9 +18,20 @@ class LocalActionTest extends WebTestBase { /** + * Modules to enable. + * + * @var string[] + */ + public static $modules = ['block', 'menu_test']; + + /** * {@inheritdoc} */ - public static $modules = array('menu_test'); + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('system_page_actions_block'); + } /** * Tests appearance of local actions. diff --git a/core/modules/system/src/Tests/Menu/LocalTasksTest.php b/core/modules/system/src/Tests/Menu/LocalTasksTest.php index b7824ef..4f99b86 100644 --- a/core/modules/system/src/Tests/Menu/LocalTasksTest.php +++ b/core/modules/system/src/Tests/Menu/LocalTasksTest.php @@ -17,7 +17,21 @@ */ class LocalTasksTest extends WebTestBase { - public static $modules = array('menu_test', 'entity_test'); + /** + * Modules to enable. + * + * @var string[] + */ + public static $modules = ['block', 'menu_test', 'entity_test']; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('system_page_tabs_block'); + } /** * Asserts local tasks in the page output. diff --git a/core/modules/system/src/Tests/Menu/MenuRouterTest.php b/core/modules/system/src/Tests/Menu/MenuRouterTest.php index d75bd6c..f54bd11 100644 --- a/core/modules/system/src/Tests/Menu/MenuRouterTest.php +++ b/core/modules/system/src/Tests/Menu/MenuRouterTest.php @@ -43,6 +43,7 @@ protected function setUp() { parent::setUp(); $this->drupalPlaceBlock('system_menu_block:tools'); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/system/src/Tests/Menu/MenuTranslateTest.php b/core/modules/system/src/Tests/Menu/MenuTranslateTest.php index e316c95..f4e158a 100644 --- a/core/modules/system/src/Tests/Menu/MenuTranslateTest.php +++ b/core/modules/system/src/Tests/Menu/MenuTranslateTest.php @@ -23,7 +23,16 @@ class MenuTranslateTest extends WebTestBase { * * @var array */ - public static $modules = array('menu_test'); + public static $modules = ['block', 'menu_test']; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('system_page_tabs_block'); + } /** * Tests _menu_translate(). diff --git a/core/modules/system/src/Tests/System/DateTimeTest.php b/core/modules/system/src/Tests/System/DateTimeTest.php index 9f0b0ac..f01200b 100644 --- a/core/modules/system/src/Tests/System/DateTimeTest.php +++ b/core/modules/system/src/Tests/System/DateTimeTest.php @@ -22,13 +22,14 @@ class DateTimeTest extends WebTestBase { * * @var array */ - public static $modules = array('node', 'language'); + public static $modules = ['block', 'node', 'language']; protected function setUp() { parent::setUp(); // Create admin user and log in admin user. $this->drupalLogin ($this->drupalCreateUser(array('administer site configuration'))); + $this->drupalPlaceBlock('system_page_actions_block'); } /** diff --git a/core/modules/system/src/Tests/System/ThemeTest.php b/core/modules/system/src/Tests/System/ThemeTest.php index d5bb6f6..48710cb 100644 --- a/core/modules/system/src/Tests/System/ThemeTest.php +++ b/core/modules/system/src/Tests/System/ThemeTest.php @@ -30,7 +30,7 @@ class ThemeTest extends WebTestBase { * * @var array */ - public static $modules = array('node', 'block', 'file'); + public static $modules = ['node', 'block', 'file']; protected function setUp() { parent::setUp(); @@ -40,6 +40,7 @@ protected function setUp() { $this->adminUser = $this->drupalCreateUser(array('access administration pages', 'view the administration theme', 'administer themes', 'bypass node access', 'administer blocks')); $this->drupalLogin($this->adminUser); $this->node = $this->drupalCreateNode(); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 96f0083..99785f9 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -169,6 +169,14 @@ function system_theme() { 'block__system_messages_block' => array( 'base hook' => 'block', ), + 'block__system_page_actions_block' => [ + 'base hook' => 'block', + 'template' => 'block--system-page-actions-block', + ], + 'block__system_page_tabs_block' => [ + 'base hook' => 'block', + 'template' => 'block--system-page-tabs-block', + ], 'block__system_menu_block' => array( 'render element' => 'elements', 'base hook' => 'block', @@ -782,6 +790,14 @@ function system_preprocess_block(&$variables) { } break; + case 'system_page_actions_block': + $variables['action_links'] = $variables['content']['action_links']; + break; + + case 'system_page_tabs_block': + $variables['tabs'] = $variables['content']['tabs']; + break; + case 'system_powered_by_block': $variables['attributes']['role'] = 'complementary'; break; diff --git a/core/modules/system/templates/block--system-page-actions-block.html.twig b/core/modules/system/templates/block--system-page-actions-block.html.twig new file mode 100644 index 0000000..a5972dc --- /dev/null +++ b/core/modules/system/templates/block--system-page-actions-block.html.twig @@ -0,0 +1,18 @@ +{% extends "@block/block.html.twig" %} +{# +/** + * @file + * Default theme implementation for page local actions. + * + * Available variables: + * - action_links: Actions local to the page, such as "Add menu" on the menu + * administration interface. + * + * @ingroup themeable + */ +#} +{% block content %} + {% if action_links %} + + {% endif %} +{% endblock %} diff --git a/core/modules/system/templates/block--system-page-tabs-block.html.twig b/core/modules/system/templates/block--system-page-tabs-block.html.twig new file mode 100644 index 0000000..780abe7 --- /dev/null +++ b/core/modules/system/templates/block--system-page-tabs-block.html.twig @@ -0,0 +1,16 @@ +{% extends "@block/block.html.twig" %} +{# +/** + * @file + * Default theme implementation for page tabs. + * + * Available variables: + * - tabs: The Tabs linking to any sub-pages beneath the current page (e.g., the + * view and edit tabs when displaying a node). + * + * @ingroup themeable + */ +#} +{% block content %} + {{ tabs }} +{% endblock %} diff --git a/core/modules/system/templates/page.html.twig b/core/modules/system/templates/page.html.twig index c5a3711..6200539 100644 --- a/core/modules/system/templates/page.html.twig +++ b/core/modules/system/templates/page.html.twig @@ -32,10 +32,6 @@ * - title_suffix: Additional output populated by modules, intended to be * displayed after the main title tag that appears in the template. * - messages: Status and error messages. Should be displayed prominently. - * - tabs: Tabs linking to any sub-pages beneath the current page (e.g., the - * view and edit tabs when displaying a node). - * - action_links: Actions local to the page, such as "Add menu" on the menu - * administration interface. * - node: Fully loaded node, if there is an automatically-loaded node * associated with the page and the node ID is the second argument in the * page's path (e.g. node/12345 and node/12345/revisions, but not @@ -52,6 +48,8 @@ * - page.sidebar_second: Items for the second sidebar. * - page.footer: Items for the footer region. * - page.breadcrumb: Items for the breadcrumb region. + * - page.tabs: Items for the tabs region. + * - page.actions: Items for the actions region. * * @see template_preprocess_page() * @see html.html.twig @@ -111,11 +109,9 @@ {% endif %} {{ title_suffix }} - {{ tabs }} + {{ page.tabs }} - {% if action_links %} - - {% endif %} + {{ page.actions }} {{ page.content }} {# /.layout-content #} diff --git a/core/modules/taxonomy/src/Tests/TermTest.php b/core/modules/taxonomy/src/Tests/TermTest.php index bfeeb86..e326c74 100644 --- a/core/modules/taxonomy/src/Tests/TermTest.php +++ b/core/modules/taxonomy/src/Tests/TermTest.php @@ -35,8 +35,22 @@ class TermTest extends TaxonomyTestBase { */ protected $field; + /** + * Modules to enable. + * + * @var string[] + */ + public static $modules = ['block']; + + /** + * {@inheritdoc} + */ protected function setUp() { parent::setUp(); + + $this->drupalPlaceBlock('system_page_actions_block'); + $this->drupalPlaceBlock('system_page_tabs_block'); + $this->drupalLogin($this->drupalCreateUser(['administer taxonomy', 'bypass node access'])); $this->vocabulary = $this->createVocabulary(); diff --git a/core/modules/taxonomy/src/Tests/VocabularyUiTest.php b/core/modules/taxonomy/src/Tests/VocabularyUiTest.php index 3a34c2e..791d168 100644 --- a/core/modules/taxonomy/src/Tests/VocabularyUiTest.php +++ b/core/modules/taxonomy/src/Tests/VocabularyUiTest.php @@ -29,6 +29,7 @@ protected function setUp() { parent::setUp(); $this->drupalLogin($this->drupalCreateUser(['administer taxonomy'])); $this->vocabulary = $this->createVocabulary(); + $this->drupalPlaceBlock('system_page_actions_block'); } /** diff --git a/core/modules/tour/src/Tests/TourTest.php b/core/modules/tour/src/Tests/TourTest.php index 8ed261c..fa3df85 100644 --- a/core/modules/tour/src/Tests/TourTest.php +++ b/core/modules/tour/src/Tests/TourTest.php @@ -21,7 +21,7 @@ class TourTest extends TourTestBasic { * * @var array */ - public static $modules = array('tour', 'locale', 'language', 'tour_test'); + public static $modules = ['block', 'tour', 'locale', 'language', 'tour_test']; /** * The permissions required for a logged in user to test tour tips. @@ -42,6 +42,18 @@ class TourTest extends TourTestBasic { ); /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->drupalPlaceBlock('system_page_actions_block', [ + 'theme' => 'seven', + 'region' => 'actions' + ]); + } + + /** * Test tour functionality. */ public function testTourFunctionality() { diff --git a/core/modules/tracker/src/Tests/TrackerTest.php b/core/modules/tracker/src/Tests/TrackerTest.php index c20c054..0593622 100644 --- a/core/modules/tracker/src/Tests/TrackerTest.php +++ b/core/modules/tracker/src/Tests/TrackerTest.php @@ -29,7 +29,7 @@ class TrackerTest extends WebTestBase { * * @var array */ - public static $modules = array('comment', 'tracker', 'history', 'node_test'); + public static $modules = ['block', 'comment', 'tracker', 'history', 'node_test']; /** * The main user for testing. @@ -54,6 +54,8 @@ protected function setUp() { $this->user = $this->drupalCreateUser($permissions); $this->otherUser = $this->drupalCreateUser($permissions); $this->addDefaultCommentField('node', 'page'); + $this->drupalPlaceBlock('system_page_tabs_block'); + $this->drupalPlaceBlock('system_page_actions_block'); } /** diff --git a/core/modules/update/src/Tests/UpdateCoreTest.php b/core/modules/update/src/Tests/UpdateCoreTest.php index 3aa598a..fdbf735 100644 --- a/core/modules/update/src/Tests/UpdateCoreTest.php +++ b/core/modules/update/src/Tests/UpdateCoreTest.php @@ -22,12 +22,13 @@ class UpdateCoreTest extends UpdateTestBase { * * @var array */ - public static $modules = array('update_test', 'update', 'language'); + public static $modules = ['update_test', 'update', 'language', 'block']; protected function setUp() { parent::setUp(); $admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer modules', 'administer themes')); $this->drupalLogin($admin_user); + $this->drupalPlaceBlock('system_page_actions_block'); } /** diff --git a/core/modules/user/src/Tests/UserRoleAdminTest.php b/core/modules/user/src/Tests/UserRoleAdminTest.php index c19130c..f65897e 100644 --- a/core/modules/user/src/Tests/UserRoleAdminTest.php +++ b/core/modules/user/src/Tests/UserRoleAdminTest.php @@ -25,9 +25,17 @@ class UserRoleAdminTest extends WebTestBase { */ protected $adminUser; + /** + * Modules to enable. + * + * @var array + */ + public static $modules = ['block']; + protected function setUp() { parent::setUp(); $this->adminUser = $this->drupalCreateUser(array('administer permissions', 'administer users')); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/views/src/Tests/Plugin/DisplayPageWebTest.php b/core/modules/views/src/Tests/Plugin/DisplayPageWebTest.php index 31bfd3c..3b9f5bb 100644 --- a/core/modules/views/src/Tests/Plugin/DisplayPageWebTest.php +++ b/core/modules/views/src/Tests/Plugin/DisplayPageWebTest.php @@ -33,10 +33,14 @@ class DisplayPageWebTest extends PluginTestBase { */ public static $modules = ['menu_ui', 'block']; + /** + * {@inheritdoc} + */ protected function setUp() { parent::setUp(); $this->enableViewsTestModule(); + $this->drupalPlaceBlock('system_page_tabs_block'); } /** diff --git a/core/modules/views/src/Tests/Wizard/WizardTestBase.php b/core/modules/views/src/Tests/Wizard/WizardTestBase.php index 0a2e998..b81ee73 100644 --- a/core/modules/views/src/Tests/Wizard/WizardTestBase.php +++ b/core/modules/views/src/Tests/Wizard/WizardTestBase.php @@ -27,6 +27,7 @@ protected function setUp() { // Create and log in a user with administer views permission. $views_admin = $this->drupalCreateUser(array('administer views', 'administer blocks', 'bypass node access', 'access user profiles', 'view all revisions')); $this->drupalLogin($views_admin); + $this->drupalPlaceBlock('system_page_actions_block'); } } diff --git a/core/modules/views_ui/src/Tests/SettingsTest.php b/core/modules/views_ui/src/Tests/SettingsTest.php index 262fc7a..523288c 100644 --- a/core/modules/views_ui/src/Tests/SettingsTest.php +++ b/core/modules/views_ui/src/Tests/SettingsTest.php @@ -22,6 +22,14 @@ class SettingsTest extends UITestBase { protected $adminUser; /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + $this->drupalPlaceBlock('system_page_tabs_block'); + } + + /** * Tests the settings for the edit ui. */ function testEditUI() { diff --git a/core/profiles/minimal/config/install/block.block.stark_page_actions.yml b/core/profiles/minimal/config/install/block.block.stark_page_actions.yml new file mode 100644 index 0000000..44cb317 --- /dev/null +++ b/core/profiles/minimal/config/install/block.block.stark_page_actions.yml @@ -0,0 +1,18 @@ +id: bartik_page_actions +theme: stark +weight: 10 +status: true +langcode: en +region: actions +plugin: system_page_actions_block +settings: + id: system_page_actions_block + label: Page actions + provider: system + label_display: '0' +dependencies: + module: + - system + theme: + - stark +visibility: { } diff --git a/core/profiles/minimal/config/install/block.block.stark_page_tabs.yml b/core/profiles/minimal/config/install/block.block.stark_page_tabs.yml new file mode 100644 index 0000000..6660d0f --- /dev/null +++ b/core/profiles/minimal/config/install/block.block.stark_page_tabs.yml @@ -0,0 +1,18 @@ +id: bartik_page_tabs +theme: stark +weight: 10 +status: true +langcode: en +region: tabs +plugin: system_page_tabs_block +settings: + id: system_page_tabs_block + label: Page tabs + provider: system + label_display: '0' +dependencies: + module: + - system + theme: + - stark +visibility: { } diff --git a/core/profiles/standard/config/install/block.block.bartik_page_actions.yml b/core/profiles/standard/config/install/block.block.bartik_page_actions.yml new file mode 100644 index 0000000..4e051e8 --- /dev/null +++ b/core/profiles/standard/config/install/block.block.bartik_page_actions.yml @@ -0,0 +1,18 @@ +id: bartik_page_actions +theme: bartik +weight: 10 +status: true +langcode: en +region: actions +plugin: system_page_actions_block +settings: + id: system_page_actions_block + label: Page actions + provider: system + label_display: '0' +dependencies: + module: + - system + theme: + - bartik +visibility: { } diff --git a/core/profiles/standard/config/install/block.block.bartik_page_tabs.yml b/core/profiles/standard/config/install/block.block.bartik_page_tabs.yml new file mode 100644 index 0000000..c8cf59a --- /dev/null +++ b/core/profiles/standard/config/install/block.block.bartik_page_tabs.yml @@ -0,0 +1,18 @@ +id: bartik_page_tabs +theme: bartik +weight: 10 +status: true +langcode: en +region: tabs +plugin: system_page_tabs_block +settings: + id: system_page_tabs_block + label: Page tabs + provider: system + label_display: '0' +dependencies: + module: + - system + theme: + - bartik +visibility: { } diff --git a/core/profiles/standard/config/install/block.block.seven_page_actions.yml b/core/profiles/standard/config/install/block.block.seven_page_actions.yml new file mode 100644 index 0000000..7802a57 --- /dev/null +++ b/core/profiles/standard/config/install/block.block.seven_page_actions.yml @@ -0,0 +1,18 @@ +id: page_actions +theme: seven +weight: 0 +status: true +langcode: en +region: actions +plugin: system_page_actions_block +settings: + id: system_page_actions_block + label: Page actions + provider: system + label_display: '0' +dependencies: + module: + - system + theme: + - seven +visibility: { } diff --git a/core/profiles/standard/config/install/block.block.seven_page_primary_tabs.yml b/core/profiles/standard/config/install/block.block.seven_page_primary_tabs.yml new file mode 100644 index 0000000..907f489 --- /dev/null +++ b/core/profiles/standard/config/install/block.block.seven_page_primary_tabs.yml @@ -0,0 +1,20 @@ +id: page_primary_tabs +theme: seven +weight: 0 +status: true +langcode: en +region: primary_tabs +plugin: system_page_tabs_block +settings: + id: system_page_tabs_block + label: Primary tabs + provider: system + label_display: '0' + primary_tasks: 1 + secondary_tasks: 0 +dependencies: + module: + - system + theme: + - seven +visibility: { } diff --git a/core/profiles/standard/config/install/block.block.seven_page_seconadry_tabs.yml b/core/profiles/standard/config/install/block.block.seven_page_seconadry_tabs.yml new file mode 100644 index 0000000..b01ae48 --- /dev/null +++ b/core/profiles/standard/config/install/block.block.seven_page_seconadry_tabs.yml @@ -0,0 +1,20 @@ +id: page_secondary_tabs +theme: seven +weight: 0 +status: true +langcode: en +region: secondary_tabs +plugin: system_page_tabs_block +settings: + id: system_page_tabs_block + label: Secondary tabs + provider: system + label_display: '0' + primary_tasks: 0 + secondary_tasks: 1 +dependencies: + module: + - system + theme: + - seven +visibility: { } diff --git a/core/themes/bartik/bartik.info.yml b/core/themes/bartik/bartik.info.yml index fb8f2fb..444992e 100644 --- a/core/themes/bartik/bartik.info.yml +++ b/core/themes/bartik/bartik.info.yml @@ -24,6 +24,8 @@ regions: highlighted: Highlighted featured_top: 'Featured top' breadcrumb: Breadcrumb + tabs: Tabs + actions: Actions content: Content sidebar_first: 'Sidebar first' sidebar_second: 'Sidebar second' diff --git a/core/themes/bartik/templates/block--system-page-actions-block.html.twig b/core/themes/bartik/templates/block--system-page-actions-block.html.twig new file mode 100644 index 0000000..b8283b5 --- /dev/null +++ b/core/themes/bartik/templates/block--system-page-actions-block.html.twig @@ -0,0 +1,20 @@ +{% extends "@block/block.html.twig" %} +{# +/** + * @file + * Bartik's theme implementation for page local actions. + * + * Available variables: + * - action_links: Actions local to the page, such as "Add menu" on the menu + * administration interface. + * + * @ingroup themeable + */ +#} +{% block content %} + {% if action_links %} +