Issue #2492839 by joelpittet, mikeker, dawehner, lauriii, plach, Fabianx, olli: Views replacement token bc layer allows for Twig template injection via arguments
parent
b29148a70f
commit
9aec827586
|
|
@ -1019,7 +1019,7 @@ display:
|
||||||
title_enable: false
|
title_enable: false
|
||||||
title: All
|
title: All
|
||||||
title_enable: true
|
title_enable: true
|
||||||
title: 'File usage information for %1'
|
title: 'File usage information for {{ arguments.fid }}'
|
||||||
default_argument_type: fixed
|
default_argument_type: fixed
|
||||||
default_argument_options:
|
default_argument_options:
|
||||||
argument: ''
|
argument: ''
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ display:
|
||||||
exception:
|
exception:
|
||||||
title_enable: true
|
title_enable: true
|
||||||
title_enable: true
|
title_enable: true
|
||||||
title: '%1'
|
title: '{{ arguments.created_year_month }}'
|
||||||
default_argument_type: fixed
|
default_argument_type: fixed
|
||||||
summary:
|
summary:
|
||||||
sort_order: desc
|
sort_order: desc
|
||||||
|
|
@ -186,7 +186,7 @@ display:
|
||||||
exception:
|
exception:
|
||||||
title_enable: true
|
title_enable: true
|
||||||
title_enable: true
|
title_enable: true
|
||||||
title: '%1'
|
title: '{{ arguments.created_year_month }}'
|
||||||
default_argument_type: fixed
|
default_argument_type: fixed
|
||||||
summary:
|
summary:
|
||||||
format: default_summary
|
format: default_summary
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ display:
|
||||||
title_enable: false
|
title_enable: false
|
||||||
title: All
|
title: All
|
||||||
title_enable: true
|
title_enable: true
|
||||||
title: '%1'
|
title: '{{ arguments.tid }}'
|
||||||
default_argument_type: fixed
|
default_argument_type: fixed
|
||||||
default_argument_options:
|
default_argument_options:
|
||||||
argument: ''
|
argument: ''
|
||||||
|
|
@ -231,7 +231,7 @@ display:
|
||||||
admin_label: ''
|
admin_label: ''
|
||||||
empty: true
|
empty: true
|
||||||
tokenize: true
|
tokenize: true
|
||||||
target: '!1'
|
target: '{{ raw_arguments.tid }}'
|
||||||
view_mode: full
|
view_mode: full
|
||||||
bypass_access: false
|
bypass_access: false
|
||||||
plugin_id: entity
|
plugin_id: entity
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ display:
|
||||||
title_enable: false
|
title_enable: false
|
||||||
title: All
|
title: All
|
||||||
title_enable: true
|
title_enable: true
|
||||||
title: '%1'
|
title: '{{ arguments.roles_target_id }}'
|
||||||
default_argument_type: fixed
|
default_argument_type: fixed
|
||||||
default_argument_options:
|
default_argument_options:
|
||||||
argument: ''
|
argument: ''
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ display:
|
||||||
table: users_field_data
|
table: users_field_data
|
||||||
field: uid
|
field: uid
|
||||||
title_enable: true
|
title_enable: true
|
||||||
title: '%1'
|
title: '{{ arguments.uid }}'
|
||||||
plugin_id: user_uid
|
plugin_id: user_uid
|
||||||
entity_type: user
|
entity_type: user
|
||||||
entity_field: uid
|
entity_field: uid
|
||||||
|
|
|
||||||
|
|
@ -337,10 +337,6 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
||||||
* Replaces Views' tokens in a given string. The resulting string will be
|
* Replaces Views' tokens in a given string. The resulting string will be
|
||||||
* sanitized with Xss::filterAdmin.
|
* sanitized with Xss::filterAdmin.
|
||||||
*
|
*
|
||||||
* 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
|
* @param $text
|
||||||
* Unsanitized string with possible tokens.
|
* Unsanitized string with possible tokens.
|
||||||
* @param $tokens
|
* @param $tokens
|
||||||
|
|
@ -357,34 +353,44 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
||||||
return Xss::filterAdmin($text);
|
return Xss::filterAdmin($text);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Separate Twig tokens from other tokens (e.g.: contextual filter tokens in
|
|
||||||
// the form of %1).
|
|
||||||
$twig_tokens = array();
|
$twig_tokens = array();
|
||||||
$other_tokens = array();
|
|
||||||
foreach ($tokens as $token => $replacement) {
|
foreach ($tokens as $token => $replacement) {
|
||||||
|
// Twig wants a token replacement array stripped of curly-brackets.
|
||||||
|
// Some Views tokens come with curly-braces, others do not.
|
||||||
|
//@todo: https://www.drupal.org/node/2544392
|
||||||
if (strpos($token, '{{') !== FALSE) {
|
if (strpos($token, '{{') !== FALSE) {
|
||||||
// Twig wants a token replacement array stripped of curly-brackets.
|
// Twig wants a token replacement array stripped of curly-brackets.
|
||||||
$token = trim(str_replace(array('{', '}'), '', $token));
|
$token = trim(str_replace(['{{', '}}'], '', $token));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for arrays in Twig tokens. Internally these are passed as
|
||||||
|
// dot-delimited strings, but need to be turned into associative arrays
|
||||||
|
// for parsing.
|
||||||
|
if (strpos($token, '.') === FALSE) {
|
||||||
// We need to validate tokens are valid Twig variables. Twig uses the
|
// We need to validate tokens are valid Twig variables. Twig uses the
|
||||||
// same variable naming rules as PHP.
|
// same variable naming rules as PHP.
|
||||||
// @see http://php.net/manual/en/language.variables.basics.php
|
// @see http://php.net/manual/en/language.variables.basics.php
|
||||||
assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/\', $token) === 1', 'Tokens need to be valid Twig variables.');
|
assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/\', $token) === 1', 'Tokens need to be valid Twig variables.');
|
||||||
|
|
||||||
$twig_tokens[$token] = $replacement;
|
$twig_tokens[$token] = $replacement;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$other_tokens[$token] = $replacement;
|
$parts = explode('.', $token);
|
||||||
|
$top = array_shift($parts);
|
||||||
|
assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/\', $top) === 1', 'Tokens need to be valid Twig variables.');
|
||||||
|
$token_array = array(array_pop($parts) => $replacement);
|
||||||
|
foreach(array_reverse($parts) as $key) {
|
||||||
|
assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/\', $key) === 1', 'Tokens need to be valid Twig variables.');
|
||||||
|
$token_array = array($key => $token_array);
|
||||||
|
}
|
||||||
|
$twig_tokens[$top] = $token_array;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
if ($twig_tokens) {
|
||||||
// Use the unfiltered text for the Twig template, then filter the output.
|
// Use the unfiltered text for the Twig template, then filter the output.
|
||||||
// Otherwise, Xss::filterAdmin could remove valid Twig syntax before the
|
// Otherwise, Xss::filterAdmin could remove valid Twig syntax before the
|
||||||
// template is parsed.
|
// template is parsed.
|
||||||
|
|
||||||
$build = array(
|
$build = array(
|
||||||
'#type' => 'inline_template',
|
'#type' => 'inline_template',
|
||||||
'#template' => $text,
|
'#template' => $text,
|
||||||
|
|
@ -396,10 +402,14 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (string) $this->getRenderer()->render($build);
|
// Currently you cannot attach assets to tokens with
|
||||||
|
// Renderer::renderPlain(). This may be unnecessarily limiting. Consider
|
||||||
|
// using Renderer::executeInRenderContext() instead.
|
||||||
|
// @todo: https://www.drupal.org/node/2566621
|
||||||
|
return (string) $this->getRenderer()->renderPlain($build);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return $text;
|
return Xss::filterAdmin($text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ class Entity extends TokenizeAreaPluginBase {
|
||||||
// display the entity ID to the admin form user.
|
// display the entity ID to the admin form user.
|
||||||
// @todo Use a method to check for tokens in
|
// @todo Use a method to check for tokens in
|
||||||
// https://www.drupal.org/node/2396607.
|
// https://www.drupal.org/node/2396607.
|
||||||
if (strpos($this->options['target'], '{{') === FALSE && strpos($this->options['target'], '!') === FALSE && strpos($this->options['target'], '%') === FALSE && strpos($this->options['target'], '[') === FALSE) {
|
if (strpos($this->options['target'], '{{') === FALSE) {
|
||||||
// @todo If the entity does not exist, this will will show the config
|
// @todo If the entity does not exist, this will will show the config
|
||||||
// target identifier. Decide if this is the correct behavior in
|
// target identifier. Decide if this is the correct behavior in
|
||||||
// https://www.drupal.org/node/2415391.
|
// https://www.drupal.org/node/2415391.
|
||||||
|
|
@ -146,7 +146,7 @@ class Entity extends TokenizeAreaPluginBase {
|
||||||
// @todo Use a method to check for tokens in
|
// @todo Use a method to check for tokens in
|
||||||
// https://www.drupal.org/node/2396607.
|
// https://www.drupal.org/node/2396607.
|
||||||
$options = $form_state->getValue('options');
|
$options = $form_state->getValue('options');
|
||||||
if (strpos($options['target'], '{{') === FALSE && strpos($options['target'], '!') === FALSE && strpos($options['target'], '%') === FALSE && strpos($options['target'], '[') === FALSE) {
|
if (strpos($options['target'], '{{') === FALSE) {
|
||||||
if ($entity = $this->entityManager->getStorage($this->entityType)->load($options['target'])) {
|
if ($entity = $this->entityManager->getStorage($this->entityType)->load($options['target'])) {
|
||||||
$options['target'] = $entity->getConfigTarget();
|
$options['target'] = $entity->getConfigTarget();
|
||||||
}
|
}
|
||||||
|
|
@ -161,7 +161,7 @@ class Entity extends TokenizeAreaPluginBase {
|
||||||
if (!$empty || !empty($this->options['empty'])) {
|
if (!$empty || !empty($this->options['empty'])) {
|
||||||
// @todo Use a method to check for tokens in
|
// @todo Use a method to check for tokens in
|
||||||
// https://www.drupal.org/node/2396607.
|
// https://www.drupal.org/node/2396607.
|
||||||
if (strpos($this->options['target'], '{{') !== FALSE || strpos($this->options['target'], '!') !== FALSE || strpos($this->options['target'], '%') !== FALSE || strpos($this->options['target'], '[') !== FALSE) {
|
if (strpos($this->options['target'], '{{') !== FALSE) {
|
||||||
$target_id = $this->tokenizeValue($this->options['target']);
|
$target_id = $this->tokenizeValue($this->options['target']);
|
||||||
if ($entity = $this->entityManager->getStorage($this->entityType)->load($target_id)) {
|
if ($entity = $this->entityManager->getStorage($this->entityType)->load($target_id)) {
|
||||||
$target_entity = $entity;
|
$target_entity = $entity;
|
||||||
|
|
@ -190,7 +190,7 @@ class Entity extends TokenizeAreaPluginBase {
|
||||||
// Ensure that we don't add dependencies for placeholders.
|
// Ensure that we don't add dependencies for placeholders.
|
||||||
// @todo Use a method to check for tokens in
|
// @todo Use a method to check for tokens in
|
||||||
// https://www.drupal.org/node/2396607.
|
// https://www.drupal.org/node/2396607.
|
||||||
if (strpos($this->options['target'], '{{') === FALSE && strpos($this->options['target'], '!') === FALSE && strpos($this->options['target'], '%') === FALSE && strpos($this->options['target'], '[') === FALSE) {
|
if (strpos($this->options['target'], '{{') === FALSE) {
|
||||||
if ($entity = $this->entityManager->loadEntityByConfigTarget($this->entityType, $this->options['target'])) {
|
if ($entity = $this->entityManager->loadEntityByConfigTarget($this->entityType, $this->options['target'])) {
|
||||||
$dependencies[$this->entityManager->getDefinition($this->entityType)->getConfigDependencyKey()][] = $entity->getConfigDependencyName();
|
$dependencies[$this->entityManager->getDefinition($this->entityType)->getConfigDependencyKey()][] = $entity->getConfigDependencyName();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,13 +57,12 @@ abstract class TokenizeAreaPluginBase extends AreaPluginBase {
|
||||||
$optgroup_arguments = (string) t('Arguments');
|
$optgroup_arguments = (string) t('Arguments');
|
||||||
$optgroup_fields = (string) t('Fields');
|
$optgroup_fields = (string) t('Fields');
|
||||||
foreach ($this->view->display_handler->getHandlers('field') as $field => $handler) {
|
foreach ($this->view->display_handler->getHandlers('field') as $field => $handler) {
|
||||||
$options[$optgroup_fields]["[$field]"] = $handler->adminLabel();
|
$options[$optgroup_fields]["{{ $field }}"] = $handler->adminLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
$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 $handler) {
|
$options[$optgroup_arguments]["{{ arguments.$arg }}"] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
||||||
$options[$optgroup_arguments]['%' . ++$count] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
$options[$optgroup_arguments]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
||||||
$options[$optgroup_arguments]['!' . $count] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($options)) {
|
if (!empty($options)) {
|
||||||
|
|
@ -79,7 +78,7 @@ abstract class TokenizeAreaPluginBase extends AreaPluginBase {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
$form['tokens']['help'] = array(
|
$form['tokens']['help'] = array(
|
||||||
'#markup' => '<p>' . $this->t('The following tokens are available. 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>',
|
'#markup' => '<p>' . $this->t('The following tokens are available. You may use Twig syntax in this field.') . '</p>',
|
||||||
);
|
);
|
||||||
foreach (array_keys($options) as $type) {
|
foreach (array_keys($options) as $type) {
|
||||||
if (!empty($options[$type])) {
|
if (!empty($options[$type])) {
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheablePlugin
|
||||||
'#title_display' => 'invisible',
|
'#title_display' => 'invisible',
|
||||||
'#size' => 20,
|
'#size' => 20,
|
||||||
'#default_value' => $this->options['exception']['title'],
|
'#default_value' => $this->options['exception']['title'],
|
||||||
'#description' => $this->t('Override the view and other argument titles. Use "%1" for the first argument, "%2" for the second, etc.'),
|
'#description' => $this->t('Override the view and other argument titles. You may use Twig syntax in this field as well as the "arguments" and "raw_arguments" arrays.'),
|
||||||
'#states' => array(
|
'#states' => array(
|
||||||
'visible' => array(
|
'visible' => array(
|
||||||
':input[name="options[exception][title_enable]"]' => array('checked' => TRUE),
|
':input[name="options[exception][title_enable]"]' => array('checked' => TRUE),
|
||||||
|
|
@ -249,7 +249,7 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheablePlugin
|
||||||
'#title' => $this->t('Provide title'),
|
'#title' => $this->t('Provide title'),
|
||||||
'#title_display' => 'invisible',
|
'#title_display' => 'invisible',
|
||||||
'#default_value' => $this->options['title'],
|
'#default_value' => $this->options['title'],
|
||||||
'#description' => $this->t('Override the view and other argument titles. Use "%1" for the first argument, "%2" for the second, etc.'),
|
'#description' => $this->t('Override the view and other argument titles. You may use Twig syntax in this field.'),
|
||||||
'#states' => array(
|
'#states' => array(
|
||||||
'visible' => array(
|
'visible' => array(
|
||||||
':input[name="options[title_enable]"]' => array('checked' => TRUE),
|
':input[name="options[title_enable]"]' => array('checked' => TRUE),
|
||||||
|
|
@ -258,6 +258,23 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheablePlugin
|
||||||
'#fieldset' => 'argument_present',
|
'#fieldset' => 'argument_present',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$output = $this->getTokenHelp();
|
||||||
|
$form['token_help'] = [
|
||||||
|
'#type' => 'details',
|
||||||
|
'#title' => $this->t('Replacement patterns'),
|
||||||
|
'#value' => $output,
|
||||||
|
'#states' => [
|
||||||
|
'visible' => [
|
||||||
|
[
|
||||||
|
':input[name="options[title_enable]"]' => ['checked' => TRUE],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
':input[name="options[exception][title_enable]"]' => ['checked' => TRUE],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
$form['specify_validation'] = array(
|
$form['specify_validation'] = array(
|
||||||
'#type' => 'checkbox',
|
'#type' => 'checkbox',
|
||||||
'#title' => $this->t('Specify validation criteria'),
|
'#title' => $this->t('Specify validation criteria'),
|
||||||
|
|
@ -348,6 +365,45 @@ abstract class ArgumentPluginBase extends HandlerBase implements CacheablePlugin
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide token help information for the argument.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* A render array.
|
||||||
|
*/
|
||||||
|
protected function getTokenHelp() {
|
||||||
|
$output = [];
|
||||||
|
|
||||||
|
foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
|
||||||
|
/** @var \Drupal\views\Plugin\views\argument\ArgumentPluginBase $handler */
|
||||||
|
$options[(string) t('Arguments')]["{{ arguments.$arg }}"] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
||||||
|
$options[(string) t('Arguments')]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have some options, so make a list.
|
||||||
|
if (!empty($options)) {
|
||||||
|
$output[] = [
|
||||||
|
'#markup' => '<p>' . $this->t("The following replacement tokens are available for this argument.") . '</p>',
|
||||||
|
];
|
||||||
|
foreach (array_keys($options) as $type) {
|
||||||
|
if (!empty($options[$type])) {
|
||||||
|
$items = array();
|
||||||
|
foreach ($options[$type] as $key => $value) {
|
||||||
|
$items[] = $key . ' == ' . $value;
|
||||||
|
}
|
||||||
|
$item_list = array(
|
||||||
|
'#theme' => 'item_list',
|
||||||
|
'#items' => $items,
|
||||||
|
);
|
||||||
|
$output[] = $item_list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function validateOptionsForm(&$form, FormStateInterface $form_state) {
|
public function validateOptionsForm(&$form, FormStateInterface $form_state) {
|
||||||
$option_values = &$form_state->getValue('options');
|
$option_values = &$form_state->getValue('options');
|
||||||
if (empty($option_values)) {
|
if (empty($option_values)) {
|
||||||
|
|
|
||||||
|
|
@ -1725,21 +1725,27 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
||||||
);
|
);
|
||||||
|
|
||||||
$options = array();
|
$options = array();
|
||||||
$count = 0; // This lets us prepare the key as we want it printed.
|
|
||||||
// We cast the optgroup label to string as array keys must not be
|
// We cast the optgroup label to string as array keys must not be
|
||||||
// objects and t() may return a TranslationWrapper once issue #2557113
|
// objects and t() may return a TranslationWrapper once issue #2557113
|
||||||
// lands.
|
// lands.
|
||||||
$optgroup_arguments = (string) t('Arguments');
|
$optgroup_arguments = (string) t('Arguments');
|
||||||
foreach ($this->view->display_handler->getHandlers('argument') as $handler) {
|
foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
|
||||||
$options[$optgroup_arguments]['%' . ++$count] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
$options[$optgroup_arguments]["{{ arguments.$arg }}"] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
||||||
$options[$optgroup_arguments]['!' . $count] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
$options[$optgroup_arguments]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default text.
|
// Default text.
|
||||||
// We have some options, so make a list.
|
// We have some options, so make a list.
|
||||||
$output = '';
|
$description = [];
|
||||||
|
$description[] = [
|
||||||
|
'#markup' => $this->t('A Drupal path or external URL the more link will point to. Note that this will override the link display setting above.'),
|
||||||
|
];
|
||||||
if (!empty($options)) {
|
if (!empty($options)) {
|
||||||
$output = $this->t('<p>The following tokens are available for this link.</p>');
|
$description[] = [
|
||||||
|
'#prefix' => '<p>',
|
||||||
|
'#markup' => $this->t('The following tokens are available for this link. You may use Twig syntax in this field.'),
|
||||||
|
'#suffix' => '</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();
|
||||||
|
|
@ -1749,9 +1755,8 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
||||||
$item_list = array(
|
$item_list = array(
|
||||||
'#theme' => 'item_list',
|
'#theme' => 'item_list',
|
||||||
'#items' => $items,
|
'#items' => $items,
|
||||||
'#list_type' => $type,
|
|
||||||
);
|
);
|
||||||
$output .= drupal_render($item_list);
|
$description[] = $item_list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1760,7 +1765,7 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
||||||
'#type' => 'textfield',
|
'#type' => 'textfield',
|
||||||
'#title' => $this->t('Custom URL'),
|
'#title' => $this->t('Custom URL'),
|
||||||
'#default_value' => $this->getOption('link_url'),
|
'#default_value' => $this->getOption('link_url'),
|
||||||
'#description' => $this->t('A Drupal path or external URL the more link will point to. Note that this will override the link display setting above.') . $output,
|
'#description' => $description,
|
||||||
'#states' => array(
|
'#states' => array(
|
||||||
'visible' => array(
|
'visible' => array(
|
||||||
':input[name="link_display"]' => array('value' => 'custom_url'),
|
':input[name="link_display"]' => array('value' => 'custom_url'),
|
||||||
|
|
|
||||||
|
|
@ -333,7 +333,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) {
|
||||||
$fake_item = array(
|
$fake_item = array(
|
||||||
'alter_text' => TRUE,
|
'alter_text' => TRUE,
|
||||||
'text' => $value,
|
'text' => $value,
|
||||||
|
|
@ -872,10 +872,9 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
||||||
// Add the field to the list of options.
|
// Add the field to the list of options.
|
||||||
$options[$optgroup_fields]["{{ {$this->options['id']} }}"] = substr(strrchr($this->adminLabel(), ":"), 2 );
|
$options[$optgroup_fields]["{{ {$this->options['id']} }}"] = substr(strrchr($this->adminLabel(), ":"), 2 );
|
||||||
|
|
||||||
$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) {
|
||||||
$options[$optgroup_arguments]['%' . ++$count] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
$options[$optgroup_arguments]["{{ arguments.$arg }}"] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
||||||
$options[$optgroup_arguments]['!' . $count] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
$options[$optgroup_arguments]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', array('@argument' => $handler->adminLabel()));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->documentSelfTokens($options[$optgroup_fields]);
|
$this->documentSelfTokens($options[$optgroup_fields]);
|
||||||
|
|
@ -900,7 +899,6 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
||||||
$item_list = array(
|
$item_list = array(
|
||||||
'#theme' => 'item_list',
|
'#theme' => 'item_list',
|
||||||
'#items' => $items,
|
'#items' => $items,
|
||||||
'#list_type' => $type,
|
|
||||||
);
|
);
|
||||||
$output[] = $item_list;
|
$output[] = $item_list;
|
||||||
}
|
}
|
||||||
|
|
@ -1561,7 +1559,7 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
||||||
}
|
}
|
||||||
$count = 0;
|
$count = 0;
|
||||||
foreach ($this->displayHandler->getHandlers('argument') as $arg => $handler) {
|
foreach ($this->displayHandler->getHandlers('argument') as $arg => $handler) {
|
||||||
$token = '%' . ++$count;
|
$token = "{{ arguments.$arg }}";
|
||||||
if (!isset($tokens[$token])) {
|
if (!isset($tokens[$token])) {
|
||||||
$tokens[$token] = '';
|
$tokens[$token] = '';
|
||||||
}
|
}
|
||||||
|
|
@ -1569,7 +1567,8 @@ 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 SafeMarkup::checkPlain().
|
// were removed by SafeMarkup::checkPlain().
|
||||||
$tokens['!' . $count] = isset($this->view->args[$count - 1]) ? strip_tags(Html::decodeEntities($this->view->args[$count - 1])) : '';
|
$tokens["{{ raw_arguments.$arg }}"] = isset($this->view->args[$count]) ? strip_tags(Html::decodeEntities($this->view->args[$count])) : '';
|
||||||
|
$count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get flattened set of tokens for any array depth in query parameters.
|
// Get flattened set of tokens for any array depth in query parameters.
|
||||||
|
|
@ -1665,8 +1664,8 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Create a token key based on array element structure.
|
// Create a token key based on array element structure.
|
||||||
$token_string = !empty($parent_keys) ? implode('_', $parent_keys) . '_' . $param : $param;
|
$token_string = !empty($parent_keys) ? implode('.', $parent_keys) . '.' . $param : $param;
|
||||||
$tokens['%' . $token_string] = strip_tags(Html::decodeEntities($val));
|
$tokens['{{ arguments.' . $token_string . ' }}'] = strip_tags(Html::decodeEntities($val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,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) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -231,7 +231,7 @@ 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) {
|
||||||
// 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'])) {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ class FieldKernelTest extends ViewKernelTestBase {
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public static $testViews = array('test_view', 'test_field_tokens', 'test_field_output');
|
public static $testViews = array('test_view', 'test_field_tokens', 'test_field_argument_tokens', 'test_field_output');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map column names.
|
* Map column names.
|
||||||
|
|
@ -173,6 +173,44 @@ class FieldKernelTest extends ViewKernelTestBase {
|
||||||
$this->assertSubString($output, $random_text);
|
$this->assertSubString($output, $random_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the arguments tokens on field level.
|
||||||
|
*/
|
||||||
|
public function testArgumentTokens() {
|
||||||
|
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||||
|
$renderer = \Drupal::service('renderer');
|
||||||
|
|
||||||
|
$view = Views::getView('test_field_argument_tokens');
|
||||||
|
$this->executeView($view, ['{{ { "#pre_render": ["views_test_data_test_pre_render_function"]} }}']);
|
||||||
|
|
||||||
|
$name_field_0 = $view->field['name'];
|
||||||
|
|
||||||
|
// Test the old style tokens.
|
||||||
|
$name_field_0->options['alter']['alter_text'] = TRUE;
|
||||||
|
$name_field_0->options['alter']['text'] = '%1 !1';
|
||||||
|
|
||||||
|
$row = $view->result[0];
|
||||||
|
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_0, $row) {
|
||||||
|
return $name_field_0->advancedRender($row);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertFalse(strpos((string) $output, 'views_test_data_test_pre_render_function executed') !== FALSE, 'Ensure that the pre_render function was not executed');
|
||||||
|
$this->assertEqual('%1 !1', (string) $output, "Ensure that old style placeholders aren't replaced");
|
||||||
|
|
||||||
|
// This time use new style tokens but ensure that we still don't allow
|
||||||
|
// arbitrary code execution.
|
||||||
|
$name_field_0->options['alter']['alter_text'] = TRUE;
|
||||||
|
$name_field_0->options['alter']['text'] = '{{ arguments.null }} {{ raw_arguments.null }}';
|
||||||
|
|
||||||
|
$row = $view->result[0];
|
||||||
|
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_0, $row) {
|
||||||
|
return $name_field_0->advancedRender($row);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertFalse(strpos((string) $output, 'views_test_data_test_pre_render_function executed') !== FALSE, 'Ensure that the pre_render function was not executed');
|
||||||
|
$this->assertEqual('{{ { "#pre_render": ["views_test_data_test_pre_render_function"]} }} {{ { "#pre_render": ["views_test_data_test_pre_render_function"]} }}', (string) $output, 'Ensure that new style placeholders are replaced');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the field tokens, row level and field level.
|
* Tests the field tokens, row level and field level.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,16 @@ class PluginBaseTest extends KernelTestBase {
|
||||||
$this->assertIdentical($result, 'en means English');
|
$this->assertIdentical($result, 'en means English');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests viewsTokenReplace without any twig tokens.
|
||||||
|
*/
|
||||||
|
public function testViewsTokenReplaceWithTwigTokens() {
|
||||||
|
$text = 'Just some text';
|
||||||
|
$tokens = [];
|
||||||
|
$result = $this->testPluginBase->viewsTokenReplace($text, $tokens);
|
||||||
|
$this->assertIdentical($result, 'Just some text');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains \Drupal\views\Tests\Update\ArgumentPlaceholderUpdatePathTest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\views\Tests\Update;
|
||||||
|
|
||||||
|
use Drupal\system\Tests\Update\UpdatePathTestBase;
|
||||||
|
use Drupal\views\Entity\View;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the argument placeholder update path.
|
||||||
|
*
|
||||||
|
* @see views_update_8002()
|
||||||
|
*
|
||||||
|
* @group views
|
||||||
|
*/
|
||||||
|
class ArgumentPlaceholderUpdatePathTest extends UpdatePathTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function setDatabaseDumpFiles() {
|
||||||
|
$this->databaseDumpFiles = [
|
||||||
|
__DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
|
||||||
|
__DIR__ . '/../../../tests/fixtures/update/argument-placeholder.php'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that %1 and !1 are converted to twig tokens in existing views.
|
||||||
|
*/
|
||||||
|
public function testArgumentPlaceholderUpdate() {
|
||||||
|
$this->runUpdates();
|
||||||
|
$view = View::load('test_token_view');
|
||||||
|
|
||||||
|
$data = $view->toArray();
|
||||||
|
$this->assertEqual('{{ arguments.nid }}-test-class-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['style']['options']['col_class_custom']);
|
||||||
|
$this->assertEqual('{{ arguments.nid }}-test-class-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['style']['options']['row_class_custom']);
|
||||||
|
$this->assertEqual('{{ arguments.nid }}-description-{{ raw_arguments.nid }}', $data['display']['feed_1']['display_options']['style']['options']['description']);
|
||||||
|
$this->assertEqual('{{ arguments.nid }}-custom-text-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['fields']['title']['alter']['text']);
|
||||||
|
$this->assertEqual('test_token_view {{ arguments.nid }} {{ raw_arguments.nid }}', $data['display']['default']['display_options']['title']);
|
||||||
|
$this->assertEqual('{{ arguments.nid }}-custom-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['header']['area_text_custom']['content']);
|
||||||
|
$this->assertEqual('{{ arguments.nid }}-text-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['footer']['area']['content']['value']);
|
||||||
|
$this->assertEqual("Displaying @start - @end of @total\n\n{{ arguments.nid }}-result-{{ raw_arguments.nid }}", $data['display']['default']['display_options']['empty']['result']['content']);
|
||||||
|
$this->assertEqual('{{ arguments.nid }}-title-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['empty']['title']['title']);
|
||||||
|
$this->assertEqual('{{ arguments.nid }}-entity-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['empty']['entity_node']['target']);
|
||||||
|
$this->assertEqual('{{ arguments.nid }} title {{ raw_arguments.nid }}', $data['display']['default']['display_options']['arguments']['nid']['title']);
|
||||||
|
$this->assertEqual('{{ arguments.nid }} exception-title {{ raw_arguments.nid }}', $data['display']['default']['display_options']['arguments']['nid']['exception']['title']);
|
||||||
|
$this->assertEqual('{{ arguments.nid }}-more-text-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['use_more_text']);
|
||||||
|
$this->assertEqual('{{ arguments.nid }}-custom-url-{{ raw_arguments.nid }}', $data['display']['default']['display_options']['link_url']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1028,8 +1028,8 @@ class ViewExecutable implements \Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add this argument's substitution
|
// Add this argument's substitution
|
||||||
$substitutions['%' . ($position + 1)] = $arg_title;
|
$substitutions["{{ arguments.$id }}"] = $arg_title;
|
||||||
$substitutions['!' . ($position + 1)] = strip_tags(Html::decodeEntities($arg));
|
$substitutions["{{ raw_arguments.$id }}"] = strip_tags(Html::decodeEntities($arg));
|
||||||
|
|
||||||
// Test to see if we should use this argument's title
|
// Test to see if we should use this argument's title
|
||||||
if (!empty($argument->options['title_enable']) && !empty($argument->options['title'])) {
|
if (!empty($argument->options['title_enable']) && !empty($argument->options['title'])) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$connection = Drupal\Core\Database\Database::getConnection();
|
||||||
|
|
||||||
|
$connection->insert('config')
|
||||||
|
->fields(array(
|
||||||
|
'collection' => '',
|
||||||
|
'name' => 'views.view.test_token_view',
|
||||||
|
'data' => serialize(\Drupal\Component\Serialization\Yaml::decode(file_get_contents('core/modules/views/tests/modules/views_test_config/test_views/views.view.test_token_view.yml'))),
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
|
@ -174,7 +174,7 @@ display:
|
||||||
title_enable: false
|
title_enable: false
|
||||||
title: All
|
title: All
|
||||||
title_enable: true
|
title_enable: true
|
||||||
title: '%1'
|
title: '{{ arguments.tid }}'
|
||||||
default_argument_type: fixed
|
default_argument_type: fixed
|
||||||
default_argument_options:
|
default_argument_options:
|
||||||
argument: ''
|
argument: ''
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ display:
|
||||||
field: entity_entity_test
|
field: entity_entity_test
|
||||||
id: entity_entity_test
|
id: entity_entity_test
|
||||||
table: views
|
table: views
|
||||||
target: '!1'
|
target: '{{ raw_arguments.id }}'
|
||||||
view_mode: full
|
view_mode: full
|
||||||
plugin_id: entity
|
plugin_id: entity
|
||||||
entity_block:
|
entity_block:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
langcode: en
|
||||||
|
status: true
|
||||||
|
dependencies: { }
|
||||||
|
id: test_field_argument_tokens
|
||||||
|
label: null
|
||||||
|
module: views
|
||||||
|
description: ''
|
||||||
|
tag: ''
|
||||||
|
base_table: views_test_data
|
||||||
|
base_field: id
|
||||||
|
core: '8'
|
||||||
|
display:
|
||||||
|
default:
|
||||||
|
display_options:
|
||||||
|
access:
|
||||||
|
type: none
|
||||||
|
cache:
|
||||||
|
type: tag
|
||||||
|
exposed_form:
|
||||||
|
type: basic
|
||||||
|
pager:
|
||||||
|
type: full
|
||||||
|
query:
|
||||||
|
type: views_query
|
||||||
|
fields:
|
||||||
|
name:
|
||||||
|
id: name
|
||||||
|
table: views_test_data
|
||||||
|
field: name
|
||||||
|
plugin_id: string
|
||||||
|
name_1:
|
||||||
|
id: name_1
|
||||||
|
table: views_test_data
|
||||||
|
field: name
|
||||||
|
plugin_id: string
|
||||||
|
name_2:
|
||||||
|
id: name_2
|
||||||
|
table: views_test_data
|
||||||
|
field: name
|
||||||
|
plugin_id: string
|
||||||
|
job:
|
||||||
|
id: job
|
||||||
|
table: views_test_data
|
||||||
|
field: job
|
||||||
|
plugin_id: string
|
||||||
|
arguments:
|
||||||
|
'null':
|
||||||
|
id: 'null'
|
||||||
|
table: views
|
||||||
|
field: 'null'
|
||||||
|
plugin_id: 'null'
|
||||||
|
style:
|
||||||
|
type: default
|
||||||
|
row:
|
||||||
|
type: fields
|
||||||
|
display_plugin: default
|
||||||
|
display_title: Defaults
|
||||||
|
id: default
|
||||||
|
position: 0
|
||||||
|
|
@ -0,0 +1,349 @@
|
||||||
|
langcode: en
|
||||||
|
status: true
|
||||||
|
dependencies:
|
||||||
|
module:
|
||||||
|
- node
|
||||||
|
- user
|
||||||
|
id: test_token_view
|
||||||
|
label: test_token_view
|
||||||
|
module: views
|
||||||
|
description: ''
|
||||||
|
tag: ''
|
||||||
|
base_table: node_field_data
|
||||||
|
base_field: nid
|
||||||
|
core: 8.x
|
||||||
|
display:
|
||||||
|
default:
|
||||||
|
display_plugin: default
|
||||||
|
id: default
|
||||||
|
display_title: Master
|
||||||
|
position: 0
|
||||||
|
display_options:
|
||||||
|
access:
|
||||||
|
type: perm
|
||||||
|
options:
|
||||||
|
perm: 'access content'
|
||||||
|
cache:
|
||||||
|
type: tag
|
||||||
|
options: { }
|
||||||
|
query:
|
||||||
|
type: views_query
|
||||||
|
options:
|
||||||
|
disable_sql_rewrite: false
|
||||||
|
distinct: false
|
||||||
|
replica: false
|
||||||
|
query_comment: ''
|
||||||
|
query_tags: { }
|
||||||
|
exposed_form:
|
||||||
|
type: basic
|
||||||
|
options:
|
||||||
|
submit_button: Apply
|
||||||
|
reset_button: false
|
||||||
|
reset_button_label: Reset
|
||||||
|
exposed_sorts_label: 'Sort by'
|
||||||
|
expose_sort_order: true
|
||||||
|
sort_asc_label: Asc
|
||||||
|
sort_desc_label: Desc
|
||||||
|
pager:
|
||||||
|
type: full
|
||||||
|
options:
|
||||||
|
items_per_page: 10
|
||||||
|
offset: 0
|
||||||
|
id: 0
|
||||||
|
total_pages: null
|
||||||
|
expose:
|
||||||
|
items_per_page: false
|
||||||
|
items_per_page_label: 'Items per page'
|
||||||
|
items_per_page_options: '5, 10, 25, 50'
|
||||||
|
items_per_page_options_all: false
|
||||||
|
items_per_page_options_all_label: '- All -'
|
||||||
|
offset: false
|
||||||
|
offset_label: Offset
|
||||||
|
tags:
|
||||||
|
previous: '‹ previous'
|
||||||
|
next: 'next ›'
|
||||||
|
first: '« first'
|
||||||
|
last: 'last »'
|
||||||
|
quantity: 9
|
||||||
|
style:
|
||||||
|
type: grid
|
||||||
|
options:
|
||||||
|
grouping: { }
|
||||||
|
columns: 4
|
||||||
|
automatic_width: true
|
||||||
|
alignment: horizontal
|
||||||
|
col_class_default: true
|
||||||
|
col_class_custom: '%1-test-class-!1'
|
||||||
|
row_class_default: true
|
||||||
|
row_class_custom: '%1-test-class-!1'
|
||||||
|
row:
|
||||||
|
type: fields
|
||||||
|
options:
|
||||||
|
default_field_elements: true
|
||||||
|
inline: { }
|
||||||
|
separator: ''
|
||||||
|
hide_empty: false
|
||||||
|
fields:
|
||||||
|
title:
|
||||||
|
id: title
|
||||||
|
table: node_field_data
|
||||||
|
field: title
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
label: ''
|
||||||
|
exclude: false
|
||||||
|
alter:
|
||||||
|
alter_text: true
|
||||||
|
text: '%1-custom-text-!1'
|
||||||
|
make_link: false
|
||||||
|
path: ''
|
||||||
|
absolute: false
|
||||||
|
external: false
|
||||||
|
replace_spaces: false
|
||||||
|
path_case: none
|
||||||
|
trim_whitespace: false
|
||||||
|
alt: ''
|
||||||
|
rel: ''
|
||||||
|
link_class: ''
|
||||||
|
prefix: ''
|
||||||
|
suffix: ''
|
||||||
|
target: ''
|
||||||
|
nl2br: false
|
||||||
|
max_length: 0
|
||||||
|
word_boundary: false
|
||||||
|
ellipsis: false
|
||||||
|
more_link: false
|
||||||
|
more_link_text: ''
|
||||||
|
more_link_path: ''
|
||||||
|
strip_tags: false
|
||||||
|
trim: false
|
||||||
|
preserve_tags: ''
|
||||||
|
html: false
|
||||||
|
element_type: ''
|
||||||
|
element_class: ''
|
||||||
|
element_label_type: ''
|
||||||
|
element_label_class: ''
|
||||||
|
element_label_colon: false
|
||||||
|
element_wrapper_type: ''
|
||||||
|
element_wrapper_class: ''
|
||||||
|
element_default_classes: true
|
||||||
|
empty: ''
|
||||||
|
hide_empty: false
|
||||||
|
empty_zero: false
|
||||||
|
hide_alter_empty: true
|
||||||
|
click_sort_column: value
|
||||||
|
type: string
|
||||||
|
settings:
|
||||||
|
link_to_entity: true
|
||||||
|
group_column: value
|
||||||
|
group_columns: { }
|
||||||
|
group_rows: true
|
||||||
|
delta_limit: 0
|
||||||
|
delta_offset: 0
|
||||||
|
delta_reversed: false
|
||||||
|
delta_first_last: false
|
||||||
|
multi_type: separator
|
||||||
|
separator: ', '
|
||||||
|
field_api_classes: false
|
||||||
|
entity_type: node
|
||||||
|
entity_field: title
|
||||||
|
plugin_id: field
|
||||||
|
filters:
|
||||||
|
status:
|
||||||
|
value: true
|
||||||
|
table: node_field_data
|
||||||
|
field: status
|
||||||
|
plugin_id: boolean
|
||||||
|
entity_type: node
|
||||||
|
entity_field: status
|
||||||
|
id: status
|
||||||
|
expose:
|
||||||
|
operator: ''
|
||||||
|
group: 1
|
||||||
|
sorts:
|
||||||
|
created:
|
||||||
|
id: created
|
||||||
|
table: node_field_data
|
||||||
|
field: created
|
||||||
|
order: DESC
|
||||||
|
entity_type: node
|
||||||
|
entity_field: created
|
||||||
|
plugin_id: date
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
exposed: false
|
||||||
|
expose:
|
||||||
|
label: ''
|
||||||
|
granularity: second
|
||||||
|
title: 'test_token_view %1 !1'
|
||||||
|
header:
|
||||||
|
area_text_custom:
|
||||||
|
id: area_text_custom
|
||||||
|
table: views
|
||||||
|
field: area_text_custom
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
empty: false
|
||||||
|
tokenize: false
|
||||||
|
content: '%1-custom-!1'
|
||||||
|
plugin_id: text_custom
|
||||||
|
footer:
|
||||||
|
area:
|
||||||
|
id: area
|
||||||
|
table: views
|
||||||
|
field: area
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
empty: false
|
||||||
|
tokenize: false
|
||||||
|
content:
|
||||||
|
value: '%1-text-!1'
|
||||||
|
format: basic_html
|
||||||
|
plugin_id: text
|
||||||
|
empty:
|
||||||
|
result:
|
||||||
|
id: result
|
||||||
|
table: views
|
||||||
|
field: result
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
empty: true
|
||||||
|
content: "Displaying @start - @end of @total\n\n%1-result-!1"
|
||||||
|
plugin_id: result
|
||||||
|
title:
|
||||||
|
id: title
|
||||||
|
table: views
|
||||||
|
field: title
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
empty: true
|
||||||
|
title: '%1-title-!1'
|
||||||
|
plugin_id: title
|
||||||
|
entity_node:
|
||||||
|
id: entity
|
||||||
|
table: views
|
||||||
|
field: entity_node
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
empty: true
|
||||||
|
target: '%1-entity-!1'
|
||||||
|
plugin_id: entity
|
||||||
|
relationships: { }
|
||||||
|
arguments:
|
||||||
|
nid:
|
||||||
|
id: nid
|
||||||
|
table: node_field_data
|
||||||
|
field: nid
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
default_action: ignore
|
||||||
|
exception:
|
||||||
|
value: all
|
||||||
|
title_enable: true
|
||||||
|
title: '%1 exception-title !1'
|
||||||
|
title_enable: true
|
||||||
|
title: '%1 title !1'
|
||||||
|
default_argument_type: fixed
|
||||||
|
default_argument_options:
|
||||||
|
argument: ''
|
||||||
|
default_argument_skip_url: false
|
||||||
|
summary_options:
|
||||||
|
base_path: ''
|
||||||
|
count: true
|
||||||
|
items_per_page: 25
|
||||||
|
override: false
|
||||||
|
summary:
|
||||||
|
sort_order: asc
|
||||||
|
number_of_records: 0
|
||||||
|
format: default_summary
|
||||||
|
specify_validation: false
|
||||||
|
validate:
|
||||||
|
type: none
|
||||||
|
fail: 'not found'
|
||||||
|
validate_options: { }
|
||||||
|
break_phrase: false
|
||||||
|
not: false
|
||||||
|
entity_type: node
|
||||||
|
entity_field: nid
|
||||||
|
plugin_id: numeric
|
||||||
|
display_extenders: { }
|
||||||
|
css_class: ''
|
||||||
|
use_more: true
|
||||||
|
use_more_always: true
|
||||||
|
use_more_text: '%1-more-text-!1'
|
||||||
|
link_url: '%1-custom-url-!1'
|
||||||
|
link_display: custom_url
|
||||||
|
cache_metadata:
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url
|
||||||
|
- url.query_args
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
cacheable: false
|
||||||
|
block_1:
|
||||||
|
display_plugin: block
|
||||||
|
id: block_1
|
||||||
|
display_title: Block
|
||||||
|
position: 2
|
||||||
|
display_options:
|
||||||
|
display_extenders: { }
|
||||||
|
cache_metadata:
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url
|
||||||
|
- url.query_args
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
cacheable: false
|
||||||
|
page_1:
|
||||||
|
display_plugin: page
|
||||||
|
id: page_1
|
||||||
|
display_title: Page
|
||||||
|
position: 1
|
||||||
|
display_options:
|
||||||
|
display_extenders: { }
|
||||||
|
path: test-token-view
|
||||||
|
cache_metadata:
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url
|
||||||
|
- url.query_args
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
cacheable: false
|
||||||
|
feed_1:
|
||||||
|
display_plugin: feed
|
||||||
|
id: feed_1
|
||||||
|
display_title: Feed
|
||||||
|
position: 1
|
||||||
|
display_options:
|
||||||
|
defaults:
|
||||||
|
style: false
|
||||||
|
display_extenders: { }
|
||||||
|
style:
|
||||||
|
type: rss
|
||||||
|
options:
|
||||||
|
description: %1-description-!1
|
||||||
|
|
||||||
|
path: test-token-view.xml
|
||||||
|
cache_metadata:
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url
|
||||||
|
- url.query_args
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
cacheable: false
|
||||||
|
|
@ -46,7 +46,7 @@ class FieldTest extends FieldPluginBase {
|
||||||
* Overrides Drupal\views\Plugin\views\field\FieldPluginBase::addSelfTokens().
|
* Overrides Drupal\views\Plugin\views\field\FieldPluginBase::addSelfTokens().
|
||||||
*/
|
*/
|
||||||
protected function addSelfTokens(&$tokens, $item) {
|
protected function addSelfTokens(&$tokens, $item) {
|
||||||
$tokens['[test__token]'] = $this->getTestValue();
|
$tokens['{{ test_token }}'] = $this->getTestValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -110,3 +110,17 @@ function template_preprocess_views_view_mapping_test(&$variables) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test pre_render function.
|
||||||
|
*
|
||||||
|
* @param array $element
|
||||||
|
* A render array
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* The changed render array.
|
||||||
|
*/
|
||||||
|
function views_test_data_test_pre_render_function($element) {
|
||||||
|
$element['#markup'] = 'views_test_data_test_pre_render_function executed';
|
||||||
|
return $element;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,10 +130,10 @@ class EntityTest extends UnitTestCase {
|
||||||
*/
|
*/
|
||||||
public function providerTestTokens() {
|
public function providerTestTokens() {
|
||||||
return [
|
return [
|
||||||
['!1', 5],
|
['{{ raw_arguments.test1 }}', 5],
|
||||||
['%2', 6],
|
['{{ arguments.test2 }}', 6],
|
||||||
['{{ test_render_token }}', 7],
|
['{{ test_render_token }}', 7],
|
||||||
['[test:global_token]', 8],
|
['{{ test:global_token }}', 8],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -449,8 +449,8 @@ class FieldPluginBaseTest extends UnitTestCase {
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->renderer->expects($this->once())
|
$this->renderer->expects($this->once())
|
||||||
->method('render')
|
->method('renderPlain')
|
||||||
->with($build, FALSE)
|
->with($build)
|
||||||
->willReturn('base:test-path/123');
|
->willReturn('base:test-path/123');
|
||||||
|
|
||||||
$result = $field->advancedRender($row);
|
$result = $field->advancedRender($row);
|
||||||
|
|
@ -497,6 +497,67 @@ class FieldPluginBaseTest extends UnitTestCase {
|
||||||
return $field;
|
return $field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::getRenderTokens
|
||||||
|
*/
|
||||||
|
public function testGetRenderTokensWithoutFieldsAndArguments() {
|
||||||
|
$field = $this->setupTestField();
|
||||||
|
|
||||||
|
$this->display->expects($this->any())
|
||||||
|
->method('getHandlers')
|
||||||
|
->willReturnMap([
|
||||||
|
['argument', []],
|
||||||
|
['field', []],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals([], $field->getRenderTokens([]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::getRenderTokens
|
||||||
|
*/
|
||||||
|
public function testGetRenderTokensWithoutArguments() {
|
||||||
|
$field = $this->setupTestField(['id' => 'id']);
|
||||||
|
|
||||||
|
$field->last_render = 'last rendered output';
|
||||||
|
$this->display->expects($this->any())
|
||||||
|
->method('getHandlers')
|
||||||
|
->willReturnMap([
|
||||||
|
['argument', []],
|
||||||
|
['field', ['id' => $field]],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(['{{ id }}' => 'last rendered output'], $field->getRenderTokens([]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::getRenderTokens
|
||||||
|
*/
|
||||||
|
public function testGetRenderTokensWithArguments() {
|
||||||
|
$field = $this->setupTestField(['id' => 'id']);
|
||||||
|
$field->view->args = ['argument value'];
|
||||||
|
$field->view->build_info['substitutions']['{{ arguments.name }}'] = 'argument value';
|
||||||
|
|
||||||
|
$argument = $this->getMockBuilder('\Drupal\views\Plugin\views\argument\ArgumentPluginBase')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$field->last_render = 'last rendered output';
|
||||||
|
$this->display->expects($this->any())
|
||||||
|
->method('getHandlers')
|
||||||
|
->willReturnMap([
|
||||||
|
['argument', ['name' => $argument]],
|
||||||
|
['field', ['id' => $field]],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
'{{ id }}' => 'last rendered output',
|
||||||
|
'{{ arguments.name }}' => 'argument value',
|
||||||
|
'{{ raw_arguments.name }}' => 'argument value',
|
||||||
|
];
|
||||||
|
$this->assertEquals($expected, $field->getRenderTokens([]));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class FieldPluginBaseTestField extends FieldPluginBase {
|
class FieldPluginBaseTestField extends FieldPluginBase {
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,200 @@ function views_update_8001(&$sandbox) {
|
||||||
return $message;
|
return $message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates %1 and !1 tokens to argument tokens.
|
||||||
|
*/
|
||||||
|
function views_update_8002() {
|
||||||
|
$config_factory = \Drupal::configFactory();
|
||||||
|
foreach ($config_factory->listAll('views.view.') as $view_config_name) {
|
||||||
|
$view = $config_factory->getEditable($view_config_name);
|
||||||
|
|
||||||
|
$displays = $view->get('display');
|
||||||
|
$argument_map_per_display = _views_update_argument_map($displays);
|
||||||
|
|
||||||
|
$changed = FALSE;
|
||||||
|
|
||||||
|
// Update all the field settings, which support tokens.
|
||||||
|
foreach ($displays as $display_name => &$display) {
|
||||||
|
if (!empty($display['display_options']['fields'])) {
|
||||||
|
$token_values = [
|
||||||
|
'path',
|
||||||
|
'alt',
|
||||||
|
'link_class',
|
||||||
|
'rel',
|
||||||
|
'target',
|
||||||
|
'query',
|
||||||
|
'fragment',
|
||||||
|
'prefix',
|
||||||
|
'suffix',
|
||||||
|
'more_link_text',
|
||||||
|
'more_link_path',
|
||||||
|
'link_attributes',
|
||||||
|
'text',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($display['display_options']['fields'] as $field_name => &$field) {
|
||||||
|
foreach ($token_values as $token_name) {
|
||||||
|
if (!empty($field['alter'][$token_name])) {
|
||||||
|
if (is_array($field['alter'][$token_name])) {
|
||||||
|
foreach (array_keys($field['alter'][$token_name]) as $key) {
|
||||||
|
$field['alter'][$token_name][$key] = _views_update_8002_token_update($field['alter'][$token_name][$key], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$field['alter'][$token_name] = _views_update_8002_token_update($field['alter'][$token_name], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the area handlers with tokens.
|
||||||
|
foreach ($displays as $display_name => &$display) {
|
||||||
|
$area_types = ['header', 'footer', 'empty'];
|
||||||
|
foreach ($area_types as $area_type) {
|
||||||
|
if (!empty($display['display_options'][$area_type])) {
|
||||||
|
foreach ($display['display_options'][$area_type] as &$area) {
|
||||||
|
switch ($area['plugin_id']) {
|
||||||
|
case 'title':
|
||||||
|
$area['title'] = _views_update_8002_token_update($area['title'], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
break;
|
||||||
|
case 'result':
|
||||||
|
$area['content'] = _views_update_8002_token_update($area['content'], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
break;
|
||||||
|
case 'text':
|
||||||
|
$area['content']['value'] = _views_update_8002_token_update($area['content']['value'], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
break;
|
||||||
|
case 'text_custom':
|
||||||
|
$area['content'] = _views_update_8002_token_update($area['content'], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
break;
|
||||||
|
case 'entity':
|
||||||
|
$area['target'] = _views_update_8002_token_update($area['target'], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the argument title settings.
|
||||||
|
foreach ($displays as $display_name => &$display) {
|
||||||
|
if (!empty($display['display_options']['arguments'])) {
|
||||||
|
foreach ($display['display_options']['arguments'] as &$argument) {
|
||||||
|
if (isset($argument['exception']['title'])) {
|
||||||
|
$argument['exception']['title'] = _views_update_8002_token_update($argument['exception']['title'], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
}
|
||||||
|
if (isset($argument['title'])) {
|
||||||
|
$argument['title'] = _views_update_8002_token_update($argument['title'], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the display title settings.
|
||||||
|
// Update the more link text and more link URL.
|
||||||
|
foreach ($displays as $display_name => &$display) {
|
||||||
|
if (!empty($display['display_options']['title'])) {
|
||||||
|
$display['display_options']['title'] = _views_update_8002_token_update($display['display_options']['title'], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
}
|
||||||
|
if (!empty($display['display_options']['use_more_text'])) {
|
||||||
|
$display['display_options']['use_more_text'] = _views_update_8002_token_update($display['display_options']['use_more_text'], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
}
|
||||||
|
if (!empty($display['display_options']['link_url'])) {
|
||||||
|
$display['display_options']['link_url'] = _views_update_8002_token_update($display['display_options']['link_url'], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update custom classes for row class + grid classes.
|
||||||
|
// Update RSS description field.
|
||||||
|
foreach ($displays as $display_name => &$display) {
|
||||||
|
if (!empty($display['display_options']['style'])) {
|
||||||
|
if (!empty($display['display_options']['style']['options']['row_class_custom'])) {
|
||||||
|
$display['display_options']['style']['options']['row_class_custom'] = _views_update_8002_token_update($display['display_options']['style']['options']['row_class_custom'], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
}
|
||||||
|
if (!empty($display['display_options']['style']['options']['col_class_custom'])) {
|
||||||
|
$display['display_options']['style']['options']['col_class_custom'] = _views_update_8002_token_update($display['display_options']['style']['options']['col_class_custom'], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
}
|
||||||
|
if (!empty($display['display_options']['style']['options']['description'])) {
|
||||||
|
$display['display_options']['style']['options']['description'] = _views_update_8002_token_update($display['display_options']['style']['options']['description'], $argument_map_per_display[$display_name]);
|
||||||
|
$changed = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($changed) {
|
||||||
|
$view->set('display', $displays);
|
||||||
|
$view->save(TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a views configuration string from using %/! to twig tokens.
|
||||||
|
*
|
||||||
|
* @param string $text
|
||||||
|
* Text in which to search for argument tokens and replace them with their
|
||||||
|
* twig representation.
|
||||||
|
* @param array $argument_map
|
||||||
|
* A map of argument machine names keyed by their previous index.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* The updated token.
|
||||||
|
*/
|
||||||
|
function _views_update_8002_token_update($text, array $argument_map) {
|
||||||
|
$text = preg_replace_callback('/%(\d)/', function ($match) use ($argument_map) {
|
||||||
|
return "{{ arguments.{$argument_map[$match[1]]} }}";
|
||||||
|
}, $text);
|
||||||
|
$text = preg_replace_callback('/!(\d)/', function ($match) use ($argument_map) {
|
||||||
|
return "{{ raw_arguments.{$argument_map[$match[1]]} }}";
|
||||||
|
}, $text);
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an argument map for each Views display.
|
||||||
|
*
|
||||||
|
* @param array $displays
|
||||||
|
* A list of Views displays.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* The argument map keyed by display id.
|
||||||
|
*/
|
||||||
|
function _views_update_argument_map($displays) {
|
||||||
|
$argument_map = [];
|
||||||
|
foreach ($displays as $display_id => $display) {
|
||||||
|
$argument_map[$display_id] = [];
|
||||||
|
if (isset($display['display_options']['arguments'])) {
|
||||||
|
foreach (array_keys($display['display_options']['arguments']) as $number => $name) {
|
||||||
|
$argument_map[$display_id][$number + 1] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (isset($displays['default']['display_options']['arguments'])) {
|
||||||
|
foreach (array_keys($displays['default']['display_options']['arguments']) as $number => $name) {
|
||||||
|
$argument_map[$display_id][$number + 1] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $argument_map;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @} End of "addtogroup updates-8.0.0-beta".
|
* @} End of "addtogroup updates-8.0.0-beta".
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,8 @@ class AreaEntityUITest extends UITestBase {
|
||||||
$this->assertFieldByName('options[target]', $entity_test->id());
|
$this->assertFieldByName('options[target]', $entity_test->id());
|
||||||
|
|
||||||
// Replace the header target entities with argument placeholders.
|
// Replace the header target entities with argument placeholders.
|
||||||
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_block", ['options[target]' => '!1'], 'Apply');
|
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_block", ['options[target]' => '{{ raw_arguments.null }}'], 'Apply');
|
||||||
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test", ['options[target]' => '!1'], 'Apply');
|
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test", ['options[target]' => '{{ raw_arguments.null }}'], 'Apply');
|
||||||
$this->drupalPostForm(NULL, [], 'Save');
|
$this->drupalPostForm(NULL, [], 'Save');
|
||||||
|
|
||||||
// Confirm that the argument placeholders are saved.
|
// Confirm that the argument placeholders are saved.
|
||||||
|
|
@ -78,15 +78,15 @@ class AreaEntityUITest extends UITestBase {
|
||||||
$header = $view->getDisplay('default')['display_options']['header'];
|
$header = $view->getDisplay('default')['display_options']['header'];
|
||||||
$this->assertEqual(['entity_block', 'entity_entity_test'], array_keys($header));
|
$this->assertEqual(['entity_block', 'entity_entity_test'], array_keys($header));
|
||||||
|
|
||||||
$this->assertEqual('!1', $header['entity_block']['target']);
|
$this->assertEqual('{{ raw_arguments.null }}', $header['entity_block']['target']);
|
||||||
$this->assertEqual('!1', $header['entity_entity_test']['target']);
|
$this->assertEqual('{{ raw_arguments.null }}', $header['entity_entity_test']['target']);
|
||||||
|
|
||||||
// Confirm that the argument placeholders are still displayed in the form.
|
// Confirm that the argument placeholders are still displayed in the form.
|
||||||
$this->drupalGet("admin/structure/views/nojs/handler/$id/page_1/header/entity_block");
|
$this->drupalGet("admin/structure/views/nojs/handler/$id/page_1/header/entity_block");
|
||||||
$this->assertFieldByName('options[target]', '!1');
|
$this->assertFieldByName('options[target]', '{{ raw_arguments.null }}');
|
||||||
|
|
||||||
$this->drupalGet("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test");
|
$this->drupalGet("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test");
|
||||||
$this->assertFieldByName('options[target]', '!1');
|
$this->assertFieldByName('options[target]', '{{ raw_arguments.null }}');
|
||||||
|
|
||||||
// Change the targets for both headers back to the entities.
|
// Change the targets for both headers back to the entities.
|
||||||
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_block", ['options[target]' => $block->id()], 'Apply');
|
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_block", ['options[target]' => $block->id()], 'Apply');
|
||||||
|
|
|
||||||
|
|
@ -42,18 +42,18 @@ class FieldUITest extends UITestBase {
|
||||||
// Ensure that the expected tokens appear in the UI.
|
// Ensure that the expected tokens appear in the UI.
|
||||||
$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"]/ul/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"]/ul/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"]/ul/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');
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ class XssTest extends UITestBase {
|
||||||
$this->assertEscaped('<marquee>test</marquee>', 'Field admin label is properly escaped.');
|
$this->assertEscaped('<marquee>test</marquee>', 'Field admin label is properly escaped.');
|
||||||
|
|
||||||
$this->drupalGet('admin/structure/views/nojs/handler/sa_contrib_2013_035/page_1/header/area');
|
$this->drupalGet('admin/structure/views/nojs/handler/sa_contrib_2013_035/page_1/header/area');
|
||||||
$this->assertRaw('[title] == &lt;marquee&gt;test&lt;/marquee&gt;', 'Token label is properly escaped.');
|
$this->assertRaw('{{ title }} == &lt;marquee&gt;test&lt;/marquee&gt;', 'Token label is properly escaped.');
|
||||||
$this->assertRaw('[title_1] == &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;', 'Token label is properly escaped.');
|
$this->assertRaw('{{ title_1 }} == &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;', 'Token label is properly escaped.');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue