Skip to content

Commit 04d21c8

Browse files
committed
Includes: Started foundations for new include tag parser
1 parent 22a9cf1 commit 04d21c8

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
namespace BookStack\Entities\Tools;
4+
5+
use BookStack\Util\HtmlDocument;
6+
use Closure;
7+
8+
class PageIncludeParser
9+
{
10+
protected static string $includeTagRegex = "/{{@\s?([0-9].*?)}}/";
11+
12+
public function __construct(
13+
protected string $pageHtml,
14+
protected Closure $pageContentForId,
15+
) {
16+
}
17+
18+
public function parse(): string
19+
{
20+
$html = new HtmlDocument($this->pageHtml);
21+
22+
$includeHosts = $html->queryXPath("//body//*[contains(text(), '{{@')]");
23+
$node = $includeHosts->item(0);
24+
25+
// One of the direct child textnodes of the "$includeHosts" should be
26+
// the one with the include tag within.
27+
$textNode = $node->childNodes->item(0);
28+
29+
// TODO:
30+
// Hunt down the specific text nodes with matches
31+
// Split out tag text node from rest of content
32+
// Fetch tag content->
33+
// If range or top-block: delete tag text node, [Promote to top-block], delete old top-block if empty
34+
// If inline: Replace current text node with new text or elem
35+
// !! "Range" or "inline" status should come from tag parser and content fetcher, not guessed direct from content
36+
// since we could have a range of inline elements
37+
38+
// [Promote to top-block]
39+
// Tricky operation.
40+
// Can throw in before or after current top-block depending on relative position
41+
// Could [Split] top-block but complex past a single level depth.
42+
// Maybe [Split] if one level depth, otherwise default to before/after block
43+
// Should work for the vast majority of cases, and not for those which would
44+
// technically be invalid in-editor anyway.
45+
46+
// [Split]
47+
// Copy original top-block node type and attrs (apart from ID)
48+
// Move nodes after promoted tag-node into copy
49+
// Insert copy after original (after promoted top-block eventually)
50+
51+
// Notes: May want to eventually parse through backwards, which should avoid issues
52+
// in changes affecting the next tag, where tags may be in the same/adjacent nodes.
53+
54+
55+
return $html->getBodyInnerHtml();
56+
}
57+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace Tests\Unit;
4+
5+
use BookStack\Entities\Tools\PageIncludeParser;
6+
use Tests\TestCase;
7+
8+
class PageIncludeParserTest extends TestCase
9+
{
10+
public function test_include_simple_inline_text()
11+
{
12+
$this->runParserTest(
13+
'<p>{{@45#content}}</p>',
14+
['45' => '<p id="content">Testing</p>'],
15+
'<p>Testing</p>',
16+
);
17+
}
18+
19+
public function test_include_simple_inline_text_with_existing_siblings()
20+
{
21+
$this->runParserTest(
22+
'<p>{{@45#content}} <strong>Hi</strong>there!</p>',
23+
['45' => '<p id="content">Testing</p>'],
24+
'<p>Testing <strong>Hi</strong>there!</p>',
25+
);
26+
}
27+
28+
public function test_include_simple_inline_text_within_other_text()
29+
{
30+
$this->runParserTest(
31+
'<p>Hello {{@45#content}}there!</p>',
32+
['45' => '<p id="content">Testing</p>'],
33+
'<p>Hello Testingthere!</p>',
34+
);
35+
}
36+
37+
protected function runParserTest(string $html, array $contentById, string $expected)
38+
{
39+
$parser = new PageIncludeParser($html, function (int $id) use ($contentById) {
40+
return $contentById[strval($id)] ?? null;
41+
});
42+
43+
$result = $parser->parse();
44+
$this->assertEquals($expected, $result);
45+
}
46+
}

0 commit comments

Comments
 (0)