You are here

public function TextWithExpandCollapseButtonsFormatter::viewElements in Formatter Suite 8

Builds a renderable array for a field value.

Parameters

\Drupal\Core\Field\FieldItemListInterface $items: The field values to be rendered.

string $langcode: The language that should be used to render the field.

Return value

array A renderable array for $items, as an array of child elements keyed by consecutive numeric indexes starting from 0.

Overrides FormatterInterface::viewElements

File

src/Plugin/Field/FieldFormatter/TextWithExpandCollapseButtonsFormatter.php, line 208

Class

TextWithExpandCollapseButtonsFormatter
Formats text with expand/collapse buttons to show more/less.

Namespace

Drupal\formatter_suite\Plugin\Field\FieldFormatter

Code

public function viewElements(FieldItemListInterface $items, $langCode) {

  //
  // The $items array has a list of items to format. We need to return
  // an array with identical indexing and corresponding render elements
  // for those items.
  if ($items
    ->isEmpty() === TRUE) {
    return [];
  }

  // Get current settings.
  $collapsedHeight = $this
    ->getSetting('collapsedHeight');
  $animationDuration = $this
    ->getSetting('animationDuration');
  $collapseButtonLabel = $this
    ->getSetting('collapseButtonLabel');
  $expandButtonLabel = $this
    ->getSetting('expandButtonLabel');

  // Security: The button labels are entered by an administrator.
  // They may legitimately include HTML entities and minor HTML, but
  // they should not include dangerous HTML. For instance, it is
  // legitimate to include <span class="blah"> to style the label,
  // or to include <img src="blah"> to add an icon image. However,
  // it is not legitimate to add <style> or <script>.
  //
  // So, Xss::filterAdmin() is used here to get rid of the most
  // dangerous HTML, like <style> and <script>.
  //
  // We'd like the admin-entered text to be translated, if a site
  // is using that Drupal feature. However, simply calling t() will
  // not quite work. Drupal.org builds translatable text tables by
  // scanning the source code for calls to t() with literal strings.
  // Since the admin-entered button label text here is not a literal
  // string, it will not be found by that scan. This means it will
  // not be in automatically-generated translation tables and t()
  // will not necessarily do anything.
  //
  // Calling t() anyway will still do the translation table lookup.
  // If a site has MANUALLY entered the text into their own translation
  // tables, then translation will take place. Otherwise the text will
  // be used as-is.
  //
  // We'd like to call $this->t() here to do the translation, but the
  // various Drupal style checkers complain, even though this is a
  // legitimate use. To avoid those complaints, we get the string
  // translator from the StringTranslationTrait included in the
  // FormatterBase parent class. Calling the translate() method
  // directly dodges the style checkers.
  $translator = $this
    ->getStringTranslation();
  $collapseButtonLabel = $translator
    ->translate(Xss::filterAdmin($collapseButtonLabel));
  $expandButtonLabel = $translator
    ->translate(Xss::filterAdmin($expandButtonLabel));

  // Security: The animation duration is entered by an administrator.
  // It should be a simple integer, with no other characters, HTML, or
  // HTML entities.
  //
  // By parsing it as an integer, we ignore anything else and remove
  // any security issues.
  $animationDuration = intval($animationDuration);

  // Security: The collapse height is entered by an administrator.
  // It should be a number followed by CSS units, such as "px", "pt",
  // or "em". It should not contain HTML or HTML entities.
  //
  // If integer parsing of the string yields a zero, then the string
  // is assumed to be empty or invalid and collapsing is disabled.
  // Otherwise the string is santized using an Html escape filter
  // that escapes all HTML and HTML entities. If the admin enters these,
  // the resulting string is not likely to work as a collapse height
  // and the Javascript will not get a meaningful result, but it will
  // still be safe.
  $collapsedHeight = Html::escape($collapsedHeight);
  $hasCollapsedHeight = TRUE;
  if (empty($collapsedHeight) === TRUE || $collapsedHeight === "0" || (int) $collapsedHeight === 0) {
    $hasCollapsedHeight = FALSE;
  }

  // If there is no collapsed height, show text full height.
  $build = [];
  if ($hasCollapsedHeight === FALSE) {
    foreach ($items as $delta => $item) {
      $build[$delta] = [
        '#type' => 'processed_text',
        '#text' => $item->value,
        '#format' => $item->format,
        '#langcode' => $item
          ->getLangcode(),
      ];
    }
    return $build;
  }

  // Nest the text, add buttons, and add a behavior script.
  foreach ($items as $delta => $item) {
    $build[$delta] = [
      '#type' => 'container',
      '#attributes' => [
        'class' => [
          'formatter_suite-text-with-expand-collapse-buttons',
        ],
      ],
      '#attached' => [
        'library' => [
          'formatter_suite/formatter_suite.usage',
          'formatter_suite/formatter_suite.text_with_expand_collapse_buttons',
        ],
      ],
      'text' => [
        '#type' => 'container',
        '#attributes' => [
          'class' => [
            'formatter_suite-text',
          ],
          'data-formatter_suite-collapsed-height' => $collapsedHeight,
          'data-formatter_suite-animation-duration' => $animationDuration,
        ],
        'processedtext' => [
          '#type' => 'processed_text',
          '#text' => $item->value,
          '#format' => $item->format,
          '#langcode' => $item
            ->getLangcode(),
        ],
      ],
      'collapse' => [
        '#type' => 'html_tag',
        '#tag' => 'div',
        '#value' => '<a href="#">' . $collapseButtonLabel . '</a>',
        '#attributes' => [
          'class' => [
            'formatter_suite-text-collapse-button',
          ],
          'style' => 'display: none',
        ],
      ],
      'expand' => [
        '#type' => 'html_tag',
        '#tag' => 'div',
        '#value' => '<a href="#">' . $expandButtonLabel . '</a>',
        '#attributes' => [
          'class' => [
            'formatter_suite-text-expand-button',
          ],
          'style' => 'display: none',
        ],
      ],
    ];
  }
  return $build;
}