implement request #1989987: theme support. merge themes branch with --squash

This commit is contained in:
Christian Weiske 2011-05-25 19:43:36 +02:00
parent 63b0a4b8cb
commit 5ba53394fc
78 changed files with 298 additions and 19 deletions

View file

@ -121,18 +121,19 @@
<replacement <replacement
path="src/SemanticScuttle/header.php" path="src/SemanticScuttle/header.php"
type="pear-config" type="pear-config" from="@data_dir@" to="data_dir"
from="@data_dir@" to="data_dir" />
<replacement
path="src/SemanticScuttle/header.php"
type="pear-config" from="@www_dir@" to="www_dir"
/> />
<replacement <replacement
path="www/www-header.php" path="www/www-header.php"
type="pear-config" type="pear-config" from="@data_dir@" to="data_dir"
from="@data_dir@" to="data_dir"
/> />
<replacement <replacement
path="tests/prepare.php" path="tests/prepare.php"
type="pear-config" type="pear-config" from="@data_dir@" to="data_dir"
from="@data_dir@" to="data_dir"
/> />
<changelog version="0.97" date="2010-06-09" license="GPL"> <changelog version="0.97" date="2010-06-09" license="GPL">

View file

@ -63,6 +63,15 @@ $sidebarTopMessage = '';
*/ */
$sidebarBottomMessage = ''; $sidebarBottomMessage = '';
/**
* The HTML theme to use. With themes, you can give your semanticscuttle
* installation a new look.
*
* Themes are the folders in data/templates/
*
* @var string
*/
$theme = 'default';
/*************************************************** /***************************************************

View file

@ -39,7 +39,9 @@ include('search.menu.php');
<?php if($GLOBALS['enableAdminColors']!=false && isset($userid) && $userservice->isAdmin($userid) && $pageName != PAGE_WATCHLIST) : ?> <?php if($GLOBALS['enableAdminColors']!=false && isset($userid) && $userservice->isAdmin($userid) && $pageName != PAGE_WATCHLIST) : ?>
<div style="width:70%;text-align:center;"> <div style="width:70%;text-align:center;">
<img src="<?php echo ROOT ?>images/logo_24.gif" width="12px"/> <?php echo T_('Bookmarks on this page are managed by an admin user.'); ?><img src="<?php echo ROOT ?>images/logo_24.gif" width="12px"/> <img src="<?php $theme->resource('images/logo_24.gif'); ?>" width="12px"/>
<?php echo T_('Bookmarks on this page are managed by an admin user.'); ?>
<img src="<?php $theme->resource('images/logo_24.gif'); ?>" width="12px"/>
</div> </div>
<?php endif?> <?php endif?>
@ -70,7 +72,7 @@ if ($userservice->isLoggedOn()) {
) { ) {
echo ' <a href="'. createURL('tagcommondescriptionedit', $currenttag).'" title="'.T_('Edit the common description of this tag').'">'; echo ' <a href="'. createURL('tagcommondescriptionedit', $currenttag).'" title="'.T_('Edit the common description of this tag').'">';
echo !is_array($cDescription) || strlen($cDescription['cdDescription'])==0?T_('Edit the common description of this tag'):''; echo !is_array($cDescription) || strlen($cDescription['cdDescription'])==0?T_('Edit the common description of this tag'):'';
echo ' <img src="'.ROOT.'images/b_edit.png" /></a>'; echo ' <img src="' . $theme->resource('images/b_edit.png') . '" /></a>';
} else if (isset($hash)) { } else if (isset($hash)) {
echo ' (<a href="'.createURL('bookmarkcommondescriptionedit', $hash).'" title="'.T_('Edit the common description of this bookmark').'">'; echo ' (<a href="'.createURL('bookmarkcommondescriptionedit', $hash).'" title="'.T_('Edit the common description of this bookmark').'">';
echo T_('Edit the common description of this bookmark').'</a>)'; echo T_('Edit the common description of this bookmark').'</a>)';
@ -95,7 +97,7 @@ if($userservice->isLoggedOn()) {
if($currenttag!= '') { if($currenttag!= '') {
echo ' <a href="'. createURL('tagedit', $currenttag).'" title="'.T_('Edit your personal description of this tag').'" >'; echo ' <a href="'. createURL('tagedit', $currenttag).'" title="'.T_('Edit your personal description of this tag').'" >';
echo strlen($pDescription['tDescription'])==0?T_('Edit your personal description of this tag'):''; echo strlen($pDescription['tDescription'])==0?T_('Edit your personal description of this tag'):'';
echo ' <img src="'.ROOT.'images/b_edit.png" /></a>'; echo ' <img src="' . $theme->resource('images/b_edit.png') . '" /></a>';
} }
} }
?></p> ?></p>
@ -219,9 +221,12 @@ if ($currenttag!= '') {
$brss = ''; $brss = '';
$size = count($rsschannels); $size = count($rsschannels);
for ($i = 0; $i < $size; $i++) { for ($i = 0; $i < $size; $i++) {
$brss = '<a style="background:#FFFFFF" href="'. htmlspecialchars($rsschannels[$i][1]) . '"' $brss = '<a style="background:#FFFFFF"'
. ' href="'. htmlspecialchars($rsschannels[$i][1]) . '"'
. ' title="' . htmlspecialchars($rsschannels[$i][0]) . '">' . ' title="' . htmlspecialchars($rsschannels[$i][0]) . '">'
. '<img src="' . ROOT . 'images/rss.gif" width="16" height="16" alt="' . htmlspecialchars($rsschannels[$i][0]) .'"/>' . '<img src="' . $theme->resource('images/rss.gif') . '"'
. ' width="16" height="16"'
. ' alt="' . htmlspecialchars($rsschannels[$i][0]) .'"/>'
. '</a>'; . '</a>';
} }
@ -361,9 +366,15 @@ if ($currenttag!= '') {
} }
// Admin specific design // Admin specific design
if ($userservice->isAdmin($row['username']) && $GLOBALS['enableAdminColors']) { if ($userservice->isAdmin($row['username'])
&& $GLOBALS['enableAdminColors']
) {
$adminBgClass = ' class="adminBackground"'; $adminBgClass = ' class="adminBackground"';
$adminStar = ' <img src="'. ROOT .'images/logo_24.gif" width="12px" title="'. T_('This bookmark is certified by an admin user.') .'" />'; $adminStar = ' <img'
. ' src="' . $theme->resource('images/logo_24.gif') . '"'
. ' width="12px"'
. ' title="' . T_('This bookmark is certified by an admin user.') . '"'
. '/>';
} else { } else {
$adminBgClass = ''; $adminBgClass = '';
$adminStar = ''; $adminStar = '';

View file

@ -4,8 +4,8 @@
<head> <head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" /> <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
<title><?php echo filter($GLOBALS['sitename'] .(isset($pagetitle) ? ' » ' . $pagetitle : '')); ?></title> <title><?php echo filter($GLOBALS['sitename'] .(isset($pagetitle) ? ' » ' . $pagetitle : '')); ?></title>
<link rel="icon" type="image/png" href="<?php echo ROOT ?>icon.png" /> <link rel="icon" type="image/png" href="<?php echo $theme->resource('icon.png');?>" />
<link rel="stylesheet" type="text/css" href="<?php echo ROOT ?>scuttle.css" /> <link rel="stylesheet" type="text/css" href="<?php echo $theme->resource('scuttle.css');?>" />
<link rel="search" type="application/opensearchdescription+xml" href="<?php echo ROOT ?>api/opensearch.php" title="<?php echo htmlspecialchars($GLOBALS['sitename']) ?>"/> <link rel="search" type="application/opensearchdescription+xml" href="<?php echo ROOT ?>api/opensearch.php" title="<?php echo htmlspecialchars($GLOBALS['sitename']) ?>"/>
<?php <?php
if (isset($rsschannels)) { if (isset($rsschannels)) {

View file

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
<title><?php echo filter($GLOBALS['sitename'] .(isset($pagetitle) ? ' » ' . $pagetitle : '')); ?></title>
<link rel="icon" type="image/png" href="<?php echo $theme->resource('icon.png');?>" />
<link rel="stylesheet" type="text/css" href="<?php echo $theme->resource('scuttle.css');?>" />
<link rel="search" type="application/opensearchdescription+xml" href="<?php echo ROOT ?>api/opensearch.php" title="<?php echo htmlspecialchars($GLOBALS['sitename']) ?>"/>
<?php
if (isset($rsschannels)) {
$size = count($rsschannels);
for ($i = 0; $i < $size; $i++) {
echo ' <link rel="alternate" type="application/rss+xml" title="'
. htmlspecialchars($rsschannels[$i][0]) . '"'
. ' href="'. $rsschannels[$i][1] .'" />';
}
}
?>
<?php if (isset($loadjs)) :?>
<?php if (DEBUG_MODE) : ?>
<script type="text/javascript" src="<?php echo ROOT_JS ?>jquery-1.4.2.js"></script>
<script type="text/javascript" src="<?php echo ROOT_JS ?>jquery.jstree.js"></script>
<?php else: ?>
<script type="text/javascript" src="<?php echo ROOT_JS ?>jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="<?php echo ROOT_JS ?>jquery.jstree.min.js"></script>
<?php endif ?>
<script type="text/javascript" src="<?php echo ROOT ?>jsScuttle.php"></script>
<?php endif ?>
</head>
<body>
<?php
$headerstyle = '';
if(isset($_GET['popup'])) {
$headerstyle = ' class="popup"';
}
?>
<div id="header" <?php echo $headerstyle; ?>>
<h1><a href="<?php echo ROOT ?>">.</a></h1>
<?php
if(!isset($_GET['popup'])) {
$this->includeTemplate('toolbar.inc');
}
?></div>
<?php
if (isset($subtitle)) {
echo '<h2>'. $subtitle ."</h2>\n";
}
if(DEBUG_MODE) {
echo '<p class="error">'. T_('Admins, your installation is in "Debug Mode" ($debugMode = true). To go in "Normal Mode" and hide debugging messages, change $debugMode to false into config.php.') ."</p>\n";
}
if (isset($error) && $error!='') {
echo '<p class="error">'. $error ."</p>\n";
}
if (isset($msg) && $msg!='') {
echo '<p class="success">'. $msg ."</p>\n";
}
if (isset($tipMsg) && $tipMsg!='') {
echo '<p class="tipMsg">'. $tipMsg ."</p>\n";
}
?>

View file

@ -1,6 +1,9 @@
ChangeLog for SemantiScuttle ChangeLog for SemantiScuttle
============================ ============================
- Implement request #1989987: Theming support
0.98.0 - 2011-XX-XX 0.98.0 - 2011-XX-XX
------------------- -------------------
- Switch to jQuery and drop dojo - Switch to jQuery and drop dojo

48
doc/themes.rst Normal file
View file

@ -0,0 +1,48 @@
======================
SemanticScuttle Themes
======================
SemanticScuttle may be changed visually by supplying custom "themes" (skins)
that modify the visual appearance.
Changing the current theme
==========================
In ``data/config.php``, set your theme like this: ::
$theme = 'darkmood';
The available themes are the folders in ``www/themes/``.
By default, SemanticScuttle ships only one usable theme ("default") and one
to demonstrate how to create your own theme ("testdummy").
Creating your own theme
=======================
Have a look at the "testdummy" theme in ``www/themes/testdummy/``.
CSS and image files
-------------------
Since both file types need to be accessible via the web server directly,
they are located in the ``www/`` folder: ::
www/themes/$themename/
The main CSS file that automatically gets included is ::
www/themes/$themename/scuttle.css
Several template files in SemanticScuttle include image files. If they do not
exist in your theme, the default ones are used automatically.
Note that this is not true for images that are specified in the CSS files.
Template files
--------------
The templates of the default file are located in ::
data/templates/default/
You may put your theme template files into ::
data/templates/$themename/

View file

@ -76,6 +76,9 @@ class SemanticScuttle_Model_Template
* Sets variables and includes the template file, * Sets variables and includes the template file,
* causing it to be rendered. * causing it to be rendered.
* *
* Does not take care of themes and so.
* The include path must be set so the correct theme is used.
*
* @return void * @return void
*/ */
public function parse() public function parse()

View file

@ -0,0 +1,97 @@
<?php
/**
* SemanticScuttle - your social bookmark manager.
*
* PHP version 5.
*
* @category Bookmarking
* @package SemanticScuttle
* @author Christian Weiske <cweiske@cweiske.de>
* @license AGPL v3 or later http://www.gnu.org/licenses/agpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
/**
* A theme, the visual representation of SemanticScuttle.
*
* @category Bookmarking
* @package SemanticScuttle
* @author Christian Weiske <cweiske@cweiske.de>
* @license AGPL v3 or later http://www.gnu.org/licenses/agpl.html
* @link http://sourceforge.net/projects/semanticscuttle
*/
class SemanticScuttle_Model_Theme
{
/**
* Theme name. Also the path part of template and resource files
*
* @var string
*/
protected $name = null;
/**
* Local path to the www themes directory.
* Needs to have a trailing slash.
*
* @var string
*/
protected $wwwThemeDir = null;
/**
* Create a new theme instance.
*
* @param string $name Theme name "data/templates/(*)/"
*/
public function __construct($name = 'default')
{
$this->name = $name;
$this->wwwThemeDir = $GLOBALS['wwwdir'] . '/themes/';
//TODO: implement theme hierarchies with parent fallback
}
/**
* Returns the URL path to a resource file (www/themes/$name/$file).
* Automatically falls back to the parent theme if the file does not exist
* in the theme.
*
* Must always be used when adding i.e. images to the output.
*
* @param string $file File name to find the path for, i.e. "scuttle.css".
*
* @return string Full path
*/
public function resource($file)
{
$themeFile = $this->wwwThemeDir . $this->name . '/' . $file;
if (file_exists($themeFile)) {
return ROOT . 'themes/' . $this->name . '/' . $file;
}
$defaultFile = $this->wwwThemeDir . 'default/' . $file;
if (file_exists($defaultFile)) {
return ROOT . 'themes/default/' . $file;
}
//file does not exist. fall back to the theme file
// to guide the theme author a bit.
// TODO: logging. in admin mode, there should be a message
return ROOT . 'themes/' . $this->name . '/' . $file;
}
/**
* Returns the theme name.
*
* @return string Theme name
*/
public function getName()
{
return $this->name;
}
}
?>

