diff --git a/app/Config/app.php b/app/Config/app.php index 741c7fd19..065845f96 100755 --- a/app/Config/app.php +++ b/app/Config/app.php @@ -115,6 +115,7 @@ return [ BookStack\Providers\TranslationServiceProvider::class, // BookStack custom service providers + BookStack\Providers\ThemeServiceProvider::class, BookStack\Providers\AuthServiceProvider::class, BookStack\Providers\AppServiceProvider::class, BookStack\Providers\BroadcastServiceProvider::class, @@ -186,6 +187,7 @@ return [ 'Views' => BookStack\Facades\Views::class, 'Images' => BookStack\Facades\Images::class, 'Permissions' => BookStack\Facades\Permissions::class, + 'Theme' => BookStack\Facades\Theme::class, ], diff --git a/app/Entities/Tools/PageContent.php b/app/Entities/Tools/PageContent.php index 62982f4ad..82499cdf2 100644 --- a/app/Entities/Tools/PageContent.php +++ b/app/Entities/Tools/PageContent.php @@ -2,6 +2,8 @@ use BookStack\Entities\Models\Page; use BookStack\Entities\Tools\Markdown\CustomStrikeThroughExtension; +use BookStack\Facades\Theme; +use BookStack\Theming\ThemeEvents; use DOMDocument; use DOMNodeList; use DOMXPath; @@ -53,6 +55,7 @@ class PageContent $environment->addExtension(new TableExtension()); $environment->addExtension(new TaskListExtension()); $environment->addExtension(new CustomStrikeThroughExtension()); + $environment = Theme::dispatch(ThemeEvents::COMMONMARK_ENVIRONMENT_CONFIGURE, $environment) ?? $environment; $converter = new CommonMarkConverter([], $environment); return $converter->convertToHtml($markdown); } diff --git a/app/Facades/Theme.php b/app/Facades/Theme.php new file mode 100644 index 000000000..9b96e2ed2 --- /dev/null +++ b/app/Facades/Theme.php @@ -0,0 +1,16 @@ +app->singleton('permissions', function () { return $this->app->make(PermissionService::class); }); + + $this->app->singleton('theme', function () { + return $this->app->make(ThemeService::class); + }); } } diff --git a/app/Providers/ThemeServiceProvider.php b/app/Providers/ThemeServiceProvider.php new file mode 100644 index 000000000..c41a15af0 --- /dev/null +++ b/app/Providers/ThemeServiceProvider.php @@ -0,0 +1,34 @@ +app->singleton(ThemeService::class, function ($app) { + return new ThemeService; + }); + } + + /** + * Bootstrap services. + * + * @return void + */ + public function boot() + { + $themeService = $this->app->make(ThemeService::class); + $themeService->readThemeActions(); + $themeService->dispatch(ThemeEvents::APP_BOOT, $this->app); + } +} diff --git a/app/Theming/ThemeEvents.php b/app/Theming/ThemeEvents.php new file mode 100644 index 000000000..753b13d91 --- /dev/null +++ b/app/Theming/ThemeEvents.php @@ -0,0 +1,32 @@ +listeners[$event])) { + $this->listeners[$event] = []; + } + + $this->listeners[$event][] = $action; + } + + /** + * Dispatch the given event name. + * Runs any registered listeners for that event name, + * passing all additional variables to the listener action. + * + * If a callback returns a non-null value, this method will + * stop and return that value itself. + * @return mixed + */ + public function dispatch(string $event, ...$args) + { + foreach ($this->listeners[$event] ?? [] as $action) { + $result = call_user_func_array($action, $args); + if (!is_null($result)) { + return $result; + } + } + return null; + } + + /** + * Read any actions from the set theme path if the 'functions.php' file exists. + */ + public function readThemeActions() + { + $themeActionsFile = theme_path('functions.php'); + if (file_exists($themeActionsFile)) { + require $themeActionsFile; + } + } +} \ No newline at end of file