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:
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user