Issue #2342287 by mikeker: Allow Twig in Views token replacement

8.0.x
Alex Pott 2015-01-12 15:27:51 +00:00
parent 29f441d3c2
commit 552c86ca35
12 changed files with 127 additions and 55 deletions

View File

@ -489,7 +489,7 @@ display:
alter_text: false alter_text: false
text: '' text: ''
make_link: true make_link: true
path: 'admin/content/files/usage/[fid]' path: 'admin/content/files/usage/{{fid}}'
absolute: false absolute: false
external: false external: false
replace_spaces: false replace_spaces: false

View File

@ -319,6 +319,57 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
return \Drupal::token()->replace($string, array('view' => $this->view), $options); return \Drupal::token()->replace($string, array('view' => $this->view), $options);
} }
/**
* Replaces Views' tokens in a given string. It is the responsibility of the
* calling function to ensure $text and $token replacements are sanitized.
*
* This used to be a simple strtr() scattered throughout the code. Some Views
* tokens, such as arguments (e.g.: %1 or !1), still use the old format so we
* handle those as well as the new Twig-based tokens (e.g.: {{ field_name }})
*
* @param $text
* String with possible tokens.
* @param $tokens
* Array of token => replacement_value items.
*
* @return String
*/
protected function viewsTokenReplace($text, $tokens) {
if (empty($tokens)) {
return $text;
}
// Separate Twig tokens from other tokens (e.g.: contextual filter tokens in
// the form of %1).
$twig_tokens = array();
$other_tokens = array();
foreach ($tokens as $token => $replacement) {
if (strpos($token, '{{') !== FALSE) {
// Twig wants a token replacement array stripped of curly-brackets.
$token = trim(str_replace(array('{', '}'), '', $token));
$twig_tokens[$token] = $replacement;
}
else {
$other_tokens[$token] = $replacement;
}
}
// Non-Twig tokens are a straight string replacement, Twig tokens get run
// through an inline template for rendering and replacement.
$text = strtr($text, $other_tokens);
if ($twig_tokens) {
$build = array(
'#type' => 'inline_template',
'#template' => $text,
'#context' => $twig_tokens,
);
return drupal_render($build);
}
else {
return $text;
}
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */

View File

@ -2136,7 +2136,7 @@ abstract class DisplayPluginBase extends PluginBase {
if ($this->getOption('link_display') == 'custom_url' && $override_path = $this->getOption('link_url')) { if ($this->getOption('link_display') == 'custom_url' && $override_path = $this->getOption('link_url')) {
$tokens = $this->getArgumentsTokens(); $tokens = $this->getArgumentsTokens();
$path = strtr($override_path, $tokens); $path = $this->viewsTokenReplace($override_path, $tokens);
} }
if ($path) { if ($path) {

View File

@ -895,7 +895,7 @@ class Field extends FieldPluginBase implements CacheablePluginInterface, MultiIt
protected function documentSelfTokens(&$tokens) { protected function documentSelfTokens(&$tokens) {
$field = $this->getFieldDefinition(); $field = $this->getFieldDefinition();
foreach ($field->getColumns() as $id => $column) { foreach ($field->getColumns() as $id => $column) {
$tokens['[' . $this->options['id'] . '-' . $id . ']'] = $this->t('Raw @column', array('@column' => $id)); $tokens['{{ ' . $this->options['id'] . '-' . $id . ' }}'] = $this->t('Raw @column', array('@column' => $id));
} }
} }
@ -913,11 +913,11 @@ class Field extends FieldPluginBase implements CacheablePluginInterface, MultiIt
(is_object($item['raw']) ? (array)$item['raw'] : NULL); (is_object($item['raw']) ? (array)$item['raw'] : NULL);
} }
if (isset($raw) && isset($raw[$id]) && is_scalar($raw[$id])) { if (isset($raw) && isset($raw[$id]) && is_scalar($raw[$id])) {
$tokens['[' . $this->options['id'] . '-' . $id . ']'] = Xss::filterAdmin($raw[$id]); $tokens['{{ ' . $this->options['id'] . '-' . $id . ' }}'] = Xss::filterAdmin($raw[$id]);
} }
else { else {
// Make sure that empty values are replaced as well. // Make sure that empty values are replaced as well.
$tokens['[' . $this->options['id'] . '-' . $id . ']'] = ''; $tokens['{{ ' . $this->options['id'] . '-' . $id . ' }}'] = '';
} }
} }
} }

