mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-12 23:14:18 +01:00
N°3936 - Add user preference to choose backoffice theme
This commit is contained in:
@@ -58,22 +58,29 @@ class ThemeHandler
|
||||
/**
|
||||
* Return the ID of the theme currently defined in the config. file
|
||||
*
|
||||
* @deprecated 3.0.0, will be removed in 3.1, see N°3898
|
||||
* @return string
|
||||
*/
|
||||
public static function GetCurrentThemeId()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (is_null(MetaModel::GetConfig()))
|
||||
{
|
||||
static::GetCurrentUserThemeId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string ID of the theme currently defined in the config. file, which applies to all users by default. If non defined, fallback on the default one.
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetApplicationThemeId(): string
|
||||
{
|
||||
try {
|
||||
if (is_null(MetaModel::GetConfig())) {
|
||||
throw new CoreException('no config');
|
||||
}
|
||||
$sThemeId = MetaModel::GetConfig()->Get('backoffice_default_theme');
|
||||
}
|
||||
catch(CoreException $oCompileException)
|
||||
{
|
||||
catch (CoreException $oCompileException) {
|
||||
// Fallback on our default theme in case the config. is not available yet
|
||||
$aDefaultTheme = ThemeHandler::GetDefaultThemeInformation();
|
||||
$aDefaultTheme = ThemeHandler::GetDefaultThemeInformation();
|
||||
$sThemeId = $aDefaultTheme['name'];
|
||||
}
|
||||
|
||||
@@ -81,44 +88,115 @@ class ThemeHandler
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the absolute path of the compiled theme folder.
|
||||
*
|
||||
* @return string ID of the theme to use for the current user as per they preferences. If non defined, fallback on the app. theme ID.
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetCurrentUserThemeId(): string
|
||||
{
|
||||
try {
|
||||
$sThemeId = appUserPreferences::GetPref('backoffice_theme', null);
|
||||
}
|
||||
catch (Exception $oException) {
|
||||
$sThemeId = null;
|
||||
}
|
||||
|
||||
// Fallback on the app. theme
|
||||
if (is_null($sThemeId)) {
|
||||
$sThemeId = static::GetApplicationThemeId();
|
||||
}
|
||||
|
||||
return $sThemeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sThemeId
|
||||
*
|
||||
* @return string
|
||||
* @return string Label of the theme which is either a dict entry ('theme:<THEME_ID>') or the ID if no localized dict. entry found.
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetCompiledThemeFolderAbsolutePath($sThemeId)
|
||||
public static function GetThemeLabel(string $sThemeId): string
|
||||
{
|
||||
return APPROOT.'env-'.utils::GetCurrentEnvironment().'/branding/themes/'.$sThemeId.'/';
|
||||
$sDictEntryCode = 'theme:'.$sThemeId;
|
||||
$sDictEntryValue = Dict::S('theme:'.$sThemeId);
|
||||
|
||||
return ($sDictEntryCode === $sDictEntryValue) ? $sThemeId : $sDictEntryValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array Associative array of <THEME_ID> => <THEME_LABEL>, ordered by labels
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetAvailableThemes(): array
|
||||
{
|
||||
$aThemes = [];
|
||||
|
||||
foreach (glob(static::GetCompiledThemesFolderAbsolutePath().'/*') as $sPath) {
|
||||
if (is_dir($sPath)) {
|
||||
$sThemeId = basename($sPath);
|
||||
$sThemeLabel = static::GetThemeLabel($sThemeId);
|
||||
|
||||
$aThemes[$sThemeId] = $sThemeLabel;
|
||||
}
|
||||
}
|
||||
asort($aThemes);
|
||||
|
||||
return $aThemes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sThemeId
|
||||
*
|
||||
* @return bool True if $sThemeId is a valid theme that can be used.
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function IsValidTheme(string $sThemeId): bool
|
||||
{
|
||||
return array_key_exists($sThemeId, static::GetAvailableThemes());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Absolute path to the folder containing all the compiled themes
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetCompiledThemesFolderAbsolutePath(): string
|
||||
{
|
||||
return APPROOT.'env-'.utils::GetCurrentEnvironment().'/branding/themes/';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sThemeId
|
||||
*
|
||||
* @return string Absolute path to the folder containing the $sThemeId theme
|
||||
*/
|
||||
public static function GetCompiledThemeFolderAbsolutePath(string $sThemeId): string
|
||||
{
|
||||
return static::GetCompiledThemesFolderAbsolutePath().$sThemeId.'/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the absolute URL for the current theme CSS file
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function GetCurrentThemeUrl()
|
||||
public static function GetCurrentThemeUrl(): string
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
// Try to compile theme defined in the configuration
|
||||
$sThemeId = static::GetCurrentThemeId();
|
||||
$sThemeId = static::GetCurrentUserThemeId();
|
||||
static::CompileTheme($sThemeId);
|
||||
}
|
||||
catch(CoreException $oCompileException)
|
||||
{
|
||||
catch (CoreException $oCompileException) {
|
||||
// Fallback on our default theme (should always be compilable) in case the previous theme doesn't exists
|
||||
$aDefaultTheme = ThemeHandler::GetDefaultThemeInformation();
|
||||
$aDefaultTheme = ThemeHandler::GetDefaultThemeInformation();
|
||||
$sThemeId = $aDefaultTheme['name'];
|
||||
$sDefaultThemeDirPath = static::GetCompiledThemeFolderAbsolutePath($sThemeId);
|
||||
|
||||
|
||||
// Create our theme dir if it doesn't exist (XML theme node removed, renamed etc..)
|
||||
if(!is_dir($sDefaultThemeDirPath))
|
||||
{
|
||||
if (!is_dir($sDefaultThemeDirPath)) {
|
||||
SetupUtils::builddir($sDefaultThemeDirPath);
|
||||
}
|
||||
|
||||
|
||||
static::CompileTheme($sThemeId, false, "", $aDefaultTheme['parameters']);
|
||||
}
|
||||
|
||||
|
||||
@@ -371,3 +371,9 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Person:personal_info' => 'Personal information',
|
||||
'Person:notifiy' => 'Notification',
|
||||
));
|
||||
|
||||
// Themes
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'theme:fullmoon' => 'Full moon 🌕',
|
||||
'theme:test-red' => 'Test instance (Red)',
|
||||
));
|
||||
|
||||
@@ -381,3 +381,9 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Person:personal_info' => 'Informations personnelles',
|
||||
'Person:notifiy' => 'Notification',
|
||||
));
|
||||
|
||||
// Themes
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'theme:fullmoon' => 'Full moon 🌕',
|
||||
'theme:test-red' => 'Instance de test (Rouge)',
|
||||
));
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Preferences:Title' => 'Preferences',
|
||||
'UI:Preferences:UserInterface:Title' => 'User interface',
|
||||
'UI:Preferences:General:Title' => 'General',
|
||||
'UI:Preferences:General:Theme' => 'Theme',
|
||||
'UI:Preferences:General:Theme:DefaultThemeLabel' => '%1$s (default)',
|
||||
'UI:Preferences:Lists:Title' => 'Lists',
|
||||
'UI:Preferences:RichText:Title' => 'Rich text editor',
|
||||
'UI:Preferences:RichText:ToolbarState' => 'Toolbar default state',
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:Preferences:Title' => 'Préférences',
|
||||
'UI:Preferences:UserInterface:Title' => 'Interface utilisateur',
|
||||
'UI:Preferences:General:Title' => 'Général',
|
||||
'UI:Preferences:General:Theme' => 'Thême',
|
||||
'UI:Preferences:General:Theme:DefaultThemeLabel' => '%1$s (défaut)',
|
||||
'UI:Preferences:Lists:Title' => 'Listes',
|
||||
'UI:Preferences:RichText:Title' => 'Éditeur texte riche',
|
||||
'UI:Preferences:RichText:ToolbarState' => 'Affichage par défaut de la barre d\'outil',
|
||||
|
||||
@@ -76,10 +76,11 @@ function DisplayPreferences($oP)
|
||||
$oUISubmitButton = ButtonUIBlockFactory::MakeForPrimaryAction(Dict::S('UI:Button:Apply'), 'operation', 'apply_user_interface', true);
|
||||
$oUIToolbar->AddSubBlock($oUISubmitButton);
|
||||
|
||||
// Language
|
||||
$oLanguageFieldset = FieldSetUIBlockFactory::MakeStandard(Dict::S('UI:FavoriteLanguage'), 'ibo-fieldset-for-language-preferences');
|
||||
$oLanguageFieldset->AddSubBlock(GetLanguageFieldBlock());
|
||||
$oFirstColumn->AddSubBlock($oLanguageFieldset);
|
||||
// General
|
||||
$oGeneralFieldset = FieldSetUIBlockFactory::MakeStandard(Dict::S('UI:Preferences:General:Title'), 'ibo-fieldset-for-language-preferences');
|
||||
$oGeneralFieldset->AddSubBlock(GetLanguageFieldBlock());
|
||||
$oGeneralFieldset->AddSubBlock(GetThemeFieldBlock());
|
||||
$oFirstColumn->AddSubBlock($oGeneralFieldset);
|
||||
|
||||
// Lists
|
||||
$oListsFieldset = FieldSetUIBlockFactory::MakeStandard(Dict::S('UI:Preferences:Lists:Title'), 'ibo-fieldset-for-lists-preferences');
|
||||
@@ -467,7 +468,7 @@ function GetLanguageFieldBlock(): iUIBlock
|
||||
}
|
||||
ksort($aSortedLanguages);
|
||||
|
||||
$oSelect = SelectUIBlockFactory::MakeForSelectWithLabel('language', Dict::S('UI:Favorites:SelectYourLanguage'));
|
||||
$oSelect = SelectUIBlockFactory::MakeForSelectWithLabel('language', Dict::S('UI:FavoriteLanguage'));
|
||||
/** @var \Combodo\iTop\Application\UI\Base\Component\Input\Select $oSelectInput */
|
||||
$oSelectInput = $oSelect->GetInput();
|
||||
foreach ($aSortedLanguages as $sCode) {
|
||||
@@ -478,6 +479,33 @@ function GetLanguageFieldBlock(): iUIBlock
|
||||
return $oSelect;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Combodo\iTop\Application\UI\Base\iUIBlock
|
||||
* @since 3.0.0
|
||||
*/
|
||||
function GetThemeFieldBlock(): iUIBlock
|
||||
{
|
||||
$aAvailableThemes = ThemeHandler::GetAvailableThemes();
|
||||
|
||||
$oSelect = SelectUIBlockFactory::MakeForSelectWithLabel('theme', Dict::S('UI:Preferences:General:Theme'));
|
||||
/** @var \Combodo\iTop\Application\UI\Base\Component\Input\Select $oSelectInput */
|
||||
$oSelectInput = $oSelect->GetInput();
|
||||
foreach ($aAvailableThemes as $sCode => $sLabel) {
|
||||
if (MetaModel::GetConfig()->Get('demo_mode') && ($sCode !== ThemeHandler::GetApplicationThemeId())) {
|
||||
// Demo mode: only the current app. theme is listed in the available choices
|
||||
continue;
|
||||
}
|
||||
|
||||
$bSelected = ($sCode === ThemeHandler::GetCurrentUserThemeId());
|
||||
if (true === $bSelected) {
|
||||
$sLabel = Dict::Format('UI:Preferences:General:Theme:DefaultThemeLabel', $sLabel);
|
||||
}
|
||||
$oSelectInput->AddSubBlock(SelectOptionUIBlockFactory::MakeForSelectOption($sCode, $sLabel, $bSelected));
|
||||
}
|
||||
|
||||
return $oSelect;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Combodo\iTop\Application\UI\Base\iUIBlock
|
||||
* @throws \CoreException
|
||||
@@ -689,6 +717,12 @@ try {
|
||||
$oUser->DBUpdate();
|
||||
utils::PopArchiveMode();
|
||||
|
||||
// Theme
|
||||
$sThemeId = utils::ReadParam('theme', '');
|
||||
if (!empty($sThemeId) && ThemeHandler::IsValidTheme($sThemeId)) {
|
||||
appUserPreferences::SetPref('backoffice_theme', $sThemeId);
|
||||
}
|
||||
|
||||
// List
|
||||
$iDefaultPageSize = (int)utils::ReadParam('default_page_size', -1);
|
||||
if ($iDefaultPageSize > 0) {
|
||||
|
||||
Reference in New Issue
Block a user