forked from GNUsocial/gnu-social
		
	Ticket #2638: allow themes to specify a base theme to load with 'include' setting in a theme.ini file
This commit is contained in:
		@@ -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');
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user