View file

@ -14,6 +14,7 @@
*/ */
require_once 'SemanticScuttle/Model/Template.php'; require_once 'SemanticScuttle/Model/Template.php';
require_once 'SemanticScuttle/Model/Theme.php';
/** /**
* SemanticScuttle template service. * SemanticScuttle template service.
@ -38,6 +39,14 @@ class SemanticScuttle_Service_Template extends SemanticScuttle_Service
*/ */
protected $basedir; protected $basedir;
/**
* The template theme to use.
* Set in constructor based on $GLOBALS['theme']
*
* @var SemanticScuttle_Model_Theme
*/
protected $theme;
/** /**
@ -64,6 +73,8 @@ class SemanticScuttle_Service_Template extends SemanticScuttle_Service
protected function __construct() protected function __construct()
{ {
$this->basedir = $GLOBALS['TEMPLATES_DIR']; $this->basedir = $GLOBALS['TEMPLATES_DIR'];
$this->theme = new SemanticScuttle_Model_Theme($GLOBALS['theme']);
//FIXME: verify the theme exists
} }
@ -74,19 +85,33 @@ class SemanticScuttle_Service_Template extends SemanticScuttle_Service
* @param string $template Template filename relative * @param string $template Template filename relative
* to template dir * to template dir
* @param array $vars Array of template variables. * @param array $vars Array of template variables.
* The current theme object will be added
* automatically with name "theme".
* *
* @return SemanticScuttle_Model_Template Template object * @return SemanticScuttle_Model_Template Template object
*/ */
function loadTemplate($template, $vars = null) public function loadTemplate($template, $vars = null)
{ {
if (substr($template, -4) != '.php') { if (substr($template, -4) != '.php') {
$template .= '.php'; $template .= '.php';
} }
$oldIncPath = get_include_path();
set_include_path(
$this->basedir . $this->theme->getName()
. PATH_SEPARATOR . $this->basedir . 'default'
//needed since services are instantiated in templates
. PATH_SEPARATOR . $oldIncPath
);
$vars['theme'] = $this->theme;
$tpl = new SemanticScuttle_Model_Template( $tpl = new SemanticScuttle_Model_Template(
$this->basedir .'/'. $template, $vars, $this $template, $vars, $this
); );
$tpl->parse(); $tpl->parse();
set_include_path($oldIncPath);
return $tpl; return $tpl;
} }
} }

View file

@ -18,9 +18,12 @@
if ('@data_dir@' == '@' . 'data_dir@') { if ('@data_dir@' == '@' . 'data_dir@') {
//non pear-install //non pear-install
$datadir = dirname(__FILE__) . '/../../data/'; $datadir = dirname(__FILE__) . '/../../data/';
$wwwdir = dirname(__FILE__) . '/../../www/';
} else { } else {
//pear installation; files are in include path //pear installation; files are in include path
$datadir = '@data_dir@/SemanticScuttle/'; $datadir = '@data_dir@/SemanticScuttle/';
//FIXME: when you have multiple installations, the www_dir will be wrong
$wwwdir = '@www_dir@/SemanticScuttle/';
} }
if (!file_exists($datadir . '/config.php')) { if (!file_exists($datadir . '/config.php')) {

View file

@ -3,6 +3,7 @@ $GLOBALS['saveInLastUrl'] = false;
$httpContentType = 'text/javascript'; $httpContentType = 'text/javascript';
require_once 'www-header.php'; require_once 'www-header.php';
require_once 'SemanticScuttle/functions.php'; require_once 'SemanticScuttle/functions.php';
$theme = new SemanticScuttle_Model_Theme($GLOBALS['theme']);
$player_root = ROOT .'includes/player/'; $player_root = ROOT .'includes/player/';
?> ?>
@ -62,7 +63,7 @@ function isAvailable(input, response){
username = username.trim(); username = username.trim();
var availability = document.getElementById("availability"); var availability = document.getElementById("availability");
if (username != '') { if (username != '') {
usernameField.style.backgroundImage = 'url(<?php echo ROOT; ?>images/loading.gif)'; usernameField.style.backgroundImage = 'url(<?php echo $theme->resource('images/loading.gif'); ?>)';
if (response != '') { if (response != '') {
usernameField.style.backgroundImage = 'none'; usernameField.style.backgroundImage = 'none';
if (response == 'true') { if (response == 'true') {
@ -92,7 +93,7 @@ function useAddress(ele) {
function getTitle(input, response){ function getTitle(input, response){
var title = document.getElementById('titleField'); var title = document.getElementById('titleField');
if (title.value == '') { if (title.value == '') {
title.style.backgroundImage = 'url(<?php echo ROOT; ?>images/loading.gif)'; title.style.backgroundImage = 'url(<?php echo $theme->resource('images/loading.gif');?>)';
if (response != null) { if (response != null) {
title.style.backgroundImage = 'none'; title.style.backgroundImage = 'none';
title.value = response; title.value = response;

View file

Before

Width:  |  Height:  |  Size: 771 B

After

Width:  |  Height:  |  Size: 771 B

View file

Before

Width:  |  Height:  |  Size: 451 B

After

Width:  |  Height:  |  Size: 451 B

View file

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

Before

Width:  |  Height:  |  Size: 873 B

After

Width:  |  Height:  |  Size: 873 B

View file

Before

Width:  |  Height:  |  Size: 684 B

After

Width:  |  Height:  |  Size: 684 B

View file

Before

Width:  |  Height:  |  Size: 726 B

After

Width:  |  Height:  |  Size: 726 B

View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

Before

Width:  |  Height:  |  Size: 401 B

After

Width:  |  Height:  |  Size: 401 B

View file

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View file

Before

Width:  |  Height:  |  Size: 419 B

After

Width:  |  Height:  |  Size: 419 B

View file

Before

Width:  |  Height:  |  Size: 495 B

After

Width:  |  Height:  |  Size: 495 B

View file

Before

Width:  |  Height:  |  Size: 415 B

After

Width:  |  Height:  |  Size: 415 B

View file

Before

Width:  |  Height:  |  Size: 625 B

After

Width:  |  Height:  |  Size: 625 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1,12 @@
@import url(../default/scuttle.css);
body {
background-color: #FEA;
}
html > body h1 {
background: url('images/logo.png') no-repeat 10px;
}
div#header {
background: #FEA;
}