Newer
Older
namespace Drupal\views\Plugin\views\field;
Alex Pott
committed
use Drupal\Component\Utility\Html;
Alex Bronstein
committed
use Drupal\Component\Render\MarkupInterface;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\UrlHelper;
Angie Byron
committed
use Drupal\Component\Utility\Xss;
Dries Buytaert
committed
use Drupal\Core\Form\FormStateInterface;
Angie Byron
committed
use Drupal\Core\Url as CoreUrl;
Tim Plunkett
committed
use Drupal\views\Plugin\views\HandlerBase;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
Alex Bronstein
committed
use Drupal\views\Render\ViewsRenderPipelineMarkup;
use Drupal\views\ResultRow;
Daniel Wehner
committed
use Drupal\views\ViewExecutable;
Angie Byron
committed
* @defgroup views_field_handlers Views field handler plugins
Angie Byron
committed
* Handler plugins for Views fields.
Angie Byron
committed
* Field handlers handle both querying and display of fields in views.
*
* Field handler plugins extend
Alex Pott
committed
* \Drupal\views\Plugin\views\field\FieldPluginBase. They must be
Angie Byron
committed
* annotated with \Drupal\views\Annotation\ViewsField annotation, and they
* must be in namespace directory Plugin\views\field.
*
* The following items can go into a hook_views_data() implementation in a
* field section to affect how the field handler will behave:
* - additional fields: An array of fields that should be added to the query.
* The array is in one of these forms:
Angie Byron
committed
* @code
* // Simple form, for fields within the same table.
* array('identifier' => fieldname)
* // Form for fields in a different table.
Angie Byron
committed
* array('identifier' => array('table' => tablename, 'field' => fieldname))
* @endcode
* As many fields as are necessary may be in this array.
* - click sortable: If TRUE (default), this field may be click sorted.
*
* @ingroup views_plugins
* @see plugin_api
/**
* Base class for views fields.
*
* @ingroup views_field_handlers
*/
Alex Pott
committed
abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterface {
/**
* Indicator of the renderText() method for rendering a single item.
* (If no render_item() is present).
*/
const RENDER_TEXT_PHASE_SINGLE_ITEM = 0;
/**
* Indicator of the renderText() method for rendering the whole element.
* (if no render_item() method is available).
*/
const RENDER_TEXT_PHASE_COMPLETELY = 1;
/**
* Indicator of the renderText() method for rendering the empty text.
*/
const RENDER_TEXT_PHASE_EMPTY = 2;
public $aliases = [];
Tim Plunkett
committed
/**
* The field value prior to any rewriting.
*
* @var mixed
*/
public $original_value = NULL;
* Stores additional fields which get added to the query.
*
* The generated aliases are stored in $aliases.
public $additional_fields = [];
Alex Pott
committed
/**
* The link generator.
*
* @var \Drupal\Core\Utility\LinkGeneratorInterface
*/
protected $linkGenerator;
Alex Pott
committed
/**
* Stores the render API renderer.
*
Alex Pott
committed
* @var \Drupal\Core\Render\RendererInterface
Alex Pott
committed
*/
protected $renderer;
/**
* Keeps track of the last render index.
*
* @var int|NULL
*/
protected $lastRenderIndex;
* {@inheritdoc}
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
parent::init($view, $display, $options);
$this->additional_fields = [];
if (!empty($this->definition['additional fields'])) {
$this->additional_fields = $this->definition['additional fields'];
}
if (!isset($this->options['exclude'])) {
$this->options['exclude'] = '';
}
}
/**
* Determine if this field can allow advanced rendering.
*
* Fields can set this to FALSE if they do not wish to allow
* token based rewriting or link-making.
*/
protected function allowAdvancedRender() {
return TRUE;
}
/**
* Called to add the field to a query.
*/
public function query() {
$this->ensureMyTable();
$params = $this->options['group_type'] != 'group' ? ['function' => $this->options['group_type']] : [];
Alex Pott
committed
$this->field_alias = $this->query->addField($this->tableAlias, $this->realField, NULL, $params);
$this->addAdditionalFields();
}
/**
* Add 'additional' fields to the query.
*
* @param $fields
* An array of fields. The key is an identifier used to later find the
* field alias used. The value is either a string in which case it's
* assumed to be a field on this handler's table; or it's an array in the
* form of
* @code array('table' => $tablename, 'field' => $fieldname) @endcode
protected function addAdditionalFields($fields = NULL) {
if (!isset($fields)) {
// notice check
if (empty($this->additional_fields)) {
return;
}
$fields = $this->additional_fields;
}
$group_params = [];
if ($this->options['group_type'] != 'group') {
$group_params = [
];
}
if (!empty($fields) && is_array($fields)) {
foreach ($fields as $identifier => $info) {
if (is_array($info)) {
if (isset($info['table'])) {
$table_alias = $this->query->ensureTable($info['table'], $this->relationship);
$table_alias = $this->tableAlias;
debug(t('Handler @handler tried to add additional_field @identifier but @table could not be added!', ['@handler' => $this->definition['id'], '@identifier' => $identifier, '@table' => $info['table']]));
$this->aliases[$identifier] = 'broken';
continue;
}
$params = [];
if (!empty($info['params'])) {
$params = $info['params'];
}
$params += $group_params;
Alex Pott
committed
$this->aliases[$identifier] = $this->query->addField($table_alias, $info['field'], NULL, $params);
Alex Pott
committed
$this->aliases[$info] = $this->query->addField($this->tableAlias, $info, NULL, $group_params);
Alex Pott
committed
* {@inheritdoc}
public function clickSort($order) {
if (isset($this->field_alias)) {
// Since fields should always have themselves already added, just
// add a sort on the field.
$params = $this->options['group_type'] != 'group' ? ['function' => $this->options['group_type']] : [];
Alex Pott
committed
$this->query->addOrderBy(NULL, NULL, $order, $this->field_alias, $params);
Alex Pott
committed
* {@inheritdoc}
public function clickSortable() {
return isset($this->definition['click sortable']) ? $this->definition['click sortable'] : TRUE;
Alex Pott
committed
* {@inheritdoc}
public function label() {
if (!isset($this->options['label'])) {
return '';
}
return $this->options['label'];
}
/**
Alex Pott
committed
* {@inheritdoc}
Alex Pott
committed
public function elementType($none_supported = FALSE, $default_empty = FALSE, $inline = FALSE) {
if ($none_supported) {
if ($this->options['element_type'] === '0') {
return '';
}
}
if ($this->options['element_type']) {
return $this->options['element_type'];
}
if ($default_empty) {
return '';
}
if ($inline) {
return 'span';
}
if (isset($this->definition['element type'])) {
return $this->definition['element type'];
}
return 'span';
}
/**
Alex Pott
committed
* {@inheritdoc}
Alex Pott
committed
public function elementLabelType($none_supported = FALSE, $default_empty = FALSE) {
if ($none_supported) {
if ($this->options['element_label_type'] === '0') {
return '';
}
}
if ($this->options['element_label_type']) {
return $this->options['element_label_type'];
}
if ($default_empty) {
return '';
}
return 'span';
}
/**
Alex Pott
committed
* {@inheritdoc}
public function elementWrapperType($none_supported = FALSE, $default_empty = FALSE) {
if ($none_supported) {
if ($this->options['element_wrapper_type'] === '0') {
return 0;
}
}
if ($this->options['element_wrapper_type']) {
return $this->options['element_wrapper_type'];
}
if ($default_empty) {
return '';
}
return 'div';
}
/**
Alex Pott
committed
* {@inheritdoc}
public function getElements() {
static $elements = NULL;
if (!isset($elements)) {
// @todo Add possible html5 elements.
$elements = [
'' => $this->t('- Use default -'),
'0' => $this->t('- None -')
];
Angie Byron
committed
$elements += \Drupal::config('views.settings')->get('field_rewrite_elements');
}
return $elements;
}
/**
Alex Pott
committed
* {@inheritdoc}
public function elementClasses($row_index = NULL) {
$classes = $this->tokenizeValue($this->options['element_class'], $row_index);
$classes = explode(' ', $classes);
$class = Html::cleanCssIdentifier($class);
}
return implode(' ', $classes);
}
/**
Alex Pott
committed
* {@inheritdoc}
public function tokenizeValue($value, $row_index = NULL) {
if (strpos($value, '{{') !== FALSE) {
$fake_item = [
];
// Use isset() because empty() will trigger on 0 and 0 is
// the first row.
if (isset($row_index) && isset($this->view->style_plugin->render_tokens[$row_index])) {
$tokens = $this->view->style_plugin->render_tokens[$row_index];
}
else {
// Get tokens from the last field.
$last_field = end($this->view->field);
if (isset($last_field->last_tokens)) {
$tokens = $last_field->last_tokens;
}
else {
Alex Pott
committed
$tokens = $last_field->getRenderTokens($fake_item);
$value = strip_tags($this->renderAltered($fake_item, $tokens));
if (!empty($this->options['alter']['trim_whitespace'])) {
$value = trim($value);
}
}
return $value;
}
/**
Alex Pott
committed
* {@inheritdoc}
Alex Pott
committed
public function elementLabelClasses($row_index = NULL) {
$classes = $this->tokenizeValue($this->options['element_label_class'], $row_index);
$classes = explode(' ', $classes);
$class = Html::cleanCssIdentifier($class);
}
return implode(' ', $classes);
}
/**
Alex Pott
committed
* {@inheritdoc}
public function elementWrapperClasses($row_index = NULL) {
$classes = $this->tokenizeValue($this->options['element_wrapper_class'], $row_index);
$classes = explode(' ', $classes);
$class = Html::cleanCssIdentifier($class);
}
return implode(' ', $classes);
}
Bojan Živanović
committed
/**
Alex Pott
committed
* {@inheritdoc}
Bojan Živanović
committed
*/
public function getEntity(ResultRow $values) {
Bojan Živanović
committed
$relationship_id = $this->options['relationship'];
if ($relationship_id == 'none') {
return $values->_entity;
}
Alex Pott
committed
elseif (isset($values->_relationship_entities[$relationship_id])) {
Bojan Živanović
committed
return $values->_relationship_entities[$relationship_id];
}
}
Alex Pott
committed
* {@inheritdoc}
public function getValue(ResultRow $values, $field = NULL) {
$alias = isset($field) ? $this->aliases[$field] : $this->field_alias;
if (isset($values->{$alias})) {
return $values->{$alias};
}
}
/**
Alex Pott
committed
* {@inheritdoc}
*/
Alex Pott
committed
public function useStringGroupBy() {
return TRUE;
}
protected function defineOptions() {
$options = parent::defineOptions();
$options['label'] = ['default' => ''];
Alex Pott
committed
// Some styles (for example table) should have labels enabled by default.
$style = $this->view->getStyle();
if (isset($style) && $style->defaultFieldLabels()) {
$options['label']['default'] = $this->definition['title'];
}
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
$options['exclude'] = ['default' => FALSE];
$options['alter'] = [
'contains' => [
'alter_text' => ['default' => FALSE],
'text' => ['default' => ''],
'make_link' => ['default' => FALSE],
'path' => ['default' => ''],
'absolute' => ['default' => FALSE],
'external' => ['default' => FALSE],
'replace_spaces' => ['default' => FALSE],
'path_case' => ['default' => 'none'],
'trim_whitespace' => ['default' => FALSE],
'alt' => ['default' => ''],
'rel' => ['default' => ''],
'link_class' => ['default' => ''],
'prefix' => ['default' => ''],
'suffix' => ['default' => ''],
'target' => ['default' => ''],
'nl2br' => ['default' => FALSE],
'max_length' => ['default' => 0],
'word_boundary' => ['default' => TRUE],
'ellipsis' => ['default' => TRUE],
'more_link' => ['default' => FALSE],
'more_link_text' => ['default' => ''],
'more_link_path' => ['default' => ''],
'strip_tags' => ['default' => FALSE],
'trim' => ['default' => FALSE],
'preserve_tags' => ['default' => ''],
'html' => ['default' => FALSE],
],
];
$options['element_type'] = ['default' => ''];
$options['element_class'] = ['default' => ''];
$options['element_label_type'] = ['default' => ''];
$options['element_label_class'] = ['default' => ''];
$options['element_label_colon'] = ['default' => TRUE];
$options['element_wrapper_type'] = ['default' => ''];
$options['element_wrapper_class'] = ['default' => ''];
$options['element_default_classes'] = ['default' => TRUE];
$options['empty'] = ['default' => ''];
$options['hide_empty'] = ['default' => FALSE];
$options['empty_zero'] = ['default' => FALSE];
$options['hide_alter_empty'] = ['default' => TRUE];
return $options;
}
/**
* Performs some cleanup tasks on the options array before saving it.
*/
Dries Buytaert
committed
public function submitOptionsForm(&$form, FormStateInterface $form_state) {
Alex Pott
committed
$options = &$form_state->getValue('options');
$types = ['element_type', 'element_label_type', 'element_wrapper_type'];
$classes = array_combine(['element_class', 'element_label_class', 'element_wrapper_class'], $types);
foreach ($types as $type) {
if (!$options[$type . '_enable']) {
$options[$type] = '';
}
}
foreach ($classes as $class => $type) {
if (!$options[$class . '_enable'] || !$options[$type . '_enable']) {
$options[$class] = '';
}
}
if (empty($options['custom_label'])) {
$options['label'] = '';
$options['element_label_colon'] = FALSE;
}
}
/**
* Default options form that provides the label widget that all fields
* should have.
*/
Dries Buytaert
committed
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$form['custom_label'] = [
'#title' => $this->t('Create a label'),
'#default_value' => $label !== '',
'#weight' => -103,
];
$form['label'] = [
'#title' => $this->t('Label'),
'#states' => [
'visible' => [
':input[name="options[custom_label]"]' => ['checked' => TRUE],
],
],
];
$form['element_label_colon'] = [
'#title' => $this->t('Place a colon after the label'),
'#default_value' => $this->options['element_label_colon'],
'#states' => [
'visible' => [
':input[name="options[custom_label]"]' => ['checked' => TRUE],
],
],
];
$form['exclude'] = [
'#title' => $this->t('Exclude from display'),
'#default_value' => $this->options['exclude'],
'#description' => $this->t('Enable to load this field as hidden. Often used to group fields, or to use as token in another field.'),
];
$form['style_settings'] = [
'#type' => 'details',
'#title' => $this->t('Style settings'),
];
$form['element_type_enable'] = [
'#title' => $this->t('Customize field HTML'),
'#default_value' => !empty($this->options['element_type']) || (string) $this->options['element_type'] == '0' || !empty($this->options['element_class']) || (string) $this->options['element_class'] == '0',
'#fieldset' => 'style_settings',
];
$form['element_type'] = [
'#title' => $this->t('HTML element'),
'#options' => $this->getElements(),
'#type' => 'select',
'#default_value' => $this->options['element_type'],
'#description' => $this->t('Choose the HTML element to wrap around this field, e.g. H1, H2, etc.'),
'#states' => [
'visible' => [
':input[name="options[element_type_enable]"]' => ['checked' => TRUE],
],
],
];
$form['element_class_enable'] = [
'#title' => $this->t('Create a CSS class'),
'#states' => [
'visible' => [
':input[name="options[element_type_enable]"]' => ['checked' => TRUE],
],
],
'#default_value' => !empty($this->options['element_class']) || (string) $this->options['element_class'] == '0',
'#fieldset' => 'style_settings',
];
$form['element_class'] = [
'#title' => $this->t('CSS class'),
'#description' => $this->t('You may use token substitutions from the rewriting section in this class.'),
'#type' => 'textfield',
'#default_value' => $this->options['element_class'],
'#states' => [
'visible' => [
':input[name="options[element_type_enable]"]' => ['checked' => TRUE],
':input[name="options[element_class_enable]"]' => ['checked' => TRUE],
],
],
];
$form['element_label_type_enable'] = [
'#title' => $this->t('Customize label HTML'),
'#default_value' => !empty($this->options['element_label_type']) || (string) $this->options['element_label_type'] == '0' || !empty($this->options['element_label_class']) || (string) $this->options['element_label_class'] == '0',
'#fieldset' => 'style_settings',
];
$form['element_label_type'] = [
'#title' => $this->t('Label HTML element'),
'#options' => $this->getElements(FALSE),
'#type' => 'select',
'#default_value' => $this->options['element_label_type'],
'#description' => $this->t('Choose the HTML element to wrap around this label, e.g. H1, H2, etc.'),
'#states' => [
'visible' => [
':input[name="options[element_label_type_enable]"]' => ['checked' => TRUE],
],
],
];
$form['element_label_class_enable'] = [
'#title' => $this->t('Create a CSS class'),
'#states' => [
'visible' => [
':input[name="options[element_label_type_enable]"]' => ['checked' => TRUE],
],
],
'#default_value' => !empty($this->options['element_label_class']) || (string) $this->options['element_label_class'] == '0',
'#fieldset' => 'style_settings',
];
$form['element_label_class'] = [
'#title' => $this->t('CSS class'),
'#description' => $this->t('You may use token substitutions from the rewriting section in this class.'),
'#type' => 'textfield',
'#default_value' => $this->options['element_label_class'],
'#states' => [
'visible' => [
':input[name="options[element_label_type_enable]"]' => ['checked' => TRUE],
':input[name="options[element_label_class_enable]"]' => ['checked' => TRUE],
],
],
];
$form['element_wrapper_type_enable'] = [
'#title' => $this->t('Customize field and label wrapper HTML'),
'#default_value' => !empty($this->options['element_wrapper_type']) || (string) $this->options['element_wrapper_type'] == '0' || !empty($this->options['element_wrapper_class']) || (string) $this->options['element_wrapper_class'] == '0',
'#fieldset' => 'style_settings',
];
$form['element_wrapper_type'] = [
'#title' => $this->t('Wrapper HTML element'),
'#options' => $this->getElements(FALSE),
'#type' => 'select',
'#default_value' => $this->options['element_wrapper_type'],
'#description' => $this->t('Choose the HTML element to wrap around this field and label, e.g. H1, H2, etc. This may not be used if the field and label are not rendered together, such as with a table.'),
'#states' => [
'visible' => [
':input[name="options[element_wrapper_type_enable]"]' => ['checked' => TRUE],
],
],
];
$form['element_wrapper_class_enable'] = [
'#title' => $this->t('Create a CSS class'),
'#states' => [
'visible' => [
':input[name="options[element_wrapper_type_enable]"]' => ['checked' => TRUE],
],
],
'#default_value' => !empty($this->options['element_wrapper_class']) || (string) $this->options['element_wrapper_class'] == '0',
'#fieldset' => 'style_settings',
];
$form['element_wrapper_class'] = [
'#title' => $this->t('CSS class'),
'#description' => $this->t('You may use token substitutions from the rewriting section in this class.'),
'#type' => 'textfield',
'#default_value' => $this->options['element_wrapper_class'],
'#states' => [
'visible' => [
':input[name="options[element_wrapper_class_enable]"]' => ['checked' => TRUE],
':input[name="options[element_wrapper_type_enable]"]' => ['checked' => TRUE],
],
],
];
$form['element_default_classes'] = [
'#title' => $this->t('Add default classes'),
'#default_value' => $this->options['element_default_classes'],
'#description' => $this->t('Use default Views classes to identify the field, field label and field content.'),
];
$form['alter'] = [
'#title' => $this->t('Rewrite results'),
'#type' => 'details',
];
if ($this->allowAdvancedRender()) {
$form['alter']['alter_text'] = [
'#title' => $this->t('Override the output of this field with custom text'),
'#default_value' => $this->options['alter']['alter_text'],
];
$form['alter']['text'] = [
'#title' => $this->t('Text'),
'#type' => 'textarea',
'#default_value' => $this->options['alter']['text'],
'#description' => $this->t('The text to display for this field. You may include HTML or <a href=":url">Twig</a>. You may enter data from this view as per the "Replacement patterns" below.', [':url' => CoreUrl::fromUri('http://twig.sensiolabs.org/documentation')->toString()]),
'#states' => [
'visible' => [
':input[name="options[alter][alter_text]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['make_link'] = [
'#title' => $this->t('Output this field as a custom link'),
'#default_value' => $this->options['alter']['make_link'],
];
$form['alter']['path'] = [
'#title' => $this->t('Link path'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['path'],
'#description' => $this->t('The Drupal path or absolute URL for this link. You may enter data from this view as per the "Replacement patterns" below.'),
'#states' => [
'visible' => [
':input[name="options[alter][make_link]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['absolute'] = [
'#title' => $this->t('Use absolute path'),
'#default_value' => $this->options['alter']['absolute'],
'#states' => [
'visible' => [
':input[name="options[alter][make_link]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['replace_spaces'] = [
'#title' => $this->t('Replace spaces with dashes'),
'#default_value' => $this->options['alter']['replace_spaces'],
'#states' => [
'visible' => [
':input[name="options[alter][make_link]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['external'] = [
'#title' => $this->t('External server URL'),
'#default_value' => $this->options['alter']['external'],
'#description' => $this->t("Links to an external server using a full URL: e.g. 'http://www.example.com' or 'www.example.com'."),
'#states' => [
'visible' => [
':input[name="options[alter][make_link]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['path_case'] = [
'#title' => $this->t('Transform the case'),
catch
committed
'#description' => $this->t('When printing URL paths, how to transform the case of the filter value.'),
'#states' => [
'visible' => [
':input[name="options[alter][make_link]"]' => ['checked' => TRUE],
],
],
'#options' => [
'none' => $this->t('No transform'),
'upper' => $this->t('Upper case'),
'lower' => $this->t('Lower case'),
'ucfirst' => $this->t('Capitalize first letter'),
'ucwords' => $this->t('Capitalize each word'),
],
'#default_value' => $this->options['alter']['path_case'],
];
$form['alter']['link_class'] = [
'#title' => $this->t('Link class'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['link_class'],
'#description' => $this->t('The CSS class to apply to the link.'),
'#states' => [
'visible' => [
':input[name="options[alter][make_link]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['alt'] = [
'#title' => $this->t('Title text'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['alt'],
'#description' => $this->t('Text to place as "title" text which most browsers display as a tooltip when hovering over the link.'),
'#states' => [
'visible' => [
':input[name="options[alter][make_link]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['rel'] = [
'#title' => $this->t('Rel Text'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['rel'],
'#description' => $this->t('Include Rel attribute for use in lightbox2 or other javascript utility.'),
'#states' => [
'visible' => [
':input[name="options[alter][make_link]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['prefix'] = [
'#title' => $this->t('Prefix text'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['prefix'],
'#description' => $this->t('Any text to display before this link. You may include HTML.'),
'#states' => [
'visible' => [
':input[name="options[alter][make_link]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['suffix'] = [
'#title' => $this->t('Suffix text'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['suffix'],
'#description' => $this->t('Any text to display after this link. You may include HTML.'),
'#states' => [
'visible' => [
':input[name="options[alter][make_link]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['target'] = [
'#title' => $this->t('Target'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['target'],
'#description' => $this->t("Target of the link, such as _blank, _parent or an iframe's name. This field is rarely used."),
'#states' => [
'visible' => [
':input[name="options[alter][make_link]"]' => ['checked' => TRUE],
],
],
];
// Get a list of the available fields and arguments for token replacement.
catch
committed
// Setup the tokens for fields.
$previous = $this->getPreviousFieldLabels();
$optgroup_arguments = (string) t('Arguments');
$optgroup_fields = (string) t('Fields');
catch
committed
foreach ($previous as $id => $label) {
$options[$optgroup_fields]["{{ $id }}"] = substr(strrchr($label, ":"), 2);
Angie Byron
committed
// Add the field to the list of options.
$options[$optgroup_fields]["{{ {$this->options['id']} }}"] = substr(strrchr($this->adminLabel(), ":"), 2);
catch
committed
Daniel Wehner
committed
foreach ($this->view->display_handler->getHandlers('argument') as $arg => $handler) {
$options[$optgroup_arguments]["{{ arguments.$arg }}"] = $this->t('@argument title', ['@argument' => $handler->adminLabel()]);
$options[$optgroup_arguments]["{{ raw_arguments.$arg }}"] = $this->t('@argument input', ['@argument' => $handler->adminLabel()]);
$this->documentSelfTokens($options[$optgroup_fields]);
Alex Pott
committed
$output = [];
$output[] = [
'#markup' => '<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.
if (!empty($options)) {
Alex Pott
committed
$output[] = [
'#markup' => '<p>' . $this->t("The following 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) {
if (!empty($options[$type])) {
$items = [];
foreach ($options[$type] as $key => $value) {
$items[] = $key . ' == ' . $value;
}
$item_list = [
catch
committed
'#theme' => 'item_list',
'#items' => $items,
];
Alex Pott
committed
$output[] = $item_list;
}
}
}
// This construct uses 'hidden' and not markup because process doesn't
// run. It also has an extra div because the dependency wants to hide
// the parent in situations like this, so we need a second div to
// make this work.
$form['alter']['help'] = [
'#type' => 'details',
'#title' => $this->t('Replacement patterns'),
Alex Pott
committed
'#value' => $output,
'#states' => [
'visible' => [
[
':input[name="options[alter][make_link]"]' => ['checked' => TRUE],
],
[
':input[name="options[alter][alter_text]"]' => ['checked' => TRUE],
],
[
':input[name="options[alter][more_link]"]' => ['checked' => TRUE],
],
],
],
];
$form['alter']['trim'] = [
'#title' => $this->t('Trim this field to a maximum number of characters'),
'#default_value' => $this->options['alter']['trim'],
];
$form['alter']['max_length'] = [
'#title' => $this->t('Maximum number of characters'),
'#type' => 'textfield',
'#default_value' => $this->options['alter']['max_length'],
'#states' => [
'visible' => [
':input[name="options[alter][trim]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['word_boundary'] = [
'#title' => $this->t('Trim only on a word boundary'),
'#description' => $this->t('If checked, this field be trimmed only on a word boundary. This is guaranteed to be the maximum characters stated or less. If there are no word boundaries this could trim a field to nothing.'),
'#default_value' => $this->options['alter']['word_boundary'],
'#states' => [
'visible' => [
':input[name="options[alter][trim]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['ellipsis'] = [
'#title' => $this->t('Add "…" at the end of trimmed text'),
'#default_value' => $this->options['alter']['ellipsis'],
'#states' => [
'visible' => [
':input[name="options[alter][trim]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['more_link'] = [
'#title' => $this->t('Add a read-more link if output is trimmed'),
'#default_value' => $this->options['alter']['more_link'],
'#states' => [
'visible' => [
':input[name="options[alter][trim]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['more_link_text'] = [
'#title' => $this->t('More link label'),
'#default_value' => $this->options['alter']['more_link_text'],
'#description' => $this->t('You may use the "Replacement patterns" above.'),
'#states' => [
'visible' => [
':input[name="options[alter][trim]"]' => ['checked' => TRUE],
':input[name="options[alter][more_link]"]' => ['checked' => TRUE],
],
],
];
$form['alter']['more_link_path'] = [
'#title' => $this->t('More link path'),
'#default_value' => $this->options['alter']['more_link_path'],
Jess
committed
'#description' => $this->t('This can be an internal Drupal path such as node/add or an external URL such as "https://www.drupal.org". You may use the "Replacement patterns" above.'),