]> BookStack Code Mirror - bookstack/commitdiff
Started backend theme system
authorDan Brown <redacted>
Tue, 16 Mar 2021 17:14:03 +0000 (17:14 +0000)
committerDan Brown <redacted>
Tue, 16 Mar 2021 17:14:03 +0000 (17:14 +0000)
Allows customization of back-end components via event-driven handling
from the theme folder.

app/Config/app.php
app/Entities/Tools/PageContent.php
app/Facades/Theme.php [new file with mode: 0644]
app/Providers/CustomFacadeProvider.php
app/Providers/ThemeServiceProvider.php [new file with mode: 0644]
app/Theming/ThemeEvents.php [new file with mode: 0644]
app/Theming/ThemeService.php [new file with mode: 0644]

index 741c7fd1991b41c4e3e66d0973bebcb02f938222..065845f961258f0fc04d0c9c46d18ddacc50f7f4 100755 (executable)
@@ -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,
 
     ],
 
index 62982f4ad5dbbb3ea2524b83f7ed028da4c3971c..82499cdf2d28030f5930e5f4e94fff11f8a3728a 100644 (file)
@@ -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 (file)
index 0000000..9b96e2e
--- /dev/null
@@ -0,0 +1,16 @@
+<?php namespace BookStack\Facades;
+
+use Illuminate\Support\Facades\Facade;
+
+class Theme extends Facade
+{
+    /**
+     * Get the registered name of the component.
+     *
+     * @return string
+     */
+    protected static function getFacadeAccessor()
+    {
+        return 'theme';
+    }
+}
index 0918c0aba9f594adb90eff4f29ca71b459b4b9f1..f203f0fda592f5e27e7099b851395207bf8de71b 100644 (file)
@@ -5,6 +5,7 @@ namespace BookStack\Providers;
 use BookStack\Actions\ActivityService;
 use BookStack\Actions\ViewService;
 use BookStack\Auth\Permissions\PermissionService;
+use BookStack\Theming\ThemeService;
 use BookStack\Uploads\ImageService;
 use Illuminate\Support\ServiceProvider;
 
@@ -42,5 +43,9 @@ class CustomFacadeProvider extends ServiceProvider
         $this->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 (file)
index 0000000..c41a15a
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+
+namespace BookStack\Providers;
+
+use BookStack\Theming\ThemeEvents;
+use BookStack\Theming\ThemeService;
+use Illuminate\Support\ServiceProvider;
+
+class ThemeServiceProvider extends ServiceProvider
+{
+    /**
+     * Register services.
+     *
+     * @return void
+     */
+    public function register()
+    {
+        $this->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 (file)
index 0000000..753b13d
--- /dev/null
@@ -0,0 +1,32 @@
+<?php namespace BookStack\Theming;
+
+/**
+ * The ThemeEvents used within BookStack.
+ *
+ * This file details the events that BookStack may fire via the custom
+ * theme system, including event names, parameters and expected return types.
+ *
+ * This system is regarded as semi-stable.
+ * We'll look to fix issues with it or migrate old event types but
+ * events and their signatures may change in new versions of BookStack.
+ * We'd advise testing any usage of these events upon upgrade.
+ */
+class ThemeEvents
+{
+    /**
+     * Application boot-up.
+     * After main services are registered.
+     * @param \BookStack\Application $app
+     */
+    const APP_BOOT = 'app_boot';
+
+    /**
+     * Commonmark environment configure.
+     * Provides the commonmark library environment for customization
+     * before its 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
+     * @returns \League\CommonMark\ConfigurableEnvironmentInterface|null
+     */
+    const COMMONMARK_ENVIRONMENT_CONFIGURE = 'commonmark_environment_configure';
+}
\ No newline at end of file
diff --git a/app/Theming/ThemeService.php b/app/Theming/ThemeService.php
new file mode 100644 (file)
index 0000000..cc68de1
--- /dev/null
@@ -0,0 +1,50 @@
+<?php namespace BookStack\Theming;
+
+class ThemeService
+{
+    protected $listeners = [];
+
+    /**
+     * Listen to a given custom theme event,
+     * setting up the action to be ran when the event occurs.
+     */
+    public function listen(string $event, callable $action)
+    {
+        if (!isset($this->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
Morty Proxy This is a proxified and sanitized view of the page, visit original site.