Is there a way to only return the TOC #718
-
Hello ~ I've been struggling trying to figure out a way to get only the table of contents. I am using the Table of Contents extension and when return the markdown, the TOC is there. What I guess I'm wondering is if there's a way to passing the markdown and instead of returning everything along with the TOC is if it's possible to only return the TOC? Thanks so much for the help! |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
The Table of Contents is stored within a $toc = (new Query())
->where(Query::type(TableOfContents::class))
->findOne($document);
if ($toc === null) {
// No TOC is present
} else {
// FOUND IT!
} Or without using the fancy function getTOC(Document $document): ?TableOfContents
{
foreach ($document->iterator() as $node) {
if ($node instanceof TableOfContents) {
return $node;
}
}
return null;
} There are two main ways you could use this: Manually parse and render the TOCWith this approach, you have to wire some of the parsing/rendering logic yourself, but it's not too bad: $environment = new Environment();
// TODO: add any/all extensions you want
$document = (new MarkdownParser($environment))->parse($markdown);
$toc = (new Query())
->where(Query::type(TableOfContents::class))
->findOne($document);
if ($toc === null) {
// No TOC is present; you might want to handle this somehow
}
$tocHtml = (new HtmlRenderer($environment))->renderNodes([$toc]); Use an event listener to remove everything except the TOCIf you'd like to avoid that wiring, you can create a custom event listener that removes everything from the final class RemoveEverythingExceptTOCListener
{
public function __invoke(DocumentParsedEvent $event): void
{
$document = $event->getDocument();
$toc = (new Query())
->where(Query::type(TableOfContents::class))
->findOne($document);
if ($toc === null) {
// No TOC is present; remove all children
$event->getDocument()->replaceChildren([]);
} else {
$event->getDocument()->replaceChildren([$toc]);
}
}
} You can then register that with the environment: $environment->addEventListener(DocumentParsedEvent::class, new RemoveEverythingExceptTOCListener(), -200); // I'm not 100% sure about the priority here Or bundle it into a custom extension that registers it. I have not tested any of this code but I'm confident that it should at least be very very close to what you need. Hope that helps! |
Beta Was this translation helpful? Give feedback.
-
Thanks, works like a charm! Personally I'm also detaching the toc from the document because I also need the rest of the document. I'm doing something like this $converter = new GithubFlavoredMarkdownConverter($options);
$environment = $converter->getEnvironment();
foreach ($extensions as $extension) {
$environment->addExtension($extension);
}
$converted = $converter->convert($page->content);
$document = $converted->getDocument();
$toc = (new Query())
->where(Query::type(TableOfContents::class))
->findOne($document);
$toc->detach();
$renderer = new HtmlRenderer($environment);
$content = $renderer->renderDocument($document);
$toc = $renderer->renderNodes([$toc]); And that way I have my content I can put in the main container and the toc I can put aside, with different css and html structure. |
Beta Was this translation helpful? Give feedback.
The Table of Contents is stored within a
TableOfContents
node in the AST. There are a few ways to accomplish what you're looking to do, but all of them will center around locating that node. Given aDocument
object named$document
, you can grab the TOC with code like this:Or without using the fancy
Query
functionality: