1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-07-28 17:02:04 +03:00

Includes: Added back support for parse theme event

Managed to do this in an API-compatible way although resuling output may
differ due to new dom handling in general, although user content is used
inline to remain as comptable as possible.
This commit is contained in:
Dan Brown
2023-11-27 21:38:43 +00:00
parent b569827114
commit 652d5417bf
7 changed files with 106 additions and 35 deletions

View File

@ -5,10 +5,13 @@ namespace BookStack\Entities\Tools;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Tools\Markdown\MarkdownToHtml;
use BookStack\Exceptions\ImageUploadException;
use BookStack\Facades\Theme;
use BookStack\Theming\ThemeEvents;
use BookStack\Uploads\ImageRepo;
use BookStack\Uploads\ImageService;
use BookStack\Util\HtmlContentFilter;
use BookStack\Util\HtmlDocument;
use Closure;
use DOMElement;
use DOMNode;
use DOMNodeList;
@ -280,18 +283,11 @@ class PageContent
}
$doc = new HtmlDocument($html);
$contentProvider = function (int $id) use ($blankIncludes) {
if ($blankIncludes) {
return '';
}
return Page::visible()->find($id)->html ?? '';
};
$contentProvider = $this->getContentProviderClosure($blankIncludes);
$parser = new PageIncludeParser($doc, $contentProvider);
$nodesAdded = 1;
for ($includeDepth = 0; $includeDepth < 1 && $nodesAdded !== 0; $includeDepth++) {
$nodesAdded = 1;
for ($includeDepth = 0; $includeDepth < 3 && $nodesAdded !== 0; $includeDepth++) {
$nodesAdded = $parser->parse();
}
@ -308,6 +304,39 @@ class PageContent
return $doc->getBodyInnerHtml();
}
/**
* Get the closure used to fetch content for page includes.
*/
protected function getContentProviderClosure(bool $blankIncludes): Closure
{
$contextPage = $this->page;
return function (PageIncludeTag $tag) use ($blankIncludes, $contextPage): PageIncludeContent {
if ($blankIncludes) {
return PageIncludeContent::fromHtmlAndTag('', $tag);
}
$matchedPage = Page::visible()->find($tag->getPageId());
$content = PageIncludeContent::fromHtmlAndTag($matchedPage->html ?? '', $tag);
if (Theme::hasListeners(ThemeEvents::PAGE_INCLUDE_PARSE)) {
$themeReplacement = Theme::dispatch(
ThemeEvents::PAGE_INCLUDE_PARSE,
$tag->tagContent,
$content->toHtml(),
clone $contextPage,
$matchedPage ? (clone $matchedPage) : null,
);
if ($themeReplacement !== null) {
$content = PageIncludeContent::fromInlineHtml(strval($themeReplacement));
}
}
return $content;
};
}
/**
* Parse the headers on the page to get a navigation menu.
*/

View File

@ -10,47 +10,53 @@ class PageIncludeContent
protected static array $topLevelTags = ['table', 'ul', 'ol', 'pre'];
/**
* @var DOMNode[]
* @param DOMNode[] $contents
* @param bool $isInline
*/
protected array $contents = [];
protected bool $isTopLevel = false;
public function __construct(
string $html,
PageIncludeTag $tag,
protected array $contents,
protected bool $isInline,
) {
$this->parseHtml($html, $tag);
}
protected function parseHtml(string $html, PageIncludeTag $tag): void
public static function fromHtmlAndTag(string $html, PageIncludeTag $tag): self
{
if (empty($html)) {
return;
return new self([], true);
}
$doc = new HtmlDocument($html);
$sectionId = $tag->getSectionId();
if (!$sectionId) {
$this->contents = [...$doc->getBodyChildren()];
$this->isTopLevel = true;
return;
$contents = [...$doc->getBodyChildren()];
return new self($contents, false);
}
$section = $doc->getElementById($sectionId);
if (!$section) {
return;
return new self([], true);
}
$isTopLevel = in_array(strtolower($section->nodeName), static::$topLevelTags);
$this->isTopLevel = $isTopLevel;
$this->contents = $isTopLevel ? [$section] : [...$section->childNodes];
$contents = $isTopLevel ? [$section] : [...$section->childNodes];
return new self($contents, !$isTopLevel);
}
public static function fromInlineHtml(string $html): self
{
if (empty($html)) {
return new self([], true);
}
$doc = new HtmlDocument($html);
return new self([...$doc->getBodyChildren()], true);
}
public function isInline(): bool
{
return !$this->isTopLevel;
return $this->isInline;
}
public function isEmpty(): bool
@ -65,4 +71,15 @@ class PageIncludeContent
{
return $this->contents;
}
public function toHtml(): string
{
$html = '';
foreach ($this->contents as $content) {
$html .= $content->ownerDocument->saveHTML($content);
}
return $html;
}
}

View File

@ -19,6 +19,9 @@ class PageIncludeParser
*/
protected array $toCleanup = [];
/**
* @param Closure(PageIncludeTag $tag): PageContent $pageContentForId
*/
public function __construct(
protected HtmlDocument $doc,
protected Closure $pageContentForId,
@ -35,8 +38,8 @@ class PageIncludeParser
$tags = $this->locateAndIsolateIncludeTags();
foreach ($tags as $tag) {
$htmlContent = $this->pageContentForId->call($this, $tag->getPageId());
$content = new PageIncludeContent($htmlContent, $tag);
/** @var PageIncludeContent $content */
$content = $this->pageContentForId->call($this, $tag);
if (!$content->isInline()) {
$parentP = $this->getParentParagraph($tag->domNode);