core/modules/contextual/contextual.module | 27 +++++++------ .../Drupal/contextual/Tests/ContextualUnitTest.php | 41 ++++++++++++++++---- .../lib/Drupal/views/Tests/UI/DisplayTest.php | 21 +++++++++- core/modules/views/views.module | 16 ++++---- core/modules/views/views_ui/views_ui.module | 4 +- 5 files changed, 80 insertions(+), 29 deletions(-) diff --git a/core/modules/contextual/contextual.module b/core/modules/contextual/contextual.module index 0b00e2e..d9a0461 100644 --- a/core/modules/contextual/contextual.module +++ b/core/modules/contextual/contextual.module @@ -239,12 +239,15 @@ function contextual_pre_render_links($element) { * Serializes #contextual_links property metadata to a "contextual id". * * Examples: - * - node[node]:1 - * - views_ui[admin/structure/views/view]:frontpage - * - menu[admin/structure/menu/manage]:tools|block[admin/structure/block/manage]:bartik.tools + * - node:node:1: + * - views_ui:admin/structure/views/view:frontpage:location=page&view_name=frontpage&view_display_id=page_1 + * - menu:admin/structure/menu/manage:tools:|block:admin/structure/block/manage:bartik.tools: * * So, expressed in a pattern: - * []:: + * ::: + * + * The (dynamic) path args are joined with slashes. The metadata is encoded as a + * query string * * @param array $contextual_links * The $element['#contextual_links'] value for some render element. @@ -255,10 +258,14 @@ function contextual_pre_render_links($element) { function _contextual_links_to_id($contextual_links) { $id = ''; foreach ($contextual_links as $module => $args) { + $parent_path = $args[0]; + $path_args = implode('/', $args[1]); + $metadata = drupal_http_build_query((isset($args[2])) ? $args[2] : array()); + if (drupal_strlen($id) > 0) { $id .= '|'; } - $id .= $module . '[' . $args[0] . ']:' . implode(':', $args[1]); + $id .= $module . ':' . $parent_path . ':' . $path_args . ':' . $metadata; } return $id; } @@ -280,12 +287,10 @@ function _contextual_id_to_links($id) { $contextual_links = array(); $contexts = explode('|', $id); foreach ($contexts as $context) { - $args = explode(':', $context); - $provider = array_shift($args); - $pos = strpos($provider, '['); - $module = drupal_substr($provider, 0, $pos); - $parent_path = drupal_substr($provider, $pos + 1, drupal_strlen($provider) - $pos - 2); - $contextual_links[$module] = array($parent_path, $args); + list($module, $parent_path, $path_args, $metadata_raw) = explode(':', $context); + $path_args = explode('/', $path_args); + $metadata = drupal_get_query_array($metadata_raw); + $contextual_links[$module] = array($parent_path, $path_args, $metadata); } return $contextual_links; } diff --git a/core/modules/contextual/lib/Drupal/contextual/Tests/ContextualUnitTest.php b/core/modules/contextual/lib/Drupal/contextual/Tests/ContextualUnitTest.php index 5c545dc..51e9a51 100644 --- a/core/modules/contextual/lib/Drupal/contextual/Tests/ContextualUnitTest.php +++ b/core/modules/contextual/lib/Drupal/contextual/Tests/ContextualUnitTest.php @@ -28,27 +28,49 @@ function _contextual_links_id_testcases() { // Test branch conditions: // - one module. // - one dynamic path argument. + // - no metadata. $tests[] = array( 'links' => array( 'node' => array( 'node', - array('14031991') + array('14031991'), + array() ), ), - 'id' => 'node[node]:14031991', + 'id' => 'node:node:14031991:', ); // Test branch conditions: // - one module. // - multiple dynamic path arguments. + // - no metadata. $tests[] = array( 'links' => array( 'foo' => array( 'baz/in/ga', - array('bar', 'baz', 'qux') + array('bar', 'baz', 'qux'), + array() ), ), - 'id' => 'foo[baz/in/ga]:bar:baz:qux', + 'id' => 'foo:baz/in/ga:bar/baz/qux:', + ); + + // Test branch conditions: + // - one module. + // - one dynamic path argument. + // - metadata. + $tests[] = array( + 'links' => array( + 'views_ui' => array( + 'admin/structure/views/view', + array('frontpage'), + array( + 'location' => 'page', + 'display' => 'page_1', + ) + ), + ), + 'id' => 'views_ui:admin/structure/views/view:frontpage:location=page&display=page_1', ); // Test branch conditions: @@ -58,18 +80,21 @@ function _contextual_links_id_testcases() { 'links' => array( 'node' => array( 'node', - array('14031991') + array('14031991'), + array() ), 'foo' => array( 'baz/in/ga', - array('bar', 'baz', 'qux') + array('bar', 'baz', 'qux'), + array() ), 'edge' => array( 'edge', - array('20011988') + array('20011988'), + array() ), ), - 'id' => 'node[node]:14031991|foo[baz/in/ga]:bar:baz:qux|edge[edge]:20011988', + 'id' => 'node:node:14031991:|foo:baz/in/ga:bar/baz/qux:|edge:edge:20011988:', ); return $tests; diff --git a/core/modules/views/lib/Drupal/views/Tests/UI/DisplayTest.php b/core/modules/views/lib/Drupal/views/Tests/UI/DisplayTest.php index 15cb97a..0398d30 100644 --- a/core/modules/views/lib/Drupal/views/Tests/UI/DisplayTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/UI/DisplayTest.php @@ -284,8 +284,27 @@ public function testPageContextualLinks() { $this->drupalLogin($this->drupalCreateUser(array('administer views', 'access contextual links'))); $view = entity_load('view', 'test_display'); $view->enable()->save(); + $this->drupalGet('test-display'); - $this->assertLinkByHref("admin/structure/views/view/{$view->id()}/edit/page_1"); + $id = 'views_ui:admin/structure/views/view:test_display:location=page&name=test_display&display_id=page_1'; + // @see \Drupal\contextual\Tests\ContextualDynamicContextTest:assertContextualLinkPlaceHolder() + $this->assertRaw('
', format_string('Contextual link placeholder with id @id exists.', array('@id' => $id))); + + // Get server-rendered contextual links. + // @see \Drupal\contextual\Tests\ContextualDynamicContextTest:renderContextualLinks() + $post = urlencode('ids[0]') . '=' . urlencode($id); + $response = $this->curlExec(array( + CURLOPT_URL => url('contextual/render', array('absolute' => TRUE, 'query' => array('destination' => 'test-display'))), + CURLOPT_POST => TRUE, + CURLOPT_POSTFIELDS => $post, + CURLOPT_HTTPHEADER => array( + 'Accept: application/json', + 'Content-Type: application/x-www-form-urlencoded', + ), + )); + $this->assertResponse(200); + $json = drupal_json_decode($response); + $this->assertIdentical($json[$id], ''); } } diff --git a/core/modules/views/views.module b/core/modules/views/views.module index 698f32e..5c86dd6 100644 --- a/core/modules/views/views.module +++ b/core/modules/views/views.module @@ -484,7 +484,7 @@ function views_preprocess_html(&$variables) { // page.tpl.php, so we can only find it using JavaScript. We therefore remove // the "contextual-region" class from the tag here and add // JavaScript that will insert it back in the correct place. - if (!empty($variables['page']['#views_contextual_links_info'])) { + if (!empty($variables['page']['#contextual_links']['views_ui'])) { $key = array_search('contextual-region', $variables['attributes']['class']->value()); if ($key !== FALSE) { unset($variables['attributes']['class'][$key]); @@ -605,12 +605,14 @@ function views_add_contextual_links(&$render_element, $location, ViewExecutable // If the link was valid, attach information about it to the renderable // array. if ($valid) { - $render_element['#contextual_links'][$module] = array($link['parent path'], $args); - $render_element['#views_contextual_links_info'][$module] = array( - 'location' => $location, - 'view' => $view, - 'view_name' => $view->storage->id(), - 'view_display_id' => $display_id, + $render_element['#contextual_links'][$module] = array( + $link['parent path'], + $args, + array( + 'location' => $location, + 'name' => $view->storage->id(), + 'display_id' => $display_id, + ) ); } } diff --git a/core/modules/views/views_ui/views_ui.module b/core/modules/views/views_ui/views_ui.module index 4c3ae95..d62eaa5 100644 --- a/core/modules/views/views_ui/views_ui.module +++ b/core/modules/views/views_ui/views_ui.module @@ -376,8 +376,8 @@ function views_ui_contextual_links_view_alter(&$element, $items) { // Append the display ID to the Views UI edit links, so that clicking on the // contextual link takes you directly to the correct display tab on the edit // screen. - elseif (!empty($element['#links']['views-ui-edit']) && !empty($element['#element']['#views_contextual_links_info']['views_ui']['view_display_id'])) { - $display_id = $element['#element']['#views_contextual_links_info']['views_ui']['view_display_id']; + elseif (!empty($element['#links']['views-ui-edit'])) { + $display_id = $element['#contextual_links']['views_ui'][2]['display_id']; $element['#links']['views-ui-edit']['href'] .= '/' . $display_id; } }