diff --git a/core/modules/file/config/install/views.view.files.yml b/core/modules/file/config/install/views.view.files.yml
index cc7d114..2702d6a 100644
--- a/core/modules/file/config/install/views.view.files.yml
+++ b/core/modules/file/config/install/views.view.files.yml
@@ -667,7 +667,8 @@ display:
display_options:
path: admin/content/files
menu:
- type: tab
+ type:
+ tab: tab
title: Files
description: ''
name: admin
diff --git a/core/modules/node/config/install/views.view.content.yml b/core/modules/node/config/install/views.view.content.yml
index 074c5b5..b52d20b 100644
--- a/core/modules/node/config/install/views.view.content.yml
+++ b/core/modules/node/config/install/views.view.content.yml
@@ -538,7 +538,8 @@ display:
display_options:
path: admin/content/node
menu:
- type: 'default tab'
+ type:
+ 'default tab': 'default tab'
title: Content
description: ''
name: admin
diff --git a/core/modules/node/config/install/views.view.glossary.yml b/core/modules/node/config/install/views.view.glossary.yml
index 03a7a18..85a00f5 100644
--- a/core/modules/node/config/install/views.view.glossary.yml
+++ b/core/modules/node/config/install/views.view.glossary.yml
@@ -313,7 +313,8 @@ display:
options: { }
path: glossary
menu:
- type: normal
+ type:
+ normal: normal
title: Glossary
weight: 0
attachment_1:
diff --git a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_contextual_links.yml b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_contextual_links.yml
index fbb49e3..9dce30d 100644
--- a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_contextual_links.yml
+++ b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_contextual_links.yml
@@ -81,7 +81,8 @@ display:
plugin_id: numeric
provider: views
menu:
- type: tab
+ type:
+ tab: tab
title: 'Test contextual link'
description: ''
name: tools
diff --git a/core/modules/user/config/install/views.view.user_admin_people.yml b/core/modules/user/config/install/views.view.user_admin_people.yml
index 89d1e4e..4492b9e 100644
--- a/core/modules/user/config/install/views.view.user_admin_people.yml
+++ b/core/modules/user/config/install/views.view.user_admin_people.yml
@@ -937,7 +937,8 @@ display:
path: admin/people/list
show_admin_links: false
menu:
- type: 'default tab'
+ type:
+ 'default tab': 'default tab'
title: List
description: 'Find and manage people interacting with your site.'
name: admin
diff --git a/core/modules/views/config/schema/views.display.schema.yml b/core/modules/views/config/schema/views.display.schema.yml
index 5bd1ab3..bf3cbba 100644
--- a/core/modules/views/config/schema/views.display.schema.yml
+++ b/core/modules/views/config/schema/views.display.schema.yml
@@ -23,8 +23,11 @@ views.display.page:
label: 'Menu'
mapping:
type:
- type: string
+ type: sequence
label: 'Type'
+ sequence:
+ - type: string
+ label: 'Menu type'
title:
type: text
label: 'Title'
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsLocalTask.php b/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsLocalTask.php
index b38c4a4..7e311ff 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsLocalTask.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/Derivative/ViewsLocalTask.php
@@ -69,25 +69,27 @@ public function getDerivativeDefinitions($base_plugin_definition) {
$executable->setDisplay($display_id);
$menu = $executable->display_handler->getOption('menu');
- if (in_array($menu['type'], array('tab', 'default tab'))) {
- $plugin_id = 'view.' . $executable->storage->id() . '.' . $display_id;
- $route_name = $view_route_names[$executable->storage->id() . '.' . $display_id];
-
- // Don't add a local task for views which override existing routes.
- // @todo Alternative it could just change the existing entry.
- if ($route_name != $plugin_id) {
- continue;
- }
+ foreach ($menu['type'] as $type) {
+ if (in_array($type, array('tab', 'default tab'))) {
+ $plugin_id = 'view.' . $executable->storage->id() . '.' . $display_id;
+ $route_name = $view_route_names[$executable->storage->id() . '.' . $display_id];
+
+ // Don't add a local task for views which override existing routes.
+ // @todo Alternative it could just change the existing entry.
+ if ($route_name != $plugin_id) {
+ continue;
+ }
- $this->derivatives[$plugin_id] = array(
- 'route_name' => $route_name,
- 'weight' => $menu['weight'],
- 'title' => $menu['title'],
- ) + $base_plugin_definition;
+ $this->derivatives[$plugin_id] = array(
+ 'route_name' => $route_name,
+ 'weight' => $menu['weight'],
+ 'title' => $menu['title'],
+ ) + $base_plugin_definition;
- // Default local tasks have themselves as root tab.
- if ($menu['type'] == 'default tab') {
- $this->derivatives[$plugin_id]['base_route'] = $route_name;
+ // Default local tasks have themselves as root tab.
+ if ($type == 'default tab') {
+ $this->derivatives[$plugin_id]['base_route'] = $route_name;
+ }
}
}
}
@@ -108,29 +110,31 @@ public function alterLocalTasks(&$local_tasks) {
$menu = $executable->display_handler->getOption('menu');
// We already have set the base_route for default tabs.
- if (in_array($menu['type'], array('tab'))) {
- $plugin_id = 'view.' . $executable->storage->id() . '.' . $display_id;
- $view_route_name = $view_route_names[$executable->storage->id() . '.' . $display_id];
-
- // Don't add a local task for views which override existing routes.
- if ($view_route_name != $plugin_id) {
- unset($local_tasks[$plugin_id]);
- continue;
- }
+ foreach ($menu['type'] as $type) {
+ if (in_array($type, array('tab'))) {
+ $plugin_id = 'view.' . $executable->storage->id() . '.' . $display_id;
+ $view_route_name = $view_route_names[$executable->storage->id() . '.' . $display_id];
+
+ // Don't add a local task for views which override existing routes.
+ if ($view_route_name != $plugin_id) {
+ unset($local_tasks[$plugin_id]);
+ continue;
+ }
- // Find out the parent route.
- // @todo Find out how to find both the root and parent tab.
- $path = $executable->display_handler->getPath();
- $split = explode('/', $path);
- array_pop($split);
- $path = implode('/', $split);
-
- $pattern = '/' . str_replace('%', '{}', $path);
- if ($routes = $this->routeProvider->getRoutesByPattern($pattern)) {
- foreach ($routes->all() as $name => $route) {
- $local_tasks['views_view:' . $plugin_id]['base_route'] = $name;
- // Skip after the first found route.
- break;
+ // Find out the parent route.
+ // @todo Find out how to find both the root and parent tab.
+ $path = $executable->display_handler->getPath();
+ $split = explode('/', $path);
+ array_pop($split);
+ $path = implode('/', $split);
+
+ $pattern = '/' . str_replace('%', '{}', $path);
+ if ($routes = $this->routeProvider->getRoutesByPattern($pattern)) {
+ foreach ($routes->all() as $name => $route) {
+ $local_tasks['views_view:' . $plugin_id]['base_route'] = $name;
+ // Skip after the first found route.
+ break;
+ }
}
}
}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/Page.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/Page.php
index c0b6771..b147a62 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/Page.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/Page.php
@@ -44,7 +44,7 @@ protected function defineOptions() {
$options['menu'] = array(
'contains' => array(
- 'type' => array('default' => 'none'),
+ 'type' => array('default' => array()),
// Do not translate menu and title as menu system will.
'title' => array('default' => '', 'translatable' => FALSE),
'description' => array('default' => '', 'translatable' => FALSE),
@@ -114,23 +114,28 @@ public function optionsSummary(&$categories, &$options) {
parent::optionsSummary($categories, $options);
$menu = $this->getOption('menu');
- if (!is_array($menu)) {
- $menu = array('type' => 'none');
+
+ $menus = array();
+ foreach (array_filter($menu['type']) as $type) {
+ switch ($type) {
+ case 'none':
+ $menus[] = t('No menu');
+ break;
+ case 'normal':
+ $menus[] = t('Normal: @title', array('@title' => $menu['title']));
+ break;
+ case 'tab':
+ case 'default tab':
+ $menus[] = t('Tab: @title', array('@title' => $menu['title']));
+ break;
+ }
}
- switch ($menu['type']) {
- case 'none':
- default:
- $menu_str = t('No menu');
- break;
- case 'normal':
- $menu_str = t('Normal: @title', array('@title' => $menu['title']));
- break;
- case 'tab':
- case 'default tab':
- $menu_str = t('Tab: @title', array('@title' => $menu['title']));
- break;
+ if (empty($menus)) {
+ $menus[] = t('No menu');
}
+ $menu_str = implode(' | ', $menus);
+
$options['menu'] = array(
'category' => 'page',
'title' => t('Menu'),
@@ -139,7 +144,7 @@ public function optionsSummary(&$categories, &$options) {
// This adds a 'Settings' link to the style_options setting if the style
// has options.
- if ($menu['type'] == 'default tab') {
+ if (!empty($menu['type']['default tab'])) {
$options['menu']['setting'] = t('Parent menu item');
$options['menu']['links']['tab_options'] = t('Change settings for the parent menu');
}
@@ -159,15 +164,14 @@ public function buildOptionsForm(&$form, &$form_state) {
'#suffix' => '',
'#tree' => TRUE,
);
+
$menu = $this->getOption('menu');
- if (empty($menu)) {
- $menu = array('type' => 'none', 'title' => '', 'weight' => 0);
- }
$form['menu']['type'] = array(
'#prefix' => '
',
'#suffix' => '
',
'#title' => t('Type'),
- '#type' => 'radios',
+ '#type' => 'checkboxes',
+ '#multiple' => TRUE,
'#options' => array(
'none' => t('No menu entry'),
'normal' => t('Normal menu entry'),
@@ -382,11 +386,13 @@ public function validateOptionsForm(&$form, &$form_state) {
if ($form_state['section'] == 'menu') {
$path = $this->getOption('path');
- if ($form_state['values']['menu']['type'] == 'normal' && strpos($path, '%') !== FALSE) {
+ $types = array_filter($form_state['values']['menu']['type']);
+ form_set_value($form['menu']['type'], $types, $form_state);
+ if (in_array('normal', $types) && strpos($path, '%') !== FALSE) {
form_error($form['menu']['type'], $form_state, t('Views cannot create normal menu items for paths with a % in them.'));
}
- if ($form_state['values']['menu']['type'] == 'default tab' || $form_state['values']['menu']['type'] == 'tab') {
+ if (in_array('default tab', $types) || $types == 'tab') {
$bits = explode('/', $path);
$last = array_pop($bits);
if ($last == '%') {
@@ -394,7 +400,7 @@ public function validateOptionsForm(&$form, &$form_state) {
}
}
- if ($form_state['values']['menu']['type'] != 'none' && empty($form_state['values']['menu']['title'])) {
+ if (!in_array('none', $types) && empty($form_state['values']['menu']['title'])) {
form_error($form['menu']['title'], $form_state, t('Title is required for this menu type.'));
}
}
@@ -410,7 +416,7 @@ public function submitOptionsForm(&$form, &$form_state) {
case 'menu':
$this->setOption('menu', $form_state['values']['menu']);
// send ajax form to options page if we use it.
- if ($form_state['values']['menu']['type'] == 'default tab') {
+ if (!empty($form_state['values']['menu']['type']['default tab'])) {
$form_state['view']->addFormToStack('display', $this->display['id'], 'tab_options');
}
break;
@@ -427,13 +433,13 @@ public function validate() {
$errors = parent::validate();
$menu = $this->getOption('menu');
- if (!empty($menu['type']) && $menu['type'] != 'none' && empty($menu['title'])) {
+ if (!empty($menu['type']) && empty($menu['type']['none']) && empty($menu['title'])) {
$errors[] = t('Display @display is set to use a menu but the menu link text is not set.', array('@display' => $this->display['display_title']));
}
- if ($menu['type'] == 'default tab') {
+ if (!empty($menu['type']['default tab'])) {
$tab_options = $this->getOption('tab_options');
- if (!empty($tab_options['type']) && $tab_options['type'] != 'none' && empty($tab_options['title'])) {
+ if (!empty($tab_options['type']) && empty($menu['type']['none']) && empty($tab_options['title'])) {
$errors[] = t('Display @display is set to use a parent menu but the parent menu link text is not set.', array('@display' => $this->display['display_title']));
}
}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
index 1442c46..b65280b 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php
@@ -100,7 +100,7 @@ public function getPath() {
protected function isDefaultTabPath() {
$menu = $this->getOption('menu');
$tab_options = $this->getOption('tab_options');
- return $menu['type'] == 'default tab' && !empty($tab_options['type']) && $tab_options['type'] != 'none';
+ return !empty($menu['type']['default tab']) && !empty($tab_options['type']) && $tab_options['type'] != 'none';
}
/**
@@ -289,28 +289,29 @@ public function executeHookMenuLinkDefaults(array &$existing_links) {
$path = implode('/', $bits);
$menu_link_id = 'views.' . str_replace('/', '.', $path);
- if ($path) {
- $menu = $this->getOption('menu');
- if (!empty($menu['type']) && $menu['type'] == 'normal') {
- $links[$menu_link_id] = array();
- // Some views might override existing paths, so we have to set the route
- // name based upon the altering.
- $view_id_display = "{$this->view->storage->id()}.{$this->display['id']}";
- $links[$menu_link_id] = array(
- 'route_name' => isset($view_route_names[$view_id_display]) ? $view_route_names[$view_id_display] : "view.$view_id_display",
- // Identify URL embedded arguments and correlate them to a handler.
- 'load arguments' => array($this->view->storage->id(), $this->display['id'], '%index'),
- 'machine_name' => $menu_link_id,
- );
- $links[$menu_link_id]['title'] = $menu['title'];
- $links[$menu_link_id]['description'] = $menu['description'];
-
- if (isset($menu['weight'])) {
- $links[$menu_link_id]['weight'] = intval($menu['weight']);
+ if ($path && ($menu = $this->getOption('menu')) && !empty($menu['type'])) {
+ foreach ($menu['type'] as $type) {
+ if ($type == 'normal') {
+ $links[$menu_link_id] = array();
+ // Some views might override existing paths, so we have to set the route
+ // name based upon the altering.
+ $view_id_display = "{$this->view->storage->id()}.{$this->display['id']}";
+ $links[$menu_link_id] = array(
+ 'route_name' => isset($view_route_names[$view_id_display]) ? $view_route_names[$view_id_display] : "view.$view_id_display",
+ // Identify URL embedded arguments and correlate them to a handler.
+ 'load arguments' => array($this->view->storage->id(), $this->display['id'], '%index'),
+ 'machine_name' => $menu_link_id,
+ );
+ $links[$menu_link_id]['title'] = $menu['title'];
+ $links[$menu_link_id]['description'] = $menu['description'];
+
+ if (isset($menu['weight'])) {
+ $links[$menu_link_id]['weight'] = intval($menu['weight']);
+ }
+
+ // Insert item into the proper menu.
+ $links[$menu_link_id]['menu_name'] = $menu['name'];
}
-
- // Insert item into the proper menu.
- $links[$menu_link_id]['menu_name'] = $menu['name'];
}
}
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php
index 50e8c85..dfaff97 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/wizard/WizardPluginBase.php
@@ -1000,7 +1000,7 @@ protected function pageDisplayOptions(array $form, array &$form_state) {
// Generate the menu links settings if the user checked the link checkbox.
if (!empty($page['link'])) {
- $display_options['menu']['type'] = 'normal';
+ $display_options['menu']['type'] = array('normal' => 'normal');
$display_options['menu']['title'] = $page['link_properties']['title'];
$display_options['menu']['name'] = $page['link_properties']['menu_name'];
}
diff --git a/core/modules/views/tests/Drupal/views/Tests/Plugin/Derivative/ViewsLocalTaskTest.php b/core/modules/views/tests/Drupal/views/Tests/Plugin/Derivative/ViewsLocalTaskTest.php
index 2850b92..ae42999 100644
--- a/core/modules/views/tests/Drupal/views/Tests/Plugin/Derivative/ViewsLocalTaskTest.php
+++ b/core/modules/views/tests/Drupal/views/Tests/Plugin/Derivative/ViewsLocalTaskTest.php
@@ -87,7 +87,7 @@ public function testGetDerivativeDefinitionsWithoutLocalTask() {
$display_plugin->expects($this->once())
->method('getOption')
->with('menu')
- ->will($this->returnValue(array('type' => 'normal')));
+ ->will($this->returnValue(array('type' => array('normal' => 'normal'))));
$executable->display_handler = $display_plugin;
$result = array(array($executable, 'page_1'));
@@ -119,7 +119,7 @@ public function testGetDerivativeDefinitionsWithLocalTask() {
$display_plugin->expects($this->once())
->method('getOption')
->with('menu')
- ->will($this->returnValue(array('type' => 'tab', 'weight' => 12, 'title' => 'Example title')));
+ ->will($this->returnValue(array('type' => array('tab' => 'tab'), 'weight' => 12, 'title' => 'Example title')));
$executable->display_handler = $display_plugin;
$result = array(array($executable, 'page_1'));
@@ -164,7 +164,7 @@ public function testGetDerivativeDefinitionsWithOverrideRoute() {
$display_plugin->expects($this->once())
->method('getOption')
->with('menu')
- ->will($this->returnValue(array('type' => 'tab', 'weight' => 12)));
+ ->will($this->returnValue(array('type' => array('tab' => 'tab'), 'weight' => 12)));
$executable->display_handler = $display_plugin;
$result = array(array($executable, 'page_1'));
@@ -205,7 +205,7 @@ public function testGetDerivativeDefinitionsWithDefaultLocalTask() {
$display_plugin->expects($this->exactly(2))
->method('getOption')
->with('menu')
- ->will($this->returnValue(array('type' => 'default tab', 'weight' => 12, 'title' => 'Example title')));
+ ->will($this->returnValue(array('type' => array('default tab' => 'default tab'), 'weight' => 12, 'title' => 'Example title')));
$executable->display_handler = $display_plugin;
$result = array(array($executable, 'page_1'));
@@ -266,7 +266,7 @@ public function testGetDerivativeDefinitionsWithExistingLocalTask() {
$display_plugin->expects($this->exactly(2))
->method('getOption')
->with('menu')
- ->will($this->returnValue(array('type' => 'tab', 'weight' => 12, 'title' => 'Example title')));
+ ->will($this->returnValue(array('type' => array('tab' => 'tab'), 'weight' => 12, 'title' => 'Example title')));
$display_plugin->expects($this->once())
->method('getPath')
->will($this->returnValue('path/example'));
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_page_display_menu.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_page_display_menu.yml
index 1d1911b..892dbcf 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_page_display_menu.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_page_display_menu.yml
@@ -27,7 +27,8 @@ display:
path: test_page_display_menu/default
title: 'Test default page'
menu:
- type: 'default tab'
+ type:
+ 'default tab': 'default tab'
title: 'Test default tab'
description: ''
name: tools
@@ -50,7 +51,8 @@ display:
path: test_page_display_menu/local
title: 'Test local page'
menu:
- type: tab
+ type:
+ tab: tab
title: 'Test local tab'
description: ''
name: tools
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/Tests/DisplayPath.php b/core/modules/views_ui/lib/Drupal/views_ui/Tests/DisplayPath.php
index 8435589..cc8b340 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/Tests/DisplayPath.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/Tests/DisplayPath.php
@@ -68,7 +68,7 @@ public function testMenuOptions() {
$this->drupalPostForm('admin/structure/views/nojs/display/test_view/page_1/path', array('path' => $this->randomString()), t('Apply'));
$this->drupalGet('admin/structure/views/view/test_view');
- $this->drupalPostForm('admin/structure/views/nojs/display/test_view/page_1/menu', array('menu[type]' => 'default tab', 'menu[title]' => 'Test tab title'), t('Apply'));
+ $this->drupalPostForm('admin/structure/views/nojs/display/test_view/page_1/menu', array('menu[type][default tab]' => 'default tab', 'menu[title]' => 'Test tab title'), t('Apply'));
$this->assertResponse(200);
$this->assertUrl('admin/structure/views/nojs/display/test_view/page_1/tab_options');