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:
Ingo Schommer 2010-04-13 02:13:12 +00:00
parent 334b83dd23
commit 21299ba686
11 changed files with 131 additions and 31 deletions

View File

@ -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 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) {
// If no base directory specified, the default is the project root
@ -168,7 +168,7 @@ class ManifestBuilder {
if(strpos($file, '_') === false) {
$include = true;
}
if($include) $themes[] = $file;
if($include) $themes[$file] = $file;
}
}
closedir($handle);

View File

@ -87,6 +87,11 @@ class SSViewer {
*/
protected static $current_theme = null;
/**
* @var string
*/
protected static $cached_theme = null;
/**
* Create a template from a string instead of a .ss file
*
@ -106,8 +111,18 @@ class SSViewer {
/**
* @return string
*/
static function current_theme() {
return self::$current_theme;
static function current_theme($cached = true) {
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;
// 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(
$_TEMPLATE_MANIFEST[$template]['themes'][self::$current_theme],
$_TEMPLATE_MANIFEST[$template]['themes'][self::current_theme()],
$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
@ -257,8 +272,8 @@ class SSViewer {
*/
public static function getTemplateFileByType($identifier, $type) {
global $_TEMPLATE_MANIFEST;
if(self::$current_theme && isset($_TEMPLATE_MANIFEST[$identifier]['themes'][self::$current_theme][$type])) {
return $_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];
} else if(isset($_TEMPLATE_MANIFEST[$identifier][$type])){
return $_TEMPLATE_MANIFEST[$identifier][$type];
} else {

View File

@ -17,6 +17,7 @@ class SiteConfig extends DataObject {
static $db = array(
"Title" => "Varchar(255)",
"Tagline" => "Varchar(255)",
"Theme" => "Varchar(255)",
"CanViewType" => "Enum('Anyone, LoggedInUsers, OnlyTheseUsers', 'Anyone')",
"CanEditType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')",
"CanCreateTopLevelType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')",
@ -28,6 +29,12 @@ class SiteConfig extends DataObject {
"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
* your decorators: updateEditFormFields(&$fields)
@ -39,7 +46,8 @@ class SiteConfig extends DataObject {
new TabSet("Root",
new Tab('Main',
$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 HeaderField('WhoCanViewHeader', _t('SiteConfig.VIEWHEADER', "Who can view pages on this site?"), 2),
@ -89,6 +97,19 @@ class SiteConfig extends DataObject {
$this->extend('updateEditFormFields', $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

View File

@ -395,6 +395,25 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
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.
*

View File

@ -37,15 +37,17 @@ table.CMSList thead th {
background-repeat: repeat-x;
background-position: left bottom;
background-color: #ebeadb;
height: 24px;
border-right: 1px solid #aca899;
border-left: 1px solid #ffffff;
white-space: nowrap;
padding: 3px;
font-size: 12px;
text-align: left;
}
table.TableField thead th span,
.TableListField table.data thead th span {
display: block;
float: left;
font-size: 12px;
}
table.TableField thead th a,
@ -57,8 +59,6 @@ table.CMSList thead th a {
table.TableField thead th span.sortLink,
.TableListField table.data thead th span.sortLink,
table.CMSList thead th span.sortLink {
width: 16px;
height: 16px;
overflow: hidden;
}

View File

@ -123,6 +123,7 @@ HTML;
$field = new TreeMultiselectField_Readonly($this->name, $this->title, $this->sourceObject, $this->keyField, $this->labelField);
$field->addExtraClass($this->extraClass());
$field->setForm($this->form);
$field->setValue($this->value);
return $field;
}
}

View File

@ -17,15 +17,15 @@ TableListField.prototype = {
rules['#'+this.id+' th'] = {
initialize: function() {
var sortLinks = $$('span.sortLinkHidden a', this);
if(sortLinks) Element.hide(sortLinks[0]);
if(sortLinks) sortLinks[0].style.visibility = 'hidden';
},
onmouseover: function(e) {
var sortLinks = $$('span.sortLinkHidden a', this);
if(sortLinks) Element.show(sortLinks[0]);
if(sortLinks) sortLinks[0].style.visibility = 'visible';
},
onmouseout: function(e) {
var sortLinks = $$('span.sortLinkHidden a', this);
if(sortLinks) Element.hide(sortLinks[0]);
if(sortLinks) sortLinks[0].style.visibility = 'hidden';
}
};

View File

@ -18,17 +18,16 @@
<a href="$SortLink">$Title</a>
</span>
<span class="sortLink <% if SortBy %><% else %>sortLinkHidden<% end_if %>">
<a href="$SortLink"">
<% if SortDirection = desc %>
<img src="cms/images/bullet_arrow_down.png" alt="<% _t('SORTDESC', 'Sort in descending order') %>" />
<% else %>
<img src="cms/images/bullet_arrow_up.png" alt="<% _t('SORTASC', 'Sort in ascending order') %>" />
<% end_if %>
<% if SortDirection = desc %>
<a href="$SortLink"><img src="cms/images/bullet_arrow_down.png" alt="<% _t('SORTDESC', 'Sort in descending order') %>" /></a>
<% else %>
<a href="$SortLink"><img src="cms/images/bullet_arrow_up.png" alt="<% _t('SORTASC', 'Sort in ascending order') %>" /></a>
<% end_if %>
</a>
&nbsp;
</span>
<% else %>
$Title
<span>$Title</span>
<% end_if %>
</th>
<% end_control %>

View File

@ -140,15 +140,15 @@ class ManifestBuilderTest extends SapphireTest {
mkdir($testThemeBaseDir . $ds . 'darkshades_blog');
$this->assertEquals(array(
'blackcandy',
'darkshades'
'blackcandy' => 'blackcandy',
'darkshades' => 'darkshades'
), ManifestBuilder::get_themes($testThemeBaseDir), 'Our test theme directory contains 2 themes');
$this->assertEquals(array(
'blackcandy',
'blackcandy_blog',
'darkshades',
'darkshades_blog'
'blackcandy' => 'blackcandy',
'blackcandy_blog' => 'blackcandy_blog',
'darkshades' => 'darkshades',
'darkshades_blog' => 'darkshades_blog'
), ManifestBuilder::get_themes($testThemeBaseDir, true), 'Our test theme directory contains 2 themes and 2 sub-themes');
// Remove all the test themes we created

View File

@ -1,6 +1,30 @@
<?php
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.
*/

View File

@ -53,6 +53,27 @@ class SiteConfigTest extends SapphireTest {
$this->assertFalse($pageEn->canEdit($translatorDe));
$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');
}
}
?>