You are here

public function BlockParser::proceed in Gutenberg 8.2

Processes the next token from the input document.

This is the "next step" function that essentially takes a token as its input and decides what to do with that token before descending deeper into a nested block tree or continuing along the document or breaking out of a level of nesting.

@since 3.8.0 @internal

Return value

bool Whether to proceed eating more tokens.

1 call to BlockParser::proceed()
BlockParser::parse in src/Parser/BlockParser.php
Parses a document and returns a list of block structures.

File

src/Parser/BlockParser.php, line 119

Class

BlockParser
Class BlockParser.

Namespace

Drupal\gutenberg\Parser

Code

public function proceed() {
  $next_token = $this
    ->nextToken();
  list($token_type, $block_name, $attrs, $start_offset, $token_length) = $next_token;
  $stack_depth = count($this->stack);

  // We may have some HTML soup before the next block.
  $leading_html_start = $start_offset > $this->offset ? $this->offset : NULL;
  switch ($token_type) {
    case 'no-more-tokens':

      // If not in a block then flush output.
      if (0 === $stack_depth) {
        $this
          ->addFreeform();
        return FALSE;
      }

      /*
       * Otherwise we have a problem
       * This is an error
       *
       * we have options
       * - treat it all as freeform text
       * - assume an implicit closer (easiest when not nesting)
       */

      // For the easy case we'll assume an implicit closer.
      if (1 === $stack_depth) {
        $this
          ->addBlockFromStack();
        return FALSE;
      }

      /*
       * for the nested case where it's more difficult we'll
       * have to assume that multiple closers are missing
       * and so we'll collapse the whole stack piecewise
       */
      while (0 < count($this->stack)) {
        $this
          ->addBlockFromStack();
      }
      return FALSE;
    case 'void-block':

      /*
       * easy case is if we stumbled upon a void block
       * in the top-level of the document
       */
      if (0 === $stack_depth) {
        if (isset($leading_html_start)) {
          $this
            ->addToOutput((array) $this
            ->freeform(substr($this->document, $leading_html_start, $start_offset - $leading_html_start)));
        }
        $this
          ->addToOutput((array) new BlockParserBlock($block_name, $attrs, [], '', []));
        $this->offset = $start_offset + $token_length;
        return TRUE;
      }

      // Otherwise we found an inner block.
      $this
        ->addInnerBlock(new BlockParserBlock($block_name, $attrs, [], '', []), $start_offset, $token_length);
      $this->offset = $start_offset + $token_length;
      return TRUE;
    case 'block-opener':

      // Track all newly-opened blocks on the stack.
      $this->stack[] = new BlockParserFrame(new BlockParserBlock($block_name, $attrs, [], '', []), $start_offset, $token_length, $start_offset + $token_length, $leading_html_start);
      $this->offset = $start_offset + $token_length;
      return TRUE;
    case 'block-closer':

      /*
       * if we're missing an opener we're in trouble
       * This is an error
       */
      if (0 === $stack_depth) {

        /*
         * we have options
         * - assume an implicit opener
         * - assume _this_ is the opener
         * - give up and close out the document
         */
        $this
          ->addFreeform();
        return FALSE;
      }

      // If we're not nesting then this is easy - close the block.
      if (1 === $stack_depth) {
        $this
          ->addBlockFromStack($start_offset);
        $this->offset = $start_offset + $token_length;
        return TRUE;
      }

      /*
       * otherwise we're nested and we have to close out the current
       * block and add it as a new innerBlock to the parent
       */
      $stack_top = array_pop($this->stack);
      $html = substr($this->document, $stack_top->prevOffset, $start_offset - $stack_top->prevOffset);
      $stack_top->block->innerHTML .= $html;
      $stack_top->block->innerContent[] = $html;
      $stack_top->prevOffset = $start_offset + $token_length;
      $this
        ->addInnerBlock($stack_top->block, $stack_top->tokenStart, $stack_top->tokenLength, $start_offset + $token_length);
      $this->offset = $start_offset + $token_length;
      return TRUE;
    default:

      // This is an error.
      $this
        ->addFreeform();
      return FALSE;
  }
}