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');