Repository navigation
Let controllers add the active theme's stylesheets and scripts - #243
Merged
ralflang merged 2 commits intoOct 14, 2026
Merged
Conversation
…and scripts Controllers that build their own <head> (settings and admin pages) had no theme-aware call available on AssetCollector, so they hardcoded "/default/screen.css" and never loaded the scripts a theme declares in $theme_scripts. Add ViewModeConfigurator::addThemeStylesheets(), which resolves the user's theme and walks the existing CSS cascade (default first, the theme layered on top, only files that exist), and addThemeScripts(), which does what DesktopChromeRenderer already does with discoverTheme(). The new constructor arguments are optional, so the methods are no-ops when the services are unavailable.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Non-Horde asset requests can ignore the user's Horde-scoped theme preference.
1 open finding
What changed in this PR
Enables modern controllers to load theme assets through existing discovery services, addressing part of #233 alongside the companion controller changes and #242.
Changes:
- Adds helpers for themed stylesheets and scripts.
- Wires optional CSS discovery and theme resolution dependencies into the configurator.
| File | Description |
|---|---|
| src/PageOutput/ViewModeConfiguratorFactory.php | Injects CSS discovery and theme resolution services. |
| src/PageOutput/ViewModeConfigurator.php | Adds theme-aware stylesheet and script registration. |
🧠 Review effort: Balanced
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
|
|
||
| return $uid === '' | ||
| ? 'default' | ||
| : $this->themeResolver->resolve($uid, null, $app); |
Contributor
Author
There was a problem hiding this comment.
Right, the theme is a Horde-wide preference and the chrome renderer factories resolve it in the horde scope. resolveTheme() now does the same; $app is only used to discover that app's files. Fixed in a737985. No runtime test here (PHPUnit isn't available on my setup), php -l only.
The theme preference is Horde-wide. Resolving it in the app's scope ignored a user's horde:theme for non-horde apps, as the chrome renderer factories already avoid.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Part of #233 (cause 1). Companion PR in horde/base switches the controllers
over to these methods.
Controllers that assemble their own
<head>throughPageComposerandAssetCollector— the settings and admin pages — had no theme-aware callavailable:
AssetCollector::addStylesheet()only takes a URL. So theyhardcoded
$themesUri . '/default/screen.css', and they never loaded thescripts a theme declares in
$theme_scripts.Change
Two methods on
ViewModeConfigurator, the service that already fills theAssetCollectorwith core scripts:addThemeStylesheets(AssetCollector, array $files, string $app = 'horde')resolves the user's theme through
ThemeResolverand walks the existingCssDiscoverercascade: default first, the theme layered on top, onlyfiles that exist. A theme that does not ship
settings.csskeepsinheriting the default one.
addThemeScripts(AssetCollector, string $app = 'horde')does whatDesktopChromeRendereralready does withJsDiscoverer::discoverTheme().Meant to be called after
configure(), since theme scripts may rely onprototype.jsandhorde.js.The two new constructor arguments are optional and default to
null; themethods are no-ops if the services are unavailable.
Note on hook-based themes
As discussed on #233, this only helps self-contained themes. A theme that
gets its CSS custom properties from the
cssfiles()hook still rendersunstyled on these pages, since nothing on the modern stack calls the hook
(
CssHookProviderhas no implementation yet). We moved our own communitytheme to load its foundations itself for that reason.
Testing
On a FRAMEWORK_6_0 install, with this PR, the horde/base companion and
#242 applied, and a self-contained theme selected: the OAuth account,
OAuth provider and API registry pages render with the user's theme, load
its
$theme_scripts, and the theme's display preferences apply.#242 is needed for the end result: without it the theme is resolved for a
user id carrying a leading
\0, and falls back to the server default.