Problem/Motivation

Surprised this isn't already part of this module but figured easy enough to create. Unfortunately i started by extending the existing TocBlockBase; which has errors with all of the classes it is implementing; so that was a bad place to start.

After i simply extended the core BlockBase this seemed to work. Going from the _view hook code in the README i see i can pass TOC and/or a modified version of my content (used to create the TOC).

This raises questions:

- of course i don't want to add a TOC block with my rewritten content into the layout of my content; then i end up with 2 copies of my content.
- but if i remove adding the content, the anchor links in the TOC don't go anywhere.

How is this expected to be done?

I see 2 options:
1. I need a fake duplicate view mode which is used to simply create the TOC and then the TOC block is placed in the real full_content view mode without any of the content used in the fake one. I am sure this will become problematic as the layout becomes more complex. Not to mention it is redundant.
2. seems like far more reasonable - i write extra js to addin anchor IDs to all the heading tags.

Option 2 sounds promising but wondering why that isn't at least an option here.

Steps to reproduce

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Comments

liquidcms created an issue. See original summary.

liquidcms’s picture

In case anyone comes looking for this, i wrote Block code to allow placing a TOC block. It also uses JQ to go through the page headings and add IDs to them so that the anchor links work.

namespace Drupal\ssc_custom\Plugin\Block;

use Drupal\Core\Block\Annotation\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\node\Entity\Node;
use Drupal\toc_api\Entity\TocType;

/**
 * Provides a TOC block using the TOC API.
 *
 * @Block(
 *  id = "toc_block",
 *  admin_label = @Translation("SSC TOC"),
 * )
 */
class TOCBlock extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function blockForm($form, FormStateInterface $form_state) {
    // Get list of available TOC Types.
    $storage = \Drupal::entityTypeManager()->getStorage('toc_type');
    $ids = \Drupal::entityQuery('toc_type')->execute();

    $form = parent::blockForm($form, $form_state);
    $form['toc_type'] = [
      '#type' => 'select',
      '#title' => $this->t('TOC Type'),
      '#options' => $ids,
      '#description' => $this->t('Select the type of TOC to be displayed in this block.'),
      '#default_value' => $this->configuration['toc_type'],
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function blockSubmit($form, FormStateInterface $form_state) {
    parent::blockSubmit($form, $form_state);
    $this->configuration['toc_type'] = $form_state->getValue('toc_type');
  }

  /**
   * {@inheritdoc}
   */
  public function build() {
    // Required to break block - render page - insert block - render page, etc, etc.
    $full_content = &drupal_static('toc_block_full');
    if (!empty($full_content)) return [];

    // Get TOC Type configured for this Block.
    $toc_type_id = $this->configuration['toc_type'];

    $node = \Drupal::routeMatch()->getParameter('node');
    if (!($node instanceof \Drupal\node\NodeInterface)) {
      return [
        '#markup' => $this->t('TOC (%type): Not a NODE page', [
          '%type' => $toc_type_id,
          ]),
      ];
    }

    $view_builder = \Drupal::entityTypeManager()->getViewBuilder('node');
    $full_content = $view_builder->view($node, 'full');
    $content = (string) \Drupal::service('renderer')->render($full_content);

    // Get TOC options for this Type.
    /** @var \Drupal\toc_api\TocTypeInterface $toc_type */
    $toc_type = TocType::load($toc_type_id);
    $options = ($toc_type) ? $toc_type->getOptions() : [];

    // Create a TOC instance using the TOC manager.
    /** @var \Drupal\toc_api\TocManagerInterface $toc_manager */
    $toc_manager = \Drupal::service('toc_api.manager');
    /** @var \Drupal\toc_api\TocInterface $toc */
    $toc = $toc_manager->create('toc_filter', $content, $options);

    // If the TOC is visible (ie has more than X headers), replace the body
    // render array with the TOC and update body content using the TOC builder.
    if ($toc->isVisible()) {
      /** @var \Drupal\toc_api\TocBuilderInterface $toc_builder */
      $toc_builder = \Drupal::service('toc_api.builder');
      $build = [
        'toc' => $toc_builder->buildToc($toc),
        //'content' => $toc_builder->buildContent($toc),
      ];
    }

    return $build;
  }

}

and JS for only h2/h3 (could be done recursively)

    // Add IDs for TOC H2/H3
    var level1 = 0;
    var level2 = 0;
    $('.toc-section h2, .toc-section h3').each(function() {
      if ($(this).prop('tagName') === 'H2') {
        level1++;
        level2 = 0;
        $(this).attr('id', 'section-' + level1 + '-' + level2);
      }
      else {
        level2++;
        $(this).attr('id', 'section-' + level1 + '-' + level2);
      }
    });
joseph.olstad’s picture

Version: 8.x-1.1 » 2.0.x-dev

Please note, 1.x is no longer supported

All MRs should now be reviewed and made to go against 2.0.x if still needed

joseph.olstad’s picture

Not sure if this helps but there is a contrib module implementing the toc_api

The module is called Toc Twig Filter

#3521657: Contrib Modules using TOC API

joseph.olstad’s picture

also, the footnotes module

https://www.drupal.org/project/footnotes

which actually implements the toc_filter module more specifically , it's the toc_filter module which directly implements the toc_api module.

joseph.olstad’s picture

Good example @liquidcms, this could go into the module README.md or documentation page.

joseph.olstad’s picture

Status: Active » Fixed

Put this into our README.md

  • joseph.olstad committed 5bdc23b9 on 2.0.x
    Issue #3264056 by joseph.olstad, liquidcms: Markdown syntax fix.
    

  • joseph.olstad committed febc3149 on 2.0.x
    Issue #3264056 by liquidcms, joseph.olstad: Cleanup the example.
    

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

joseph.olstad’s picture