Ticket #2638: allow themes to specify a base theme to load with 'include' setting in a theme.ini file
This commit is contained in:
parent
11f7fce3bb
commit
c24458a9f0
|
@ -200,7 +200,7 @@ class Action extends HTMLOutputter // lawsuit
|
|||
|
||||
if (Event::handle('StartShowStatusNetStyles', array($this)) &&
|
||||
Event::handle('StartShowLaconicaStyles', array($this))) {
|
||||
$this->cssLink('css/display.css',null, 'screen, projection, tv, print');
|
||||
$this->primaryCssLink(null, 'screen, projection, tv, print');
|
||||
Event::handle('EndShowStatusNetStyles', array($this));
|
||||
Event::handle('EndShowLaconicaStyles', array($this));
|
||||
}
|
||||
|
@ -248,6 +248,18 @@ class Action extends HTMLOutputter // lawsuit
|
|||
}
|
||||
}
|
||||
|
||||
function primaryCssLink($mainTheme=null, $media=null)
|
||||
{
|
||||
// If the currently-selected theme has dependencies on other themes,
|
||||
// we'll need to load their display.css files as well in order.
|
||||
$theme = new Theme($mainTheme);
|
||||
$baseThemes = $theme->getDeps();
|
||||
foreach ($baseThemes as $baseTheme) {
|
||||
$this->cssLink('css/display.css', $baseTheme, $media);
|
||||
}
|
||||
$this->cssLink('css/display.css', $mainTheme, $media);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show javascript headers
|
||||
*
|
||||
|
|
|
@ -54,6 +54,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
|||
|
||||
class Theme
|
||||
{
|
||||
var $name = null;
|
||||
var $dir = null;
|
||||
var $path = null;
|
||||
|
||||
|
@ -70,6 +71,10 @@ class Theme
|
|||
if (empty($name)) {
|
||||
$name = common_config('site', 'theme');
|
||||
}
|
||||
if (!self::validName($name)) {
|
||||
throw new ServerException("Invalid theme name.");
|
||||
}
|
||||
$this->name = $name;
|
||||
|
||||
// Check to see if it's in the local dir
|
||||
|
||||
|
@ -177,6 +182,58 @@ class Theme
|
|||
return $this->path.'/'.$relative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a list of other themes whose CSS needs to be pulled in before
|
||||
* this theme's, based on following the theme.ini 'include' settings.
|
||||
* (May be empty if this theme has no include dependencies.)
|
||||
*
|
||||
* @return array of strings with theme names
|
||||
*/
|
||||
function getDeps()
|
||||
{
|
||||
$chain = $this->doGetDeps(array($this->name));
|
||||
array_pop($chain); // Drop us back off
|
||||
return $chain;
|
||||
}
|
||||
|
||||
protected function doGetDeps($chain)
|
||||
{
|
||||
$data = $this->getMetadata();
|
||||
if (!empty($data['include'])) {
|
||||
$include = $data['include'];
|
||||
|
||||
// Protect against cycles!
|
||||
if (!in_array($include, $chain)) {
|
||||
try {
|
||||
$theme = new Theme($include);
|
||||
array_unshift($chain, $include);
|
||||
return $theme->doGetDeps($chain);
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_ERR,
|
||||
"Exception while fetching theme dependencies " .
|
||||
"for $this->name: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
return $chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull data from the theme's theme.ini file.
|
||||
* @fixme calling getFile will fall back to default theme, this may be unsafe.
|
||||
*
|
||||
* @return associative array of strings
|
||||
*/
|
||||
function getMetadata()
|
||||
{
|
||||
$iniFile = $this->getFile('theme.ini');
|
||||
if (file_exists($iniFile)) {
|
||||
return parse_ini_file($iniFile);
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the full path of a file in a theme dir based on its relative name
|
||||
*
|
||||
|
@ -285,4 +342,9 @@ class Theme
|
|||
|
||||
return $instroot;
|
||||
}
|
||||
|
||||
static function validName($name)
|
||||
{
|
||||
return preg_match('/^[a-z0-9][a-z0-9_-]*$/i', $name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -198,7 +198,7 @@ class ThemeUploader
|
|||
protected function validateFile($filename, $ext)
|
||||
{
|
||||
$this->validateFileOrFolder($filename);
|
||||
$this->validateExtension($ext);
|
||||
$this->validateExtension($filename, $ext);
|
||||
// @fixme validate content
|
||||
}
|
||||
|
||||
|
@ -216,13 +216,17 @@ class ThemeUploader
|
|||
return true;
|
||||
}
|
||||
|
||||
protected function validateExtension($ext)
|
||||
protected function validateExtension($base, $ext)
|
||||
{
|
||||
$allowed = array('css', // CSS may need validation
|
||||
'png', 'gif', 'jpg', 'jpeg',
|
||||
'svg', // SVG images/fonts may need validation
|
||||
'ttf', 'eot', 'woff');
|
||||
if (!in_array(strtolower($ext), $allowed)) {
|
||||
if ($ext == 'ini' && $base == 'theme') {
|
||||
// theme.ini exception
|
||||
return true;
|
||||
}
|
||||
$msg = sprintf(_("Theme contains file of type '.%s', " .
|
||||
"which is not allowed."),
|
||||
$ext);
|
||||
|
|
|
@ -241,7 +241,7 @@ class MobileProfilePlugin extends WAP20Plugin
|
|||
return true;
|
||||
}
|
||||
|
||||
$action->cssLink('css/display.css');
|
||||
$action->primaryCssLink();
|
||||
|
||||
if (file_exists(Theme::file('css/mp-screen.css'))) {
|
||||
$action->cssLink('css/mp-screen.css', null, 'screen');
|
||||
|
|
Loading…
Reference in New Issue
Block a user