View File

@ -322,7 +322,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
* {@inheritdoc} * {@inheritdoc}
*/ */
public function tokenizeValue($value, $row_index = NULL) { public function tokenizeValue($value, $row_index = NULL) {
if (strpos($value, '[') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) { if (strpos($value, '{{') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) {
$fake_item = array( $fake_item = array(
'alter_text' => TRUE, 'alter_text' => TRUE,
'text' => $value, 'text' => $value,
@ -705,7 +705,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
'#title' => $this->t('Text'), '#title' => $this->t('Text'),
'#type' => 'textarea', '#type' => 'textarea',
'#default_value' => $this->options['alter']['text'], '#default_value' => $this->options['alter']['text'],
'#description' => $this->t('The text to display for this field. You may include HTML. You may enter data from this view as per the "Replacement patterns" below.'), '#description' => $this->t('The text to display for this field. You may include HTML or Twig. You may enter data from this view as per the "Replacement patterns" below.'),
'#states' => array( '#states' => array(
'visible' => array( 'visible' => array(
':input[name="options[alter][alter_text]"]' => array('checked' => TRUE), ':input[name="options[alter][alter_text]"]' => array('checked' => TRUE),
@ -852,10 +852,10 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
// Setup the tokens for fields. // Setup the tokens for fields.
$previous = $this->getPreviousFieldLabels(); $previous = $this->getPreviousFieldLabels();
foreach ($previous as $id => $label) { foreach ($previous as $id => $label) {
$options[t('Fields')]["[$id]"] = substr(strrchr($label, ":"), 2 ); $options[t('Fields')]["{{ $id }}"] = substr(strrchr($label, ":"), 2 );
} }
// Add the field to the list of options. // Add the field to the list of options.
$options[t('Fields')]["[{$this->options['id']}]"] = substr(strrchr($this->adminLabel(), ":"), 2 ); $options[t('Fields')]["{{ {$this->options['id']} }}"] = substr(strrchr($this->adminLabel(), ":"), 2 );
$count = 0; // This lets us prepare the key as we want it printed. $count = 0; // This lets us prepare the key as we want it printed.
foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) { foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
@ -869,7 +869,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
$output = '<p>' . $this->t('You must add some additional fields to this display before using this field. These fields may be marked as <em>Exclude from display</em> if you prefer. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.') . '</p>'; $output = '<p>' . $this->t('You must add some additional fields to this display before using this field. These fields may be marked as <em>Exclude from display</em> if you prefer. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.') . '</p>';
// We have some options, so make a list. // We have some options, so make a list.
if (!empty($options)) { if (!empty($options)) {
$output = '<p>' . $this->t("The following tokens are available for this field. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields. If you would like to have the characters '[' and ']' use the html entity codes '%5B' or '%5D' or they will get replaced with empty space.") . '</p>'; $output = '<p>' . $this->t("The following Twig replacement tokens are available for this field. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.") . '</p>';
foreach (array_keys($options) as $type) { foreach (array_keys($options) as $type) {
if (!empty($options[$type])) { if (!empty($options[$type])) {
$items = array(); $items = array();
@ -1229,7 +1229,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
$more_link_text = $this->options['alter']['more_link_text'] ? $this->options['alter']['more_link_text'] : $this->t('more'); $more_link_text = $this->options['alter']['more_link_text'] ? $this->options['alter']['more_link_text'] : $this->t('more');
$more_link_text = strtr(Xss::filterAdmin($more_link_text), $tokens); $more_link_text = strtr(Xss::filterAdmin($more_link_text), $tokens);
$more_link_path = $this->options['alter']['more_link_path']; $more_link_path = $this->options['alter']['more_link_path'];
$more_link_path = strip_tags(String::decodeEntities(strtr($more_link_path, $tokens))); $more_link_path = strip_tags(String::decodeEntities($this->viewsTokenReplace($more_link_path, $tokens)));
// Make sure that paths which were run through _url() work as well. // Make sure that paths which were run through _url() work as well.
$base_path = base_path(); $base_path = base_path();
@ -1260,14 +1260,12 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
} }
/** /**
* Render this field as altered text, from a fieldset set by the user. * Render this field as user-defined altered text.
*/ */
protected function renderAltered($alter, $tokens) { protected function renderAltered($alter, $tokens) {
// Filter this right away as our substitutions are already sanitized. // Filter this right away as our substitutions are already sanitized.
$value = Xss::filterAdmin($alter['text']); $template = Xss::filterAdmin($alter['text']);
$value = strtr($value, $tokens); return $this->viewsTokenReplace($template, $tokens);
return $value;
} }
/** /**
@ -1290,7 +1288,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
$value = ''; $value = '';
if (!empty($alter['prefix'])) { if (!empty($alter['prefix'])) {
$value .= Xss::filterAdmin(strtr($alter['prefix'], $tokens)); $value .= Xss::filterAdmin($this->viewsTokenReplace($alter['prefix'], $tokens));
} }
$options = array( $options = array(
@ -1311,7 +1309,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
// Use strip tags as there should never be HTML in the path. // Use strip tags as there should never be HTML in the path.
// However, we need to preserve special characters like " that // However, we need to preserve special characters like " that
// were removed by String::checkPlain(). // were removed by String::checkPlain().
$path = strip_tags(String::decodeEntities(strtr($path, $tokens))); $path = strip_tags(String::decodeEntities($this->viewsTokenReplace($path, $tokens)));
if (!empty($alter['path_case']) && $alter['path_case'] != 'none') { if (!empty($alter['path_case']) && $alter['path_case'] != 'none') {
$path = $this->caseTransform($path, $this->options['alter']['path_case']); $path = $this->caseTransform($path, $this->options['alter']['path_case']);
@ -1380,22 +1378,22 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
$options['fragment'] = $url['fragment']; $options['fragment'] = $url['fragment'];
} }
$alt = strtr($alter['alt'], $tokens); $alt = $this->viewsTokenReplace($alter['alt'], $tokens);
// Set the title attribute of the link only if it improves accessibility // Set the title attribute of the link only if it improves accessibility
if ($alt && $alt != $text) { if ($alt && $alt != $text) {
$options['attributes']['title'] = String::decodeEntities($alt); $options['attributes']['title'] = String::decodeEntities($alt);
} }
$class = strtr($alter['link_class'], $tokens); $class = $this->viewsTokenReplace($alter['link_class'], $tokens);
if ($class) { if ($class) {
$options['attributes']['class'] = array($class); $options['attributes']['class'] = array($class);
} }
if (!empty($alter['rel']) && $rel = strtr($alter['rel'], $tokens)) { if (!empty($alter['rel']) && $rel = $this->viewsTokenReplace($alter['rel'], $tokens)) {
$options['attributes']['rel'] = $rel; $options['attributes']['rel'] = $rel;
} }
$target = String::checkPlain(trim(strtr($alter['target'], $tokens))); $target = String::checkPlain(trim($this->viewsTokenReplace($alter['target'], $tokens)));
if (!empty($target)) { if (!empty($target)) {
$options['attributes']['target'] = $target; $options['attributes']['target'] = $target;
} }
@ -1405,7 +1403,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
if (isset($alter['link_attributes']) && is_array($alter['link_attributes'])) { if (isset($alter['link_attributes']) && is_array($alter['link_attributes'])) {
foreach ($alter['link_attributes'] as $key => $attribute) { foreach ($alter['link_attributes'] as $key => $attribute) {
if (!isset($options['attributes'][$key])) { if (!isset($options['attributes'][$key])) {
$options['attributes'][$key] = strtr($attribute, $tokens); $options['attributes'][$key] = $this->viewsTokenReplace($attribute, $tokens);
} }
} }
} }
@ -1416,7 +1414,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
// Convert the query to a string, perform token replacement, and then // Convert the query to a string, perform token replacement, and then
// convert back to an array form for _l(). // convert back to an array form for _l().
$options['query'] = UrlHelper::buildQuery($alter['query']); $options['query'] = UrlHelper::buildQuery($alter['query']);
$options['query'] = strtr($options['query'], $tokens); $options['query'] = $this->viewsTokenReplace($options['query'], $tokens);
$query = array(); $query = array();
parse_str($options['query'], $query); parse_str($options['query'], $query);
$options['query'] = $query; $options['query'] = $query;
@ -1426,7 +1424,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
$options['alias'] = $alter['alias']; $options['alias'] = $alter['alias'];
} }
if (isset($alter['fragment'])) { if (isset($alter['fragment'])) {
$options['fragment'] = strtr($alter['fragment'], $tokens); $options['fragment'] = $this->viewsTokenReplace($alter['fragment'], $tokens);
} }
if (isset($alter['language'])) { if (isset($alter['language'])) {
$options['language'] = $alter['language']; $options['language'] = $alter['language'];
@ -1448,7 +1446,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
} }
if (!empty($alter['suffix'])) { if (!empty($alter['suffix'])) {
$value .= Xss::filterAdmin(strtr($alter['suffix'], $tokens)); $value .= Xss::filterAdmin($this->viewsTokenReplace($alter['suffix'], $tokens));
} }
return $value; return $value;
@ -1481,10 +1479,10 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
// Now add replacements for our fields. // Now add replacements for our fields.
foreach ($this->view->display_handler->getHandlers('field') as $field => $handler) { foreach ($this->view->display_handler->getHandlers('field') as $field => $handler) {
if (isset($handler->last_render)) { if (isset($handler->last_render)) {
$tokens["[$field]"] = $handler->last_render; $tokens["{{ $field }}"] = $handler->last_render;
} }
else { else {
$tokens["[$field]"] = ''; $tokens["{{ $field }}"] = '';
} }
// We only use fields up to (and including) this one. // We only use fields up to (and including) this one.
@ -1568,9 +1566,10 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
* fields as a list. For example, the field that displays all terms * fields as a list. For example, the field that displays all terms
* on a node might have tokens for the tid and the term. * on a node might have tokens for the tid and the term.
* *
* By convention, tokens should follow the format of [token-subtoken] * By convention, tokens should follow the format of {{ token-subtoken }}
* where token is the field ID and subtoken is the field. If the * where token is the field ID and subtoken is the field. If the
* field ID is terms, then the tokens might be [terms-tid] and [terms-name]. * field ID is terms, then the tokens might be {{ terms-tid }} and
* {{ terms-name }}.
*/ */
protected function addSelfTokens(&$tokens, $item) { } protected function addSelfTokens(&$tokens, $item) { }

View File

@ -82,7 +82,7 @@ abstract class Links extends FieldPluginBase {
} }
// Make sure that tokens are replaced for this paths as well. // Make sure that tokens are replaced for this paths as well.
$tokens = $this->getRenderTokens(array()); $tokens = $this->getRenderTokens(array());
$path = strip_tags(String::decodeEntities(strtr($path, $tokens))); $path = strip_tags(String::decodeEntities($this->viewsTokenReplace($path, $tokens)));
$links[$field] = array( $links[$field] = array(
'url' => $path ? UrlObject::fromUri('base://' . $path) : $url, 'url' => $path ? UrlObject::fromUri('base://' . $path) : $url,

View File

@ -191,7 +191,7 @@ abstract class StylePluginBase extends PluginBase {
public function usesTokens() { public function usesTokens() {
if ($this->usesRowClass()) { if ($this->usesRowClass()) {
$class = $this->options['row_class']; $class = $this->options['row_class'];
if (strpos($class, '[') !== FALSE || strpos($class, '!') !== FALSE || strpos($class, '%') !== FALSE) { if (strpos($class, '{{') !== FALSE || strpos($class, '!') !== FALSE || strpos($class, '%') !== FALSE) {
return TRUE; return TRUE;
} }
} }
@ -228,18 +228,15 @@ abstract class StylePluginBase extends PluginBase {
* Take a value and apply token replacement logic to it. * Take a value and apply token replacement logic to it.
*/ */
public function tokenizeValue($value, $row_index) { public function tokenizeValue($value, $row_index) {
if (strpos($value, '[') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) { if (strpos($value, '{{') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) {
// Row tokens might be empty, for example for node row style. // Row tokens might be empty, for example for node row style.
$tokens = isset($this->rowTokens[$row_index]) ? $this->rowTokens[$row_index] : array(); $tokens = isset($this->rowTokens[$row_index]) ? $this->rowTokens[$row_index] : array();
if (!empty($this->view->build_info['substitutions'])) { if (!empty($this->view->build_info['substitutions'])) {
$tokens += $this->view->build_info['substitutions']; $tokens += $this->view->build_info['substitutions'];
} }
if ($tokens) { $value = $this->viewsTokenReplace($value, $tokens);
$value = strtr($value, $tokens);
} }
}
return $value; return $value;
} }

View File

@ -164,13 +164,13 @@ class FieldUnitTest extends ViewUnitTestBase {
$row = $view->result[0]; $row = $view->result[0];
$name_field_0->options['alter']['alter_text'] = TRUE; $name_field_0->options['alter']['alter_text'] = TRUE;
$name_field_0->options['alter']['text'] = '[name]'; $name_field_0->options['alter']['text'] = '{{ name }}';
$name_field_1->options['alter']['alter_text'] = TRUE; $name_field_1->options['alter']['alter_text'] = TRUE;
$name_field_1->options['alter']['text'] = '[name_1] [name]'; $name_field_1->options['alter']['text'] = '{{ name_1 }} {{ name }}';
$name_field_2->options['alter']['alter_text'] = TRUE; $name_field_2->options['alter']['alter_text'] = TRUE;
$name_field_2->options['alter']['text'] = '[name_2] [name_1]'; $name_field_2->options['alter']['text'] = '{{ name_2 }} {{ name_1 }}';
foreach ($view->result as $row) { foreach ($view->result as $row) {
$expected_output_0 = $row->views_test_data_name; $expected_output_0 = $row->views_test_data_name;
@ -178,23 +178,48 @@ class FieldUnitTest extends ViewUnitTestBase {
$expected_output_2 = "$row->views_test_data_name $row->views_test_data_name $row->views_test_data_name"; $expected_output_2 = "$row->views_test_data_name $row->views_test_data_name $row->views_test_data_name";
$output = $name_field_0->advancedRender($row); $output = $name_field_0->advancedRender($row);
$this->assertEqual($output, $expected_output_0); $this->assertEqual($output, $expected_output_0, format_string('Test token replacement: "!token" gave "!output"', [
'!token' => $name_field_0->options['alter']['text'],
'!output' => $output,
]));
$output = $name_field_1->advancedRender($row); $output = $name_field_1->advancedRender($row);
$this->assertEqual($output, $expected_output_1); $this->assertEqual($output, $expected_output_1, format_string('Test token replacement: "!token" gave "!output"', [
'!token' => $name_field_1->options['alter']['text'],
'!output' => $output,
]));
$output = $name_field_2->advancedRender($row); $output = $name_field_2->advancedRender($row);
$this->assertEqual($output, $expected_output_2); $this->assertEqual($output, $expected_output_2, format_string('Test token replacement: "!token" gave "!output"', [
'!token' => $name_field_2->options['alter']['text'],
'!output' => $output,
]));
} }
$job_field = $view->field['job']; $job_field = $view->field['job'];
$job_field->options['alter']['alter_text'] = TRUE; $job_field->options['alter']['alter_text'] = TRUE;
$job_field->options['alter']['text'] = '[test-token]'; $job_field->options['alter']['text'] = '{{ job }}';
$random_text = $this->randomMachineName(); $random_text = $this->randomMachineName();
$job_field->setTestValue($random_text); $job_field->setTestValue($random_text);
$output = $job_field->advancedRender($row); $output = $job_field->advancedRender($row);
$this->assertSubString($output, $random_text, format_string('Make sure the self token (!value) appears in the output (!output)', array('!value' => $random_text, '!output' => $output))); $this->assertSubString($output, $random_text, format_string('Make sure the self token (!token => !value) appears in the output (!output)', [
'!value' => $random_text,
'!output' => $output,
'!token' => $job_field->options['alter']['text'],
]));
// Verify the token format used in D7 and earlier does not get substituted.
$old_token = '[job]';
$job_field->options['alter']['text'] = $old_token;
$random_text = $this->randomMachineName();
$job_field->setTestValue($random_text);
$output = $job_field->advancedRender($row);
$this->assertSubString($output, $old_token, format_string('Make sure the old token style (!token => !value) is not changed in the output (!output)', [
'!value' => $random_text,
'!output' => $output,
'!token' => $job_field->options['alter']['text'],
]));
} }
/** /**

View File

@ -226,7 +226,7 @@ class StyleTest extends ViewTestBase {
// Setup some random css class. // Setup some random css class.
$view->initStyle(); $view->initStyle();
$random_name = $this->randomMachineName(); $random_name = $this->randomMachineName();
$view->style_plugin->options['row_class'] = $random_name . " test-token-[name]"; $view->style_plugin->options['row_class'] = $random_name . " test-token-{{ name }}";
$output = $view->preview(); $output = $view->preview();
$this->storeViewPreview(drupal_render($output)); $this->storeViewPreview(drupal_render($output));

View File

@ -122,7 +122,7 @@ display:
alter_text: true alter_text: true
text: 'Custom Text' text: 'Custom Text'
make_link: true make_link: true
path: 'node/[nid]' path: 'node/{{nid}}'
absolute: false absolute: false
external: false external: false
replace_spaces: false replace_spaces: false

View File

@ -55,9 +55,9 @@ display:
automatic_width: true automatic_width: true
alignment: horizontal alignment: horizontal
col_class_default: true col_class_default: true
col_class_custom: 'name-[name]' col_class_custom: 'name-{{name}}'
row_class_default: true row_class_default: true
row_class_custom: 'age-[age]' row_class_custom: 'age-{{ age }}'
row: row:
type: fields type: fields
field_langcode: '***LANGUAGE_language_content***' field_langcode: '***LANGUAGE_language_content***'

View File

@ -43,20 +43,20 @@ class FieldUITest extends UITestBase {
$edit_handler_url = 'admin/structure/views/nojs/handler/test_view/default/field/age'; $edit_handler_url = 'admin/structure/views/nojs/handler/test_view/default/field/age';
$this->drupalGet($edit_handler_url); $this->drupalGet($edit_handler_url);
$result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/fields/li'); $result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/fields/li');
$this->assertEqual((string) $result[0], '[age] == Age'); $this->assertEqual((string) $result[0], '{{ age }} == Age');
$edit_handler_url = 'admin/structure/views/nojs/handler/test_view/default/field/id'; $edit_handler_url = 'admin/structure/views/nojs/handler/test_view/default/field/id';
$this->drupalGet($edit_handler_url); $this->drupalGet($edit_handler_url);
$result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/fields/li'); $result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/fields/li');
$this->assertEqual((string) $result[0], '[age] == Age'); $this->assertEqual((string) $result[0], '{{ age }} == Age');
$this->assertEqual((string) $result[1], '[id] == ID'); $this->assertEqual((string) $result[1], '{{ id }} == ID');
$edit_handler_url = 'admin/structure/views/nojs/handler/test_view/default/field/name'; $edit_handler_url = 'admin/structure/views/nojs/handler/test_view/default/field/name';
$this->drupalGet($edit_handler_url); $this->drupalGet($edit_handler_url);
$result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/fields/li'); $result = $this->xpath('//details[@id="edit-options-alter-help"]/div[@class="details-wrapper"]/div[@class="item-list"]/fields/li');
$this->assertEqual((string) $result[0], '[age] == Age'); $this->assertEqual((string) $result[0], '{{ age }} == Age');
$this->assertEqual((string) $result[1], '[id] == ID'); $this->assertEqual((string) $result[1], '{{ id }} == ID');
$this->assertEqual((string) $result[2], '[name] == Name'); $this->assertEqual((string) $result[2], '{{ name }} == Name');
} }
/** /**