Merge pull request #3698 from BookStackApp/include_theme_event
Added "page_include_parse" theme event
This commit is contained in:
		
						commit
						b9941e8e61
					
				| 
						 | 
				
			
			@ -5,6 +5,8 @@ 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -372,23 +374,30 @@ class PageContent
 | 
			
		|||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Find page and skip this if page not found
 | 
			
		||||
            // Find page to use, and default replacement to empty string for non-matches.
 | 
			
		||||
            /** @var ?Page $matchedPage */
 | 
			
		||||
            $matchedPage = Page::visible()->find($pageId);
 | 
			
		||||
            if ($matchedPage === null) {
 | 
			
		||||
                $html = str_replace($fullMatch, '', $html);
 | 
			
		||||
                continue;
 | 
			
		||||
            $replacement = '';
 | 
			
		||||
 | 
			
		||||
            if ($matchedPage && count($splitInclude) === 1) {
 | 
			
		||||
                // If we only have page id, just insert all page html and continue.
 | 
			
		||||
                $replacement = $matchedPage->html;
 | 
			
		||||
            } else if ($matchedPage && count($splitInclude) > 1) {
 | 
			
		||||
                // Otherwise, if our include tag defines a section, load that specific content
 | 
			
		||||
                $innerContent = $this->fetchSectionOfPage($matchedPage, $splitInclude[1]);
 | 
			
		||||
                $replacement = trim($innerContent);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // If we only have page id, just insert all page html and continue.
 | 
			
		||||
            if (count($splitInclude) === 1) {
 | 
			
		||||
                $html = str_replace($fullMatch, $matchedPage->html, $html);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            $themeReplacement = Theme::dispatch(
 | 
			
		||||
                ThemeEvents::PAGE_INCLUDE_PARSE,
 | 
			
		||||
                $includeId,
 | 
			
		||||
                $replacement,
 | 
			
		||||
                clone $this->page,
 | 
			
		||||
                $matchedPage ? (clone $matchedPage) : null,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Create and load HTML into a document
 | 
			
		||||
            $innerContent = $this->fetchSectionOfPage($matchedPage, $splitInclude[1]);
 | 
			
		||||
            $html = str_replace($fullMatch, trim($innerContent), $html);
 | 
			
		||||
            // Perform the content replacement
 | 
			
		||||
            $html = str_replace($fullMatch, $themeReplacement ?? $replacement, $html);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $html;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,8 @@
 | 
			
		|||
 | 
			
		||||
namespace BookStack\Theming;
 | 
			
		||||
 | 
			
		||||
use BookStack\Entities\Models\Page;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The ThemeEvents used within BookStack.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -60,8 +62,7 @@ class ThemeEvents
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Commonmark environment configure.
 | 
			
		||||
     * Provides the commonmark library environment for customization
 | 
			
		||||
     * before it's used to render markdown content.
 | 
			
		||||
     * Provides the commonmark library environment for customization before it's used to render markdown content.
 | 
			
		||||
     * If the listener returns a non-null value, that will be used as an environment instead.
 | 
			
		||||
     *
 | 
			
		||||
     * @param \League\CommonMark\ConfigurableEnvironmentInterface $environment
 | 
			
		||||
| 
						 | 
				
			
			@ -69,6 +70,21 @@ class ThemeEvents
 | 
			
		|||
     */
 | 
			
		||||
    const COMMONMARK_ENVIRONMENT_CONFIGURE = 'commonmark_environment_configure';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Page include parse event.
 | 
			
		||||
     * Runs when a page include tag is being parsed, typically when page content is being processed for viewing.
 | 
			
		||||
     * Provides the "include tag" reference string, the default BookStack replacement content for the tag,
 | 
			
		||||
     * the current page being processed, and the page that's being referenced by the include tag.
 | 
			
		||||
     * The referenced page may be null where the page does not exist or where permissions prevent visibility.
 | 
			
		||||
     * If the listener returns a non-null value, that will be used as the replacement HTML content instead.
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $tagReference
 | 
			
		||||
     * @param string $replacementHTML
 | 
			
		||||
     * @param Page   $currentPage
 | 
			
		||||
     * @param ?Page  $referencedPage
 | 
			
		||||
     */
 | 
			
		||||
    const PAGE_INCLUDE_PARSE = 'page_include_parse';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Web before middleware action.
 | 
			
		||||
     * Runs before the request is handled but after all other middleware apart from those
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -214,6 +214,36 @@ class ThemeTest extends TestCase
 | 
			
		|||
        $this->assertEquals($book->id, $args[1]->id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_event_page_include_parse()
 | 
			
		||||
    {
 | 
			
		||||
        /** @var Page $page */
 | 
			
		||||
        /** @var Page $otherPage */
 | 
			
		||||
        $page = Page::query()->first();
 | 
			
		||||
        $otherPage = Page::query()->where('id', '!=', $page->id)->first();
 | 
			
		||||
        $otherPage->html = '<p id="bkmrk-cool">This is a really cool section</p>';
 | 
			
		||||
        $page->html = "<p>{{@{$otherPage->id}#bkmrk-cool}}</p>";
 | 
			
		||||
        $page->save();
 | 
			
		||||
        $otherPage->save();
 | 
			
		||||
 | 
			
		||||
        $args = [];
 | 
			
		||||
        $callback = function (...$eventArgs) use (&$args) {
 | 
			
		||||
            $args = $eventArgs;
 | 
			
		||||
            return '<strong>Big & content replace surprise!</strong>';
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Theme::listen(ThemeEvents::PAGE_INCLUDE_PARSE, $callback);
 | 
			
		||||
        $resp = $this->asEditor()->get($page->getUrl());
 | 
			
		||||
        $this->withHtml($resp)->assertElementContains('.page-content strong', 'Big & content replace surprise!');
 | 
			
		||||
 | 
			
		||||
        $this->assertCount(4, $args);
 | 
			
		||||
        $this->assertEquals($otherPage->id . '#bkmrk-cool', $args[0]);
 | 
			
		||||
        $this->assertEquals('This is a really cool section', $args[1]);
 | 
			
		||||
        $this->assertTrue($args[2] instanceof Page);
 | 
			
		||||
        $this->assertTrue($args[3] instanceof Page);
 | 
			
		||||
        $this->assertEquals($page->id, $args[2]->id);
 | 
			
		||||
        $this->assertEquals($otherPage->id, $args[3]->id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test_add_social_driver()
 | 
			
		||||
    {
 | 
			
		||||
        Theme::addSocialDriver('catnet', [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue