mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
ENHANCEMENT Allow user theme selection through SiteConfig, falling back to SSViewer::set_theme() as a default if there are none selected
MINOR Unit tests for SSViewer::current_theme() and SiteConfig::getAvailableThemes() (from r98110) git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@102597 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
334b83dd23
commit
21299ba686
@ -153,7 +153,7 @@ class ManifestBuilder {
|
|||||||
*
|
*
|
||||||
* @param string $baseDir Optional: Absolute path to theme directory for testing e.g. "/Users/sharvey/Sites/test24/themes"
|
* @param string $baseDir Optional: Absolute path to theme directory for testing e.g. "/Users/sharvey/Sites/test24/themes"
|
||||||
* @param boolean $includeSubThemes If set to TRUE, sub-themes such as "blackcandy_blog" are included too
|
* @param boolean $includeSubThemes If set to TRUE, sub-themes such as "blackcandy_blog" are included too
|
||||||
* @return array indexed array of theme directories
|
* @return array Listing of theme directories
|
||||||
*/
|
*/
|
||||||
public static function get_themes($baseDir = null, $includeSubThemes = false) {
|
public static function get_themes($baseDir = null, $includeSubThemes = false) {
|
||||||
// If no base directory specified, the default is the project root
|
// If no base directory specified, the default is the project root
|
||||||
@ -168,7 +168,7 @@ class ManifestBuilder {
|
|||||||
if(strpos($file, '_') === false) {
|
if(strpos($file, '_') === false) {
|
||||||
$include = true;
|
$include = true;
|
||||||
}
|
}
|
||||||
if($include) $themes[] = $file;
|
if($include) $themes[$file] = $file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir($handle);
|
closedir($handle);
|
||||||
|
@ -87,6 +87,11 @@ class SSViewer {
|
|||||||
*/
|
*/
|
||||||
protected static $current_theme = null;
|
protected static $current_theme = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected static $cached_theme = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a template from a string instead of a .ss file
|
* Create a template from a string instead of a .ss file
|
||||||
*
|
*
|
||||||
@ -106,8 +111,18 @@ class SSViewer {
|
|||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
static function current_theme() {
|
static function current_theme($cached = true) {
|
||||||
return self::$current_theme;
|
if($cached && self::$cached_theme) {
|
||||||
|
// First case is to return the cached user theme so we don't requery SiteConfig again
|
||||||
|
return self::$cached_theme;
|
||||||
|
} else {
|
||||||
|
// Need to refresh the cache from the SiteConfig
|
||||||
|
$theme = SiteConfig::current_site_config()->Theme;
|
||||||
|
self::$cached_theme = $theme;
|
||||||
|
}
|
||||||
|
// Fall back to the default SSViewer::set_theme() behaviour
|
||||||
|
if(!$theme) $theme = self::$current_theme;
|
||||||
|
return $theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,13 +156,13 @@ class SSViewer {
|
|||||||
else $templateFolder = null;
|
else $templateFolder = null;
|
||||||
|
|
||||||
// Use the theme template if available
|
// Use the theme template if available
|
||||||
if(self::$current_theme && isset($_TEMPLATE_MANIFEST[$template]['themes'][self::$current_theme])) {
|
if(self::current_theme() && isset($_TEMPLATE_MANIFEST[$template]['themes'][self::current_theme()])) {
|
||||||
$this->chosenTemplates = array_merge(
|
$this->chosenTemplates = array_merge(
|
||||||
$_TEMPLATE_MANIFEST[$template]['themes'][self::$current_theme],
|
$_TEMPLATE_MANIFEST[$template]['themes'][self::current_theme()],
|
||||||
$this->chosenTemplates
|
$this->chosenTemplates
|
||||||
);
|
);
|
||||||
|
|
||||||
if(isset($_GET['debug_request'])) Debug::message("Found template '$template' from main theme '" . self::$current_theme . "': " . var_export($_TEMPLATE_MANIFEST[$template]['themes'][self::$current_theme], true));
|
if(isset($_GET['debug_request'])) Debug::message("Found template '$template' from main theme '" . self::current_theme() . "': " . var_export($_TEMPLATE_MANIFEST[$template]['themes'][self::current_theme()], true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fall back to unthemed base templates
|
// Fall back to unthemed base templates
|
||||||
@ -257,8 +272,8 @@ class SSViewer {
|
|||||||
*/
|
*/
|
||||||
public static function getTemplateFileByType($identifier, $type) {
|
public static function getTemplateFileByType($identifier, $type) {
|
||||||
global $_TEMPLATE_MANIFEST;
|
global $_TEMPLATE_MANIFEST;
|
||||||
if(self::$current_theme && isset($_TEMPLATE_MANIFEST[$identifier]['themes'][self::$current_theme][$type])) {
|
if(self::current_theme() && isset($_TEMPLATE_MANIFEST[$identifier]['themes'][self::current_theme()][$type])) {
|
||||||
return $_TEMPLATE_MANIFEST[$identifier]['themes'][self::$current_theme][$type];
|
return $_TEMPLATE_MANIFEST[$identifier]['themes'][self::current_theme()][$type];
|
||||||
} else if(isset($_TEMPLATE_MANIFEST[$identifier][$type])){
|
} else if(isset($_TEMPLATE_MANIFEST[$identifier][$type])){
|
||||||
return $_TEMPLATE_MANIFEST[$identifier][$type];
|
return $_TEMPLATE_MANIFEST[$identifier][$type];
|
||||||
} else {
|
} else {
|
||||||
|
@ -17,6 +17,7 @@ class SiteConfig extends DataObject {
|
|||||||
static $db = array(
|
static $db = array(
|
||||||
"Title" => "Varchar(255)",
|
"Title" => "Varchar(255)",
|
||||||
"Tagline" => "Varchar(255)",
|
"Tagline" => "Varchar(255)",
|
||||||
|
"Theme" => "Varchar(255)",
|
||||||
"CanViewType" => "Enum('Anyone, LoggedInUsers, OnlyTheseUsers', 'Anyone')",
|
"CanViewType" => "Enum('Anyone, LoggedInUsers, OnlyTheseUsers', 'Anyone')",
|
||||||
"CanEditType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')",
|
"CanEditType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')",
|
||||||
"CanCreateTopLevelType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')",
|
"CanCreateTopLevelType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')",
|
||||||
@ -28,6 +29,12 @@ class SiteConfig extends DataObject {
|
|||||||
"CreateTopLevelGroups" => "Group"
|
"CreateTopLevelGroups" => "Group"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
protected static $disabled_themes = array();
|
||||||
|
|
||||||
|
public static function disable_theme($theme) {
|
||||||
|
self::$disabled_themes[$theme] = $theme;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the fields that are sent to the CMS. In
|
* Get the fields that are sent to the CMS. In
|
||||||
* your decorators: updateEditFormFields(&$fields)
|
* your decorators: updateEditFormFields(&$fields)
|
||||||
@ -39,7 +46,8 @@ class SiteConfig extends DataObject {
|
|||||||
new TabSet("Root",
|
new TabSet("Root",
|
||||||
new Tab('Main',
|
new Tab('Main',
|
||||||
$titleField = new TextField("Title", _t('SiteConfig.SITETITLE', "Site title")),
|
$titleField = new TextField("Title", _t('SiteConfig.SITETITLE', "Site title")),
|
||||||
$taglineField = new TextField("Tagline", _t('SiteConfig.SITETAGLINE', "Site Tagline/Slogan"))
|
$taglineField = new TextField("Tagline", _t('SiteConfig.SITETAGLINE', "Site Tagline/Slogan")),
|
||||||
|
new DropdownField("Theme", _t('SiteConfig.THEME', 'Theme'), $this->getAvailableThemes(), '', null, _t('SiteConfig.DEFAULTTHEME', '(Use default theme)'))
|
||||||
),
|
),
|
||||||
new Tab('Access',
|
new Tab('Access',
|
||||||
new HeaderField('WhoCanViewHeader', _t('SiteConfig.VIEWHEADER', "Who can view pages on this site?"), 2),
|
new HeaderField('WhoCanViewHeader', _t('SiteConfig.VIEWHEADER', "Who can view pages on this site?"), 2),
|
||||||
@ -90,6 +98,19 @@ class SiteConfig extends DataObject {
|
|||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all available themes that haven't been marked as disabled.
|
||||||
|
* @param string $baseDir Optional alternative theme base directory for testing
|
||||||
|
* @return array of theme directory names
|
||||||
|
*/
|
||||||
|
public function getAvailableThemes($baseDir = null) {
|
||||||
|
$themes = ManifestBuilder::get_themes($baseDir);
|
||||||
|
foreach(self::$disabled_themes as $theme) {
|
||||||
|
if(isset($themes[$theme])) unset($themes[$theme]);
|
||||||
|
}
|
||||||
|
return $themes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the actions that are sent to the CMS. In
|
* Get the actions that are sent to the CMS. In
|
||||||
* your decorators: updateEditFormActions(&$actions)
|
* your decorators: updateEditFormActions(&$actions)
|
||||||
|
@ -395,6 +395,25 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
|
|||||||
return Controller::join_links($base, '/', $action);
|
return Controller::join_links($base, '/', $action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the absolute URL for this page on the Live site.
|
||||||
|
*/
|
||||||
|
public function getAbsoluteLiveLink($includeStageEqualsLive = true) {
|
||||||
|
$live = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $this->ID);
|
||||||
|
|
||||||
|
if($live) {
|
||||||
|
$link = $live->AbsoluteLink();
|
||||||
|
|
||||||
|
if($includeStageEqualsLive) {
|
||||||
|
$link .= '?stage=Live';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $link;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a CSS identifier generated from this page's link.
|
* Return a CSS identifier generated from this page's link.
|
||||||
*
|
*
|
||||||
|
@ -37,15 +37,17 @@ table.CMSList thead th {
|
|||||||
background-repeat: repeat-x;
|
background-repeat: repeat-x;
|
||||||
background-position: left bottom;
|
background-position: left bottom;
|
||||||
background-color: #ebeadb;
|
background-color: #ebeadb;
|
||||||
height: 24px;
|
|
||||||
border-right: 1px solid #aca899;
|
border-right: 1px solid #aca899;
|
||||||
border-left: 1px solid #ffffff;
|
border-left: 1px solid #ffffff;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 3px;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.TableField thead th span,
|
table.TableField thead th span,
|
||||||
.TableListField table.data thead th span {
|
.TableListField table.data thead th span {
|
||||||
display: block;
|
font-size: 12px;
|
||||||
float: left;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
table.TableField thead th a,
|
table.TableField thead th a,
|
||||||
@ -57,8 +59,6 @@ table.CMSList thead th a {
|
|||||||
table.TableField thead th span.sortLink,
|
table.TableField thead th span.sortLink,
|
||||||
.TableListField table.data thead th span.sortLink,
|
.TableListField table.data thead th span.sortLink,
|
||||||
table.CMSList thead th span.sortLink {
|
table.CMSList thead th span.sortLink {
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +123,7 @@ HTML;
|
|||||||
$field = new TreeMultiselectField_Readonly($this->name, $this->title, $this->sourceObject, $this->keyField, $this->labelField);
|
$field = new TreeMultiselectField_Readonly($this->name, $this->title, $this->sourceObject, $this->keyField, $this->labelField);
|
||||||
$field->addExtraClass($this->extraClass());
|
$field->addExtraClass($this->extraClass());
|
||||||
$field->setForm($this->form);
|
$field->setForm($this->form);
|
||||||
|
$field->setValue($this->value);
|
||||||
return $field;
|
return $field;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,15 +17,15 @@ TableListField.prototype = {
|
|||||||
rules['#'+this.id+' th'] = {
|
rules['#'+this.id+' th'] = {
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
var sortLinks = $$('span.sortLinkHidden a', this);
|
var sortLinks = $$('span.sortLinkHidden a', this);
|
||||||
if(sortLinks) Element.hide(sortLinks[0]);
|
if(sortLinks) sortLinks[0].style.visibility = 'hidden';
|
||||||
},
|
},
|
||||||
onmouseover: function(e) {
|
onmouseover: function(e) {
|
||||||
var sortLinks = $$('span.sortLinkHidden a', this);
|
var sortLinks = $$('span.sortLinkHidden a', this);
|
||||||
if(sortLinks) Element.show(sortLinks[0]);
|
if(sortLinks) sortLinks[0].style.visibility = 'visible';
|
||||||
},
|
},
|
||||||
onmouseout: function(e) {
|
onmouseout: function(e) {
|
||||||
var sortLinks = $$('span.sortLinkHidden a', this);
|
var sortLinks = $$('span.sortLinkHidden a', this);
|
||||||
if(sortLinks) Element.hide(sortLinks[0]);
|
if(sortLinks) sortLinks[0].style.visibility = 'hidden';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,17 +18,16 @@
|
|||||||
<a href="$SortLink">$Title</a>
|
<a href="$SortLink">$Title</a>
|
||||||
</span>
|
</span>
|
||||||
<span class="sortLink <% if SortBy %><% else %>sortLinkHidden<% end_if %>">
|
<span class="sortLink <% if SortBy %><% else %>sortLinkHidden<% end_if %>">
|
||||||
<a href="$SortLink"">
|
|
||||||
<% if SortDirection = desc %>
|
<% if SortDirection = desc %>
|
||||||
<img src="cms/images/bullet_arrow_down.png" alt="<% _t('SORTDESC', 'Sort in descending order') %>" />
|
<a href="$SortLink"><img src="cms/images/bullet_arrow_down.png" alt="<% _t('SORTDESC', 'Sort in descending order') %>" /></a>
|
||||||
<% else %>
|
<% else %>
|
||||||
<img src="cms/images/bullet_arrow_up.png" alt="<% _t('SORTASC', 'Sort in ascending order') %>" />
|
<a href="$SortLink"><img src="cms/images/bullet_arrow_up.png" alt="<% _t('SORTASC', 'Sort in ascending order') %>" /></a>
|
||||||
<% end_if %>
|
<% end_if %>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
<% else %>
|
<% else %>
|
||||||
$Title
|
<span>$Title</span>
|
||||||
<% end_if %>
|
<% end_if %>
|
||||||
</th>
|
</th>
|
||||||
<% end_control %>
|
<% end_control %>
|
||||||
|
@ -140,15 +140,15 @@ class ManifestBuilderTest extends SapphireTest {
|
|||||||
mkdir($testThemeBaseDir . $ds . 'darkshades_blog');
|
mkdir($testThemeBaseDir . $ds . 'darkshades_blog');
|
||||||
|
|
||||||
$this->assertEquals(array(
|
$this->assertEquals(array(
|
||||||
'blackcandy',
|
'blackcandy' => 'blackcandy',
|
||||||
'darkshades'
|
'darkshades' => 'darkshades'
|
||||||
), ManifestBuilder::get_themes($testThemeBaseDir), 'Our test theme directory contains 2 themes');
|
), ManifestBuilder::get_themes($testThemeBaseDir), 'Our test theme directory contains 2 themes');
|
||||||
|
|
||||||
$this->assertEquals(array(
|
$this->assertEquals(array(
|
||||||
'blackcandy',
|
'blackcandy' => 'blackcandy',
|
||||||
'blackcandy_blog',
|
'blackcandy_blog' => 'blackcandy_blog',
|
||||||
'darkshades',
|
'darkshades' => 'darkshades',
|
||||||
'darkshades_blog'
|
'darkshades_blog' => 'darkshades_blog'
|
||||||
), ManifestBuilder::get_themes($testThemeBaseDir, true), 'Our test theme directory contains 2 themes and 2 sub-themes');
|
), ManifestBuilder::get_themes($testThemeBaseDir, true), 'Our test theme directory contains 2 themes and 2 sub-themes');
|
||||||
|
|
||||||
// Remove all the test themes we created
|
// Remove all the test themes we created
|
||||||
|
@ -1,6 +1,30 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
class SSViewerTest extends SapphireTest {
|
class SSViewerTest extends SapphireTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link SSViewer::current_theme()} for different behaviour
|
||||||
|
* of user defined themes via {@link SiteConfig} and default theme
|
||||||
|
* when no user themes are defined.
|
||||||
|
*/
|
||||||
|
function testCurrentTheme() {
|
||||||
|
$config = SiteConfig::current_site_config();
|
||||||
|
$oldTheme = $config->Theme;
|
||||||
|
$config->Theme = '';
|
||||||
|
$config->write();
|
||||||
|
|
||||||
|
SSViewer::set_theme('mytheme');
|
||||||
|
$this->assertEquals('mytheme', SSViewer::current_theme(), 'Current theme is the default - user has not defined one');
|
||||||
|
|
||||||
|
$config->Theme = 'myusertheme';
|
||||||
|
$config->write();
|
||||||
|
$this->assertEquals('myusertheme', SSViewer::current_theme(), 'Current theme is a user defined one');
|
||||||
|
|
||||||
|
// Set the theme back to the original
|
||||||
|
$config->Theme = $oldTheme;
|
||||||
|
$config->write();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that a template without a <head> tag still renders.
|
* Test that a template without a <head> tag still renders.
|
||||||
*/
|
*/
|
||||||
|
@ -54,5 +54,26 @@ class SiteConfigTest extends SapphireTest {
|
|||||||
$this->assertTrue($pageEn->canEdit($translatorEn));
|
$this->assertTrue($pageEn->canEdit($translatorEn));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testAvailableThemes() {
|
||||||
|
$config = SiteConfig::current_site_config();
|
||||||
|
$ds = DIRECTORY_SEPARATOR;
|
||||||
|
$testThemeBaseDir = TEMP_FOLDER . $ds . 'test-themes';
|
||||||
|
|
||||||
|
if(file_exists($testThemeBaseDir)) Filesystem::removeFolder($testThemeBaseDir);
|
||||||
|
mkdir($testThemeBaseDir);
|
||||||
|
mkdir($testThemeBaseDir . $ds . 'blackcandy');
|
||||||
|
mkdir($testThemeBaseDir . $ds . 'blackcandy_blog');
|
||||||
|
mkdir($testThemeBaseDir . $ds . 'darkshades');
|
||||||
|
mkdir($testThemeBaseDir . $ds . 'darkshades_blog');
|
||||||
|
|
||||||
|
$themes = $config->getAvailableThemes($testThemeBaseDir);
|
||||||
|
$this->assertContains('blackcandy', $themes, 'Test themes contain blackcandy theme');
|
||||||
|
$this->assertContains('darkshades', $themes, 'Test themes contain darkshades theme');
|
||||||
|
|
||||||
|
SiteConfig::disable_theme('darkshades');
|
||||||
|
$themes = $config->getAvailableThemes($testThemeBaseDir);
|
||||||
|
$this->assertFalse(in_array('darkshades', $themes), 'Darkshades was disabled - it is no longer available');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
Loading…
x
Reference in New Issue
Block a user