You are here

public function CollapseText::processRecurseLevels in Collapse Text 8

Same name and namespace in other branches
  1. 2.0.x src/Plugin/Filter/CollapseText.php \Drupal\collapse_text\Plugin\Filter\CollapseText::processRecurseLevels()

Helper function to translate the flat levels array into a tree.

This function is recursive.

1 call to CollapseText::processRecurseLevels()
CollapseText::process in src/Plugin/Filter/CollapseText.php
Performs the filter processing.

File

src/Plugin/Filter/CollapseText.php, line 339

Class

CollapseText
Provides a filter to display Collapsible text blocks.

Namespace

Drupal\collapse_text\Plugin\Filter

Code

public function processRecurseLevels($string, $string_start, $string_end, $elements, $options) {
  $text_start = $string_start;
  $text_length = $string_end - $string_start;
  $child_start = $string_start;
  $child_end = $string_end;
  $slice_start = -1;

  // Find the first start element.
  $elt_start_found = FALSE;
  $elt_start = 0;
  while (!$elt_start_found and $elt_start < count($elements)) {
    if ($elements[$elt_start]['type'] == 'start') {
      $elt_start_found = TRUE;
    }
    else {
      $elt_start++;
    }
  }
  if ($elt_start_found) {

    // If there is an opening element,
    // set the text length to everything up to it.
    $text_length = $elements[$elt_start]['start'] - $string_start;
    $child_start = $elements[$elt_start]['end'];
    $slice_start = $elt_start + 1;
  }
  else {

    // Otherwise, return everything in this segment as a string.
    return [
      [
        'type' => 'text',
        'value' => substr($string, $text_start, $text_length),
      ],
    ];
  }

  // Find the next end element at the same level.
  $elt_end_found = FALSE;
  $elt_end = $elt_start;
  while (!$elt_end_found and $elt_end < count($elements)) {
    if ($elements[$elt_end]['type'] == 'end' and $elements[$elt_end]['level'] == $elements[$elt_start]['level']) {
      $elt_end_found = TRUE;
    }
    else {
      $elt_end++;
    }
  }
  if ($elt_end_found) {
    $child_end = $elements[$elt_end]['start'];
    $slice_length = $elt_end - $slice_start;
  }
  else {

    // There is a matching failure.
    // Try skipping the start element...
    if ($elt_start + 1 < count($elements)) {
      return $this
        ->processRecurseLevels($string, $string_start, $string_end, array_slice($elements, $elt_start + 1), $options);
    }
    else {

      // Fall back to just returning the string...
      // Reset the text length.
      $text_length = $string_end - $text_start;
      return [
        [
          'type' => 'text',
          'value' => substr($string, $text_start, $text_length),
        ],
      ];
    }
  }
  $parts = [];

  // Add the text before the opening element.
  $parts[] = [
    'type' => 'text',
    'value' => substr($string, $text_start, $text_length),
  ];

  // Add the child element.
  $parts[] = [
    'type' => 'child',
    'tag' => $elements[$elt_start]['tag'],
    'value' => $this
      ->processRecurseLevels($string, $child_start, $child_end, array_slice($elements, $slice_start, $slice_length), $options),
  ];

  // Tail recurse (which ideally could be optimized away,
  // although it won't be...) to handle any siblings.
  $parts = array_merge($parts, $this
    ->processRecurseLevels($string, $elements[$elt_end]['end'], $string_end, array_slice($elements, $elt_end), $options));

  // Return the result.
  return $parts;
}