diff options
| author | xue <> | 2006-05-30 03:26:33 +0000 | 
|---|---|---|
| committer | xue <> | 2006-05-30 03:26:33 +0000 | 
| commit | 6e0338629774fffe5fbe7136dfce34ce83844a5c (patch) | |
| tree | 9520eaa7c3c278b5ebf525a0d1e09f0a4cdf7779 /demos/blog | |
| parent | 7f508e187e4539a16cdbb1dd6a4b1133c53cf24d (diff) | |
Blog demo is completed.
Diffstat (limited to 'demos/blog')
57 files changed, 2250 insertions, 242 deletions
diff --git a/demos/blog/protected/Common/BlogDataModule.php b/demos/blog/protected/Common/BlogDataModule.php index 714743e7..a15701ab 100644 --- a/demos/blog/protected/Common/BlogDataModule.php +++ b/demos/blog/protected/Common/BlogDataModule.php @@ -1,7 +1,22 @@  <?php
 +/**
 + * BlogDataModule class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 -// post status: 0 - draft, 1 - published
 -// comment status: 0 - awaiting approval, 1 - published
 +/**
 + * BlogDataModule class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class BlogDataModule extends TModule
  {
  	const DB_FILE_EXT='.db';
 @@ -24,7 +39,7 @@ class BlogDataModule extends TModule  	public function setDbFile($value)
  	{
  		if(($this->_dbFile=Prado::getPathOfNamespace($value,self::DB_FILE_EXT))===null)
 -			throw new BlogException('blogdatamodule_dbfile_invalid',$value);
 +			throw new BlogException(500,'blogdatamodule_dbfile_invalid',$value);
  	}
  	protected function createDatabase()
 @@ -36,7 +51,7 @@ class BlogDataModule extends TModule  			if(trim($statement)!=='')
  			{
  				if(@sqlite_query($this->_db,$statement)===false)
 -					throw new BlogException('blogdatamodule_createdatabase_failed',sqlite_error_string(sqlite_last_error($this->_db)),$statement);
 +					throw new BlogException(500,'blogdatamodule_createdatabase_failed',sqlite_error_string(sqlite_last_error($this->_db)),$statement);
  			}
  		}
  	}
 @@ -47,7 +62,7 @@ class BlogDataModule extends TModule  		$newDb=!is_file($dbFile);
  		$error='';
  		if(($this->_db=sqlite_open($dbFile,0666,$error))===false)
 -			throw new BlogException('blogdatamodule_dbconnect_failed',$error);
 +			throw new BlogException(500,'blogdatamodule_dbconnect_failed',$error);
  		if($newDb)
  			$this->createDatabase();
  	}
 @@ -69,7 +84,7 @@ class BlogDataModule extends TModule  		if(($result=@sqlite_query($this->_db,$sql))!==false)
  			return $result;
  		else
 -			throw new BlogException('blogdatamodule_query_failed',sqlite_error_string(sqlite_last_error($this->_db)),$sql);
 +			throw new BlogException(500,'blogdatamodule_query_failed',sqlite_error_string(sqlite_last_error($this->_db)),$sql);
  	}
  	protected function populateUserRecord($row)
 @@ -143,8 +158,8 @@ class BlogDataModule extends TModule  		$website=sqlite_escape_string($user->Website);
  		$createTime=time();
  		$sql="INSERT INTO tblUsers ".
 -				"(name,full_name,role,passwd,email,reg_time,website) ".
 -				"VALUES ('$name','$fullName',{$user->Role},'$passwd','$email',$createTime,'$website')";
 +				"(name,full_name,role,passwd,email,reg_time,status,website) ".
 +				"VALUES ('$name','$fullName',{$user->Role},'$passwd','$email',$createTime,{$user->Status},'$website')";
  		$this->query($sql);
  		$user->ID=sqlite_last_insert_rowid($this->_db);
  	}
 @@ -192,13 +207,11 @@ class BlogDataModule extends TModule  		return $postRecord;
  	}
 -	public function queryPosts($authorFilter,$timeFilter,$categoryFilter,$orderBy,$limit)
 +	public function queryPosts($postFilter,$categoryFilter,$orderBy,$limit)
  	{
  		$filter='';
 -		if($authorFilter!=='')
 -			$filter.=" AND $authorFilter";
 -		if($timeFilter!=='')
 -			$filter.=" AND $timeFilter";
 +		if($postFilter!=='')
 +			$filter.=" AND $postFilter";
  		if($categoryFilter!=='')
  			$filter.=" AND a.id IN (SELECT post_id AS id FROM tblPost2Category WHERE $categoryFilter)";
  		$sql="SELECT a.id AS id,
 @@ -221,13 +234,11 @@ class BlogDataModule extends TModule  		return $posts;
  	}
 -	public function queryPostCount($authorFilter,$timeFilter,$categoryFilter)
 +	public function queryPostCount($postFilter,$categoryFilter)
  	{
  		$filter='';
 -		if($authorFilter!=='')
 -			$filter.=" AND $authorFilter";
 -		if($timeFilter!=='')
 -			$filter.=" AND $timeFilter";
 +		if($postFilter!=='')
 +			$filter.=" AND $postFilter";
  		if($categoryFilter!=='')
  			$filter.=" AND a.id IN (SELECT post_id AS id FROM tblPost2Category WHERE $categoryFilter)";
  		$sql="SELECT COUNT(a.id) AS post_count
 @@ -261,6 +272,11 @@ class BlogDataModule extends TModule  			return null;
  	}
 +	public function escapeString($string)
 +	{
 +		return sqlite_escape_string($string);
 +	}
 +
  	public function insertPost($post,$catIDs)
  	{
  		$title=sqlite_escape_string($post->Title);
 @@ -382,7 +398,7 @@ class BlogDataModule extends TModule  	public function queryCategories()
  	{
 -		$sql="SELECT * FROM tblCategories";
 +		$sql="SELECT * FROM tblCategories ORDER BY name ASC";
  		$result=$this->query($sql);
  		$rows=sqlite_fetch_all($result,SQLITE_ASSOC);
  		$cats=array();
 @@ -398,7 +414,7 @@ class BlogDataModule extends TModule  				a.description AS description,
  				a.post_count AS post_count
  				FROM tblCategories a, tblPost2Category b
 -				WHERE a.id=b.category_id AND b.post_id=$postID";
 +				WHERE a.id=b.category_id AND b.post_id=$postID ORDER BY a.name";
  		$result=$this->query($sql);
  		$rows=sqlite_fetch_all($result,SQLITE_ASSOC);
  		$cats=array();
 @@ -486,6 +502,11 @@ class BlogDataModule extends TModule  class UserRecord
  {
 +	const ROLE_USER=0;
 +	const ROLE_ADMIN=1;
 +	const STATUS_NORMAL=0;
 +	const STATUS_DISABLED=1;
 +	const STATUS_PENDING=2;
  	public $ID;
  	public $Name;
  	public $FullName;
 @@ -500,6 +521,9 @@ class UserRecord  class PostRecord
  {
 +	const STATUS_PUBLISHED=0;
 +	const STATUS_DRAFT=1;
 +	const STATUS_PENDING=2;
  	public $ID;
  	public $AuthorID;
  	public $AuthorName;
 diff --git a/demos/blog/protected/Common/BlogErrorHandler.php b/demos/blog/protected/Common/BlogErrorHandler.php new file mode 100644 index 00000000..6dab2a29 --- /dev/null +++ b/demos/blog/protected/Common/BlogErrorHandler.php @@ -0,0 +1,46 @@ +<?php
 +/**
 + * BlogErrorHandler class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +
 +Prado::using('System.Exceptions.TErrorHandler');
 +Prado::using('Application.Common.BlogException');
 +
 +/**
 + * BlogErrorHandler class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
 +class BlogErrorHandler extends TErrorHandler
 +{
 +	/**
 +	 * Displays error to the client user.
 +	 * THttpException and errors happened when the application is in <b>Debug</b>
 +	 * mode will be displayed to the client user.
 +	 * @param integer response status code
 +	 * @param Exception exception instance
 +	 */
 +	protected function handleExternalError($statusCode,$exception)
 +	{
 +		if($exception instanceof BlogException)
 +		{
 +			$message=$exception->getMessage();
 +			Prado::log($message,TLogger::ERROR,'BlogApplication');
 +			$message=urldecode($this->getApplication()->getSecurityManager()->hashData($message));
 +			$this->Response->redirect($this->Service->constructUrl('ErrorReport',array('msg'=>$message)));
 +		}
 +		else
 +			parent::handleExternalError($statusCode,$exception);
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog/protected/Common/BlogErrors.php b/demos/blog/protected/Common/BlogErrors.php deleted file mode 100644 index 501ec1c9..00000000 --- a/demos/blog/protected/Common/BlogErrors.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php
 -
 -class BlogErrors
 -{
 -	const ERROR_UKNOWN=0;
 -	const ERROR_POST_NOT_FOUND=1;
 -	const ERROR_USER_NOT_FOUND=2;
 -	const ERROR_PERMISSION_DENIED=3;
 -
 -	private static $_errorMessages=array(
 -		self::ERROR_UKNOWN=>'Unknown error.',
 -		self::ERROR_POST_NOT_FOUND=>'The specified post cannot be found.',
 -		self::ERROR_USER_NOT_FOUND=>'The specified user account cannot be found.',
 -		self::ERROR_PERMISSION_DENIED=>'Sorry, you do not have permission to perform this action.',
 -	);
 -
 -	public static function getMessage($errorCode)
 -	{
 -		return isset(self::$_errorMessages[$errorCode])?self::$_errorMessages[$errorCode]:self::$_errorMessages[0];
 -	}
 -}
 -
 -?>
\ No newline at end of file diff --git a/demos/blog/protected/Common/BlogException.php b/demos/blog/protected/Common/BlogException.php index ab8020d1..64609366 100644 --- a/demos/blog/protected/Common/BlogException.php +++ b/demos/blog/protected/Common/BlogException.php @@ -1,6 +1,23 @@  <?php
 +/**
 + * BlogException class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 -class BlogException extends TApplicationException
 +/**
 + * BlogException class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
 +class BlogException extends THttpException
  {
  	/**
  	 * @return string path to the error message file
 diff --git a/demos/blog/protected/Common/BlogPage.php b/demos/blog/protected/Common/BlogPage.php index f69e4c48..85a995c0 100644 --- a/demos/blog/protected/Common/BlogPage.php +++ b/demos/blog/protected/Common/BlogPage.php @@ -1,5 +1,22 @@  <?php
 +/**
 + * BlogPage class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * BlogPage class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class BlogPage extends TPage
  {
  	public function onPreInit($param)
 diff --git a/demos/blog/protected/Common/BlogUser.php b/demos/blog/protected/Common/BlogUser.php index af49c8d7..42a171a6 100644 --- a/demos/blog/protected/Common/BlogUser.php +++ b/demos/blog/protected/Common/BlogUser.php @@ -1,7 +1,24 @@  <?php
 +/**
 + * BlogUser class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
  Prado::using('System.Security.TUser');
 +/**
 + * BlogUser class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class BlogUser extends TUser
  {
  	private $_id;
 @@ -16,6 +33,11 @@ class BlogUser extends TUser  		$this->_id=$value;
  	}
 +	public function getIsAdmin()
 +	{
 +		return $this->isInRole('admin');
 +	}
 +
  	public function saveToString()
  	{
  		$a=array($this->_id,parent::saveToString());
 diff --git a/demos/blog/protected/Common/BlogUserManager.php b/demos/blog/protected/Common/BlogUserManager.php index c3ddb80b..3a7f4789 100644 --- a/demos/blog/protected/Common/BlogUserManager.php +++ b/demos/blog/protected/Common/BlogUserManager.php @@ -1,8 +1,25 @@  <?php
 +/**
 + * BlogUserManager class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
  Prado::using('System.Security.IUserManager');
  Prado::using('Application.Common.BlogUser');
 +/**
 + * BlogUserManager class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class BlogUserManager extends TModule implements IUserManager
  {
  	public function getGuestName()
 @@ -29,7 +46,7 @@ class BlogUserManager extends TModule implements IUserManager  				$user->setID($userRecord->ID);
  				$user->setName($username);
  				$user->setIsGuest(false);
 -				$user->setRoles($userRecord->Role===0?'user':'admin');
 +				$user->setRoles($userRecord->Role===UserRecord::ROLE_USER?'user':'admin');
  				return $user;
  			}
  			else
 @@ -47,7 +64,7 @@ class BlogUserManager extends TModule implements IUserManager  	{
  		$db=$this->Application->getModule('data');
  		if(($userRecord=$db->queryUserByName($username))!==null)
 -			return $userRecord->Password===md5($password);
 +			return $userRecord->Password===md5($password) && $userRecord->Status===UserRecord::STATUS_NORMAL;
  		else
  			return false;
  	}
 diff --git a/demos/blog/protected/Common/messages.txt b/demos/blog/protected/Common/messages.txt index deb15ee3..2a18aac2 100644 --- a/demos/blog/protected/Common/messages.txt +++ b/demos/blog/protected/Common/messages.txt @@ -1,4 +1,12 @@  blogdatamodule_dbconnect_failed			= Unable to connect to database: {0}
  blogdatamodule_dbfile_invalid			= BlogDataModule.DbFile='{0}' is invalid.
  blogdatamodule_createdatabase_failed	= BlogDataModule failed to create database when executing SQL: {1}. Last SQL error is: {0}.
 -blogdatamodule_query_failed				= Failed to execute SQL: {1}. Last SQL error is: {0}.
\ No newline at end of file +blogdatamodule_query_failed				= Failed to execute SQL: {1}. Last SQL error is: {0}.
 +
 +newuser_registration_disallowed			= The Weblog system is running in single user mode and does not allow new user registration.
 +profile_edit_disallowed					= You are not allowed to modify user profile {0}.
 +profile_id_invalid						= Unable to retrieve user profile {0}.
 +
 +post_id_invalid							= Unable to retrieve post {0}.
 +post_edit_disallowed					= You are not allowed to modify post {0}.
 +post_view_disallowed					= You are not allowed to read post {0}.
\ No newline at end of file diff --git a/demos/blog/protected/Data/Settings.xml b/demos/blog/protected/Data/Settings.xml index 7e89789b..90cfe0ae 100644 --- a/demos/blog/protected/Data/Settings.xml +++ b/demos/blog/protected/Data/Settings.xml @@ -4,8 +4,9 @@      <parameter id="SiteSubtitle" value="The first time at dog beach :-p" />      <parameter id="SiteOwner" value="LP" />      <parameter id="AdminEmail" value="LP@LG.com" /> -    <parameter id="MultipleUser" value="false" /> -    <parameter id="AccountApproval" value="false" /> -    <parameter id="PostApproval" value="false" /> -    <parameter id="ThemeName" value="Basic" /> +    <parameter id="MultipleUser" value="true" /> +    <parameter id="AccountApproval" value="true" /> +    <parameter id="PostPerPage" value="3" /> +    <parameter id="PostApproval" value="true" /> +    <parameter id="ThemeName" value="Summer" />  </parameters>
\ No newline at end of file diff --git a/demos/blog/protected/Layouts/MainLayout.php b/demos/blog/protected/Layouts/MainLayout.php index 253d6c03..980e221e 100644 --- a/demos/blog/protected/Layouts/MainLayout.php +++ b/demos/blog/protected/Layouts/MainLayout.php @@ -1,5 +1,22 @@  <?php
 +/**
 + * MainLayout class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * MainLayout class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class MainLayout extends TTemplateControl
  {
  }
 diff --git a/demos/blog/protected/Layouts/MainLayout.tpl b/demos/blog/protected/Layouts/MainLayout.tpl index f171de7f..87313f38 100644 --- a/demos/blog/protected/Layouts/MainLayout.tpl +++ b/demos/blog/protected/Layouts/MainLayout.tpl @@ -14,7 +14,7 @@  <com:TForm>
  <div id="header">
 -<h1 id="header-title"><%$ SiteTitle %></h1>
 +<h1 id="header-title"><a href="?"><%$ SiteTitle %></a></h1>
  <h2 id="header-subtitle"><%$ SiteSubtitle %></h2>
  </div><!-- end of header -->
 diff --git a/demos/blog/protected/Pages/Admin/AdminMenu.php b/demos/blog/protected/Pages/Admin/AdminMenu.php index 40f40b88..9e46acea 100644 --- a/demos/blog/protected/Pages/Admin/AdminMenu.php +++ b/demos/blog/protected/Pages/Admin/AdminMenu.php @@ -1,5 +1,22 @@  <?php
 +/**
 + * AdminMenu class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * AdminMenu class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class AdminMenu extends TTemplateControl
  {
  }
 diff --git a/demos/blog/protected/Pages/Admin/ConfigMan.page b/demos/blog/protected/Pages/Admin/ConfigMan.page index 0f5ef03d..69ee0899 100644 --- a/demos/blog/protected/Pages/Admin/ConfigMan.page +++ b/demos/blog/protected/Pages/Admin/ConfigMan.page @@ -36,7 +36,7 @@  <com:TPanel GroupingText="Account settings">
 -<com:TCheckBox ID="MultipleUser" Text="Allow multiple users" />
 +<com:TCheckBox ID="MultipleUser" Text="Allow creating new accounts" />
  <br/>
  <com:TCheckBox ID="AccountApproval" Text="New accounts need approval" />
 @@ -46,12 +46,26 @@  <com:TPanel GroupingText="Post settings">
 +<span class="input-label">Number of posts per page</span>
 +<com:TTextBox ID="PostPerPage" Columns="8"/>
 +<com:TRegularExpressionValidator
 +	ControlToValidate="PostPerPage"
 +	ValidationGroup="settings"
 +	Display="Dynamic"
 +	RegularExpression="[1-9]\d*"
 +	Text="Please enter a number." />
 +<br/>
 +
  <com:TCheckBox ID="PostApproval" Text="New posts need approval" />
  <br/>
  </com:TPanel>
 -
 -<com:TLinkButton Text="Save" OnClick="saveButtonClicked" />
 +<br/>
 +<com:TLinkButton
 +	Text="Save"
 +	ValidationGroup="settings"
 +	CssClass="link-button"
 +	OnClick="saveButtonClicked" />
  <com:TLabel ID="Result" Visible=<%= $this->IsPostBack && $this->IsValid %> Text="Your changes have been saved." />
  </com:TContent>
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Admin/ConfigMan.php b/demos/blog/protected/Pages/Admin/ConfigMan.php index fc652bb3..6443e5a0 100644 --- a/demos/blog/protected/Pages/Admin/ConfigMan.php +++ b/demos/blog/protected/Pages/Admin/ConfigMan.php @@ -1,5 +1,22 @@  <?php
 +/**
 + * ConfigMan class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * ConfigMan class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class ConfigMan extends BlogPage
  {
  	const CONFIG_FILE='Application.Data.Settings';
 @@ -16,6 +33,7 @@ class ConfigMan extends BlogPage  			$this->AdminEmail->Text=$parameters['AdminEmail'];
  			$this->MultipleUser->Checked=TPropertyValue::ensureBoolean($parameters['MultipleUser']);
  			$this->AccountApproval->Checked=TPropertyValue::ensureBoolean($parameters['AccountApproval']);
 +			$this->PostPerPage->Text=$parameters['PostPerPage'];
  			$this->PostApproval->Checked=TPropertyValue::ensureBoolean($parameters['PostApproval']);
  			$themes=$this->Service->ThemeManager->AvailableThemes;
  			$this->ThemeName->DataSource=$themes;
 @@ -36,6 +54,7 @@ class ConfigMan extends BlogPage  		$elements[]=$this->createParameter('AdminEmail',$this->AdminEmail->Text);
  		$elements[]=$this->createParameter('MultipleUser',$this->MultipleUser->Checked);
  		$elements[]=$this->createParameter('AccountApproval',$this->AccountApproval->Checked);
 +		$elements[]=$this->createParameter('PostPerPage',$this->PostPerPage->Text);
  		$elements[]=$this->createParameter('PostApproval',$this->PostApproval->Checked);
  		$themeName=$this->ThemeName->SelectedItem->Text;
  		$elements[]=$this->createParameter('ThemeName',$themeName);
 diff --git a/demos/blog/protected/Pages/Admin/PostMan.php b/demos/blog/protected/Pages/Admin/PostMan.php index a99332eb..349278fc 100644 --- a/demos/blog/protected/Pages/Admin/PostMan.php +++ b/demos/blog/protected/Pages/Admin/PostMan.php @@ -1,13 +1,30 @@  <?php
 +/**
 + * PostMan class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * PostMan class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class PostMan extends BlogPage
  {
  	protected function bindData()
  	{
  		$offset=$this->PostGrid->CurrentPageIndex*$this->PostGrid->PageSize;
  		$limit=$this->PostGrid->PageSize;
 -		$this->PostGrid->DataSource=$this->DataAccess->queryPosts('','','','ORDER BY a.status DESC, create_time DESC',"LIMIT $offset,$limit");
 -		$this->PostGrid->VirtualItemCount=$this->DataAccess->queryPostCount('','','');
 +		$this->PostGrid->DataSource=$this->DataAccess->queryPosts('','','ORDER BY a.status DESC, create_time DESC',"LIMIT $offset,$limit");
 +		$this->PostGrid->VirtualItemCount=$this->DataAccess->queryPostCount('','');
  		$this->PostGrid->dataBind();
  	}
 diff --git a/demos/blog/protected/Pages/Admin/Settings.page b/demos/blog/protected/Pages/Admin/Settings.page deleted file mode 100644 index 48dfde96..00000000 --- a/demos/blog/protected/Pages/Admin/Settings.page +++ /dev/null @@ -1,4 +0,0 @@ -<com:TContent ID="main" >
 -Welcome, <com:TLabel Text=<%= $this->User->Name %> />!
 -This page contains site settings accessible only to site admin.
 -</com:TContent>
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Admin/UserMan.php b/demos/blog/protected/Pages/Admin/UserMan.php index 1cb62482..b13703a1 100644 --- a/demos/blog/protected/Pages/Admin/UserMan.php +++ b/demos/blog/protected/Pages/Admin/UserMan.php @@ -1,5 +1,22 @@  <?php
 +/**
 + * UserMan class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * UserMan class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class UserMan extends BlogPage
  {
  	protected function bindData()
 diff --git a/demos/blog/protected/Pages/ErrorReport.page b/demos/blog/protected/Pages/ErrorReport.page index a9b461d9..3a068e3c 100644 --- a/demos/blog/protected/Pages/ErrorReport.page +++ b/demos/blog/protected/Pages/ErrorReport.page @@ -3,7 +3,7 @@  <h2>Error</h2>
  <p>
 -<%= $this->ErrorMessage %>
 +<com:TLiteral ID="ErrorMessage" />
  </p>
  <p>
 diff --git a/demos/blog/protected/Pages/ErrorReport.php b/demos/blog/protected/Pages/ErrorReport.php index 3b24170f..58e15796 100644 --- a/demos/blog/protected/Pages/ErrorReport.php +++ b/demos/blog/protected/Pages/ErrorReport.php @@ -1,11 +1,28 @@  <?php
 +/**
 + * ErrorReport class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * ErrorReport class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class ErrorReport extends BlogPage
  {
 -	public function getErrorMessage()
 +	public function onLoad($param)
  	{
 -		$id=TPropertyValue::ensureInteger($this->Request['id']);
 -		return BlogErrors::getMessage($id);
 +		parent::onLoad($param);
 +		$this->ErrorMessage->Text=$this->Application->SecurityManager->validateData(urldecode($this->Request['msg']));
  	}
  }
 diff --git a/demos/blog/protected/Pages/Posts/EditCategory.page b/demos/blog/protected/Pages/Posts/EditCategory.page index fdde2648..1f61c0af 100644 --- a/demos/blog/protected/Pages/Posts/EditCategory.page +++ b/demos/blog/protected/Pages/Posts/EditCategory.page @@ -1,3 +1,5 @@ +<%@ Title="Edit Category" %>
 +
  <com:TContent ID="Main">
  <h2>Update Post Category</h2>
 @@ -14,7 +16,7 @@  	Display="Dynamic"
  	OnServerValidate="checkCategoryName"
  	Text="...must be unique"
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error1" />
  <br/>
  <com:TTextBox ID="CategoryName" Columns="50" MaxLength="128" />
  <br/>
 @@ -27,10 +29,11 @@  	Columns="50"
  	Rows="5" />
  <br/>
 -
 +<br/>
  <com:TLinkButton
  	Text="Save"
  	OnClick="saveButtonClicked"
 +	CssClass="link-button"
  	ValidationGroup="category" />
  </com:TContent>
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/EditCategory.php b/demos/blog/protected/Pages/Posts/EditCategory.php index fd2d0707..920d2d80 100644 --- a/demos/blog/protected/Pages/Posts/EditCategory.php +++ b/demos/blog/protected/Pages/Posts/EditCategory.php @@ -1,14 +1,33 @@  <?php
 +/**
 + * EditCategory class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * EditCategory class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class EditCategory extends BlogPage
  {
 -	public function getCurrentCategory()
 +	private $_category;
 +
 +	public function onInit($param)
  	{
 +		parent::onInit($param);
  		$id=TPropertyValue::ensureInteger($this->Request['id']);
 -		if(($cat=$this->DataAccess->queryCategoryByID($id))!==null)
 -			return $cat;
 -		else
 -			throw new BlogException('xxx');
 +		$this->_category=$this->DataAccess->queryCategoryByID($id);
 +		if($this->_category===null)
 +			throw new BlogException(500,'category_id_invalid',$id);
  	}
  	public function onLoad($param)
 @@ -16,9 +35,8 @@ class EditCategory extends BlogPage  		parent::onLoad($param);
  		if(!$this->IsPostBack)
  		{
 -			$catRecord=$this->getCurrentCategory();
 -			$this->CategoryName->Text=$catRecord->Name;
 -			$this->CategoryDescription->Text=$catRecord->Description;
 +			$this->CategoryName->Text=$this->_category->Name;
 +			$this->CategoryDescription->Text=$this->_category->Description;
  		}
  	}
 @@ -26,11 +44,10 @@ class EditCategory extends BlogPage  	{
  		if($this->IsValid)
  		{
 -			$categoryRecord=$this->getCurrentCategory();
 -			$categoryRecord->Name=$this->CategoryName->Text;
 -			$categoryRecord->Description=$this->CategoryDescription->Text;
 -			$this->DataAccess->updateCategory($categoryRecord);
 -			$this->gotoPage('Posts.ListPost',array('cat'=>$categoryRecord->ID));
 +			$this->_category->Name=$this->CategoryName->Text;
 +			$this->_category->Description=$this->CategoryDescription->Text;
 +			$this->DataAccess->updateCategory($this->_category);
 +			$this->gotoPage('Posts.ListPost',array('cat'=>$this->_category->ID));
  		}
  	}
 diff --git a/demos/blog/protected/Pages/Posts/EditPost.page b/demos/blog/protected/Pages/Posts/EditPost.page index 591f5945..97702848 100644 --- a/demos/blog/protected/Pages/Posts/EditPost.page +++ b/demos/blog/protected/Pages/Posts/EditPost.page @@ -1,28 +1,31 @@ +<%@ Title="Edit Post" %>
 +
  <com:TContent ID="Main">
  <h2>Update Post</h2>
 -Title
 +<span class="input-label">Title</span>
  <com:TRequiredFieldValidator
  Display="Dynamic"
  	ControlToValidate="Title"
  	ErrorMessage="...is required"
  	ValidationGroup="post" />
  <br/>
 -<com:TTextBox ID="Title" Columns="70" MaxLength="256" />
 +<com:TTextBox ID="Title" Columns="80" MaxLength="256" />
  <br/>
 -Content
 +<span class="input-label">Content</span>
  <com:TRequiredFieldValidator
  Display="Dynamic"
  	ControlToValidate="Content"
  	ErrorMessage="...is required"
  	ValidationGroup="post" />
  <br/>
 -<com:THtmlArea ID="Content" Width="450px" />
 +<com:THtmlArea ID="Content" Width="500px" />
  <br/>
 -Categories<br/>
 +<span class="input-label">Categories</span>
 +<br/>
  <com:TListBox
  	ID="Categories"
  	SelectionMode="Multiple"
 @@ -32,10 +35,12 @@ Categories<br/>  <com:TCheckBox ID="DraftMode" Text="in draft mode (the post will not be published)" />
  <br/>
 +<br/>
  <com:TLinkButton
  	Text="Save"
  	OnClick="saveButtonClicked"
 +	CssClass="link-button"
  	ValidationGroup="post" />
  </com:TContent>
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/EditPost.php b/demos/blog/protected/Pages/Posts/EditPost.php index 57e92b1c..24b58529 100644 --- a/demos/blog/protected/Pages/Posts/EditPost.php +++ b/demos/blog/protected/Pages/Posts/EditPost.php @@ -1,14 +1,36 @@  <?php
 +/**
 + * EditPost class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * EditPost class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class EditPost extends BlogPage
  {
 -	public function getCurrentPost()
 +	private $_postRecord=null;
 +
 +	public function onInit($param)
  	{
 +		parent::onInit($param);
  		$id=TPropertyValue::ensureInteger($this->Request['id']);
 -		if(($post=$this->DataAccess->queryPostByID($id))!==null)
 -			return $post;
 -		else
 -			throw new BlogException('xxx');
 +		$this->_postRecord=$this->DataAccess->queryPostByID($id);
 +		if($this->_postRecord===null)
 +			throw new BlogException(500,'post_id_invalid',$id);
 +		// only the author and admin can edit the post
 +		if(!$this->User->IsAdmin && $this->User->ID!==$this->_postRecord->AuthorID)
 +			throw new BlogException(500,'post_edit_disallowed',$id);
  	}
  	public function onLoad($param)
 @@ -16,10 +38,10 @@ class EditPost extends BlogPage  		parent::onLoad($param);
  		if(!$this->IsPostBack)
  		{
 -			$postRecord=$this->getCurrentPost();
 +			$postRecord=$this->_postRecord;
  			$this->Title->Text=$postRecord->Title;
  			$this->Content->Text=$postRecord->Content;
 -			$this->DraftMode->Checked=$postRecord->Status===0;
 +			$this->DraftMode->Checked=$postRecord->Status!==PostRecord::STATUS_PUBLISHED;
  			$this->Categories->DataSource=$this->DataAccess->queryCategories();
  			$this->Categories->dataBind();
  			$cats=$this->DataAccess->queryCategoriesByPostID($postRecord->ID);
 @@ -34,10 +56,15 @@ class EditPost extends BlogPage  	{
  		if($this->IsValid)
  		{
 -			$postRecord=$this->getCurrentPost();
 -			$postRecord->Title=$this->Title->Text;
 -			$postRecord->Content=$this->Content->Text;
 -			$postRecord->Status=$this->DraftMode->Checked?0:1;
 +			$postRecord=$this->_postRecord;
 +			$postRecord->Title=$this->Title->SafeText;
 +			$postRecord->Content=$this->Content->SafeText;
 +			if($this->DraftMode->Checked)
 +				$postRecord->Status=PostRecord::STATUS_DRAFT;
 +			else if(!$this->User->IsAdmin && TPropertyValue::ensureBoolean($this->Application->Parameters['PostApproval']))
 +				$postRecord->Status=PostRecord::STATUS_PENDING;
 +			else
 +				$postRecord->Status=PostRecord::STATUS_PUBLISHED;
  			$postRecord->ModifyTime=time();
  			$cats=array();
  			foreach($this->Categories->SelectedValues as $value)
 diff --git a/demos/blog/protected/Pages/Posts/ListPost.page b/demos/blog/protected/Pages/Posts/ListPost.page index 15fc3d0c..4c96d6fb 100644 --- a/demos/blog/protected/Pages/Posts/ListPost.page +++ b/demos/blog/protected/Pages/Posts/ListPost.page @@ -1,5 +1,20 @@  <com:TContent ID="Main">
 +<com:TPanel ID="CategoryPanel" Visible="false" CssClass="category">
 +<div class="category-name">
 +<%= $this->Category->Name %>
 +<com:TLinkButton
 +	Text="[-]"
 +	Tooltip="Delete this category"
 +	Visible=<%= $this->User->IsAdmin %>
 +	Attributes.onclick="if(!confirm('Are you sure to delete this category? Posts in this category will NOT be removed.')) return false;"
 +	OnClick="deleteButtonClicked" />
 +</div>
 +<div class="category-description">
 +<%= $this->Category->Description %>
 +</div>
 +</com:TPanel>
 +
  <com:TRepeater ID="PostList" EnableViewState="false">
  	<prop:ItemTemplate>
  <div class="post">
 @@ -24,4 +39,17 @@ posted by  	</prop:ItemTemplate>
  </com:TRepeater>
 +<div class="postlist-pager">
 +<com:THyperLink
 +	ID="PrevPage"
 +	Visible="false"
 +	Text="< Previous Page"
 +	/>
 +<com:THyperLink
 +	ID="NextPage"
 +	Visible="false"
 +	Text="Next Page >"
 +	/>
 +</div>
 +
  </com:TContent>
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/ListPost.php b/demos/blog/protected/Pages/Posts/ListPost.php index 6d56b543..bed18222 100644 --- a/demos/blog/protected/Pages/Posts/ListPost.php +++ b/demos/blog/protected/Pages/Posts/ListPost.php @@ -1,13 +1,59 @@  <?php
 +/**
 + * ListPost class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * ListPost class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class ListPost extends BlogPage
  {
 -	const DEFAULT_LIMIT=10;
 +	private $_posts;
 +	private $_category;
 -	public function getPosts()
 +	public function onInit($param)
 +	{
 +		parent::onInit($param);
 +		$this->_posts=$this->DataAccess->queryPosts(
 +				$this->getPostFilter(),
 +				$this->getCategoryFilter(),
 +				'ORDER BY create_time DESC',
 +				'LIMIT '.$this->getPageOffset().','.$this->getPageSize());
 +		if($this->Request['cat']!==null)
 +		{
 +			$catID=TPropertyValue::ensureInteger($this->Request['cat']);
 +			$this->_category=$this->DataAccess->queryCategoryByID($catID);
 +			$this->CategoryPanel->Visible=true;
 +		}
 +	}
 +
 +	private function getPageOffset()
 +	{
 +		if(($offset=TPropertyValue::ensureInteger($this->Request['offset']))<=0)
 +			$offset=0;
 +		return $offset;
 +	}
 +
 +	private function getPageSize()
 +	{
 +		if(($limit=TPropertyValue::ensureInteger($this->Request['limit']))<=0)
 +			$limit=TPropertyValue::ensureInteger($this->Application->Parameters['PostPerPage']);
 +		return $limit;
 +	}
 +
 +	private function getTimeFilter()
  	{
 -		$timeFilter='';
 -		$catFilter='';
  		if(($time=TPropertyValue::ensureInteger($this->Request['time']))>0)
  		{
  			$year=(integer)($time/100);
 @@ -19,25 +65,76 @@ class ListPost extends BlogPage  				$year++;
  			}
  			$endTime=mktime(0,0,0,$month,1,$year);
 -			$timeFilter="create_time>=$startTime AND create_time<$endTime";
 +			return "create_time>=$startTime AND create_time<$endTime";
  		}
 +		else
 +			return '';
 +	}
 +
 +	private function getPostFilter()
 +	{
 +		$filter='a.status=0';
 +		if(($timeFilter=$this->getTimeFilter())!=='')
 +			return "$filter AND $timeFilter";
 +		else
 +			return $filter;
 +	}
 +
 +	private function getCategoryFilter()
 +	{
  		if(($catID=$this->Request['cat'])!==null)
  		{
  			$catID=TPropertyValue::ensureInteger($catID);
 -			$catFilter="category_id=$catID";
 +			return "category_id=$catID";
  		}
 -		if(($offset=TPropertyValue::ensureInteger($this->Request['offset']))<=0)
 -			$offset=0;
 -		if(($limit=TPropertyValue::ensureInteger($this->Request['limit']))<=0)
 -			$limit=self::DEFAULT_LIMIT;
 -		return $this->DataAccess->queryPosts('',$timeFilter,$catFilter,'ORDER BY create_time DESC',"LIMIT $offset,$limit");
 +		else
 +			return '';
 +	}
 +
 +	private function formUrl($newOffset)
 +	{
 +		$gets=array();
 +		$gets['offset']=$newOffset;
 +		if($this->Request['limit']!==null)
 +			$gets['limit']=$this->Request['limit'];
 +		if($this->Request['time']!==null)
 +			$gets['time']=$this->Request['time'];
 +		if($this->Request['cat']!==null)
 +			$gets['cat']=$this->Request['cat'];
 +		return $this->Service->constructUrl('Posts.ListPost',$gets);
 +	}
 +
 +	public function getCategory()
 +	{
 +		return $this->_category;
  	}
  	public function onLoad($param)
  	{
  		parent::onLoad($param);
 -		$this->PostList->DataSource=$this->getPosts();
 +		$this->PostList->DataSource=$this->_posts;
  		$this->PostList->dataBind();
 +		if($this->getPageOffset()>0)
 +		{
 +			if(($offset=$this->getPageOffset()-$this->getPageSize())<0)
 +				$offset=0;
 +			$this->PrevPage->NavigateUrl=$this->formUrl($offset);
 +			$this->PrevPage->Visible=true;
 +		}
 +		if(count($this->_posts)===$this->getPageSize())
 +		{
 +			$this->NextPage->NavigateUrl=$this->formUrl($this->getPageOffset()+$this->getPageSize());
 +			$this->NextPage->Visible=true;
 +		}
 +	}
 +
 +	public function deleteButtonClicked($sender,$param)
 +	{
 +		if($this->User->IsAdmin)
 +		{
 +			$this->DataAccess->deleteCategory($this->Category->ID);
 +			$this->gotoDefaultPage();
 +		}
  	}
  }
 diff --git a/demos/blog/protected/Pages/Posts/MyPost.page b/demos/blog/protected/Pages/Posts/MyPost.page index 95a32ac9..ca153166 100644 --- a/demos/blog/protected/Pages/Posts/MyPost.page +++ b/demos/blog/protected/Pages/Posts/MyPost.page @@ -25,7 +25,7 @@  	<com:TBoundColumn
  		HeaderText="Status"
  		DataField="Status"
 -		DataFormatString="#{0}?'Published':'Draft'"
 +		DataFormatString="#{0}===0?'Published':({0}===1?'Draft':'Pending')"
  		ItemStyle.Width="70px"
  		/>
  	<com:TBoundColumn
 diff --git a/demos/blog/protected/Pages/Posts/MyPost.php b/demos/blog/protected/Pages/Posts/MyPost.php index be03ca63..dff98426 100644 --- a/demos/blog/protected/Pages/Posts/MyPost.php +++ b/demos/blog/protected/Pages/Posts/MyPost.php @@ -1,5 +1,22 @@  <?php
 +/**
 + * MyPost class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * MyPost class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class MyPost extends BlogPage
  {
  	protected function bindData()
 @@ -7,8 +24,8 @@ class MyPost extends BlogPage  		$author=$this->User->ID;
  		$offset=$this->PostGrid->CurrentPageIndex*$this->PostGrid->PageSize;
  		$limit=$this->PostGrid->PageSize;
 -		$this->PostGrid->DataSource=$this->DataAccess->queryPosts("author_id=$author",'','','ORDER BY a.status ASC, create_time DESC',"LIMIT $offset,$limit");
 -		$this->PostGrid->VirtualItemCount=$this->DataAccess->queryPostCount("author_id=$author",'','');
 +		$this->PostGrid->DataSource=$this->DataAccess->queryPosts("author_id=$author",'','ORDER BY a.status DESC, create_time DESC',"LIMIT $offset,$limit");
 +		$this->PostGrid->VirtualItemCount=$this->DataAccess->queryPostCount("author_id=$author",'');
  		$this->PostGrid->dataBind();
  	}
 diff --git a/demos/blog/protected/Pages/Posts/NewCategory.page b/demos/blog/protected/Pages/Posts/NewCategory.page index 92fe1468..43dba79b 100644 --- a/demos/blog/protected/Pages/Posts/NewCategory.page +++ b/demos/blog/protected/Pages/Posts/NewCategory.page @@ -1,3 +1,5 @@ +<%@ Title="Create New Category" %>
 +
  <com:TContent ID="Main">
  <h2>New Post Category</h2>
 @@ -14,7 +16,7 @@  	Display="Dynamic"
  	OnServerValidate="checkCategoryName"
  	Text="...must be unique"
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error1" />
  <br/>
  <com:TTextBox ID="CategoryName" Columns="50" MaxLength="128" />
  <br/>
 @@ -27,10 +29,11 @@  	Columns="50"
  	Rows="5" />
  <br/>
 -
 +<br/>
  <com:TLinkButton
  	Text="Save"
  	OnClick="saveButtonClicked"
 +	CssClass="link-button"
  	ValidationGroup="category" />
  </com:TContent>
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/NewCategory.php b/demos/blog/protected/Pages/Posts/NewCategory.php index d36f6af1..215200a9 100644 --- a/demos/blog/protected/Pages/Posts/NewCategory.php +++ b/demos/blog/protected/Pages/Posts/NewCategory.php @@ -1,5 +1,22 @@  <?php
 +/**
 + * NewCategory class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * NewCategory class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class NewCategory extends BlogPage
  {
  	public function saveButtonClicked($sender,$param)
 diff --git a/demos/blog/protected/Pages/Posts/NewPost.page b/demos/blog/protected/Pages/Posts/NewPost.page index a49188f6..15071e3a 100644 --- a/demos/blog/protected/Pages/Posts/NewPost.page +++ b/demos/blog/protected/Pages/Posts/NewPost.page @@ -1,28 +1,31 @@ +<%@ Title="Write New Post" %>
 +
  <com:TContent ID="Main">
 -<h2>Write a New Post</h2>
 +<h2>Write New Post</h2>
 -Title
 +<span class="input-label">Title</span>
  <com:TRequiredFieldValidator
  Display="Dynamic"
  	ControlToValidate="Title"
  	ErrorMessage="...is required"
  	ValidationGroup="post" />
  <br/>
 -<com:TTextBox ID="Title" Columns="70" MaxLength="256" />
 +<com:TTextBox ID="Title" Columns="80" MaxLength="256" />
  <br/>
 -Content
 +<span class="input-label">Content</span>
  <com:TRequiredFieldValidator
  Display="Dynamic"
  	ControlToValidate="Content"
  	ErrorMessage="...is required"
  	ValidationGroup="post" />
  <br/>
 -<com:THtmlArea ID="Content" Width="450px" />
 +<com:THtmlArea ID="Content" Width="500px" />
  <br/>
 -Categories<br/>
 +<span class="input-label">Categories</span>
 +<br/>
  <com:TListBox
  	ID="Categories"
  	SelectionMode="Multiple"
 @@ -32,10 +35,11 @@ Categories<br/>  <com:TCheckBox ID="DraftMode" Text="in draft mode (the post will not be published)" />
  <br/>
 -
 +<br/>
  <com:TLinkButton
  	Text="Save"
  	OnClick="saveButtonClicked"
 +	CssClass="link-button"
  	ValidationGroup="post" />
  </com:TContent>
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/NewPost.php b/demos/blog/protected/Pages/Posts/NewPost.php index 055c7f92..7d02557d 100644 --- a/demos/blog/protected/Pages/Posts/NewPost.php +++ b/demos/blog/protected/Pages/Posts/NewPost.php @@ -1,5 +1,22 @@  <?php
 +/**
 + * NewPost class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * NewPost class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class NewPost extends BlogPage
  {
  	public function onLoad($param)
 @@ -17,9 +34,14 @@ class NewPost extends BlogPage  		if($this->IsValid)
  		{
  			$postRecord=new PostRecord;
 -			$postRecord->Title=$this->Title->Text;
 -			$postRecord->Content=$this->Content->Text;
 -			$postRecord->Status=$this->DraftMode->Checked?0:1;
 +			$postRecord->Title=$this->Title->SafeText;
 +			$postRecord->Content=$this->Content->SafeText;
 +			if($this->DraftMode->Checked)
 +				$postRecord->Status=PostRecord::STATUS_DRAFT;
 +			else if(!$this->User->IsAdmin && TPropertyValue::ensureBoolean($this->Application->Parameters['PostApproval']))
 +				$postRecord->Status=PostRecord::STATUS_PENDING;
 +			else
 +				$postRecord->Status=PostRecord::STATUS_PUBLISHED;
  			$postRecord->CreateTime=time();
  			$postRecord->AuthorID=$this->User->ID;
  			$cats=array();
 diff --git a/demos/blog/protected/Pages/Posts/ViewPost.page b/demos/blog/protected/Pages/Posts/ViewPost.page index 4b233615..5bd80a52 100644 --- a/demos/blog/protected/Pages/Posts/ViewPost.page +++ b/demos/blog/protected/Pages/Posts/ViewPost.page @@ -5,6 +5,10 @@  <%= $this->CurrentPost->Title %>
  </div>
  <div class="post-time">
 +<com:TLabel
 +	ID="Status"
 +	ForeColor="red"
 +	Text=<%= $this->CurrentPost->Status===PostRecord::STATUS_DRAFT?'[Draft]':'[Pending approval]'%> />
  <%= date('l, F j, Y \a\t h:i:s a',$this->CurrentPost->CreateTime) %>
  by
  <%= '<a href="' . $this->Service->constructUrl('Users.ViewUser',array('id'=>$this->CurrentPost->AuthorID)) . '">' . $this->CurrentPost->AuthorName . '</a>' %>
 @@ -47,11 +51,11 @@ by  <%# date('F j, Y \a\t h:i:s a',$this->DataItem->CreateTime) %>
  by
  <%# $this->DataItem->AuthorWebsite==='' ?
 -		$this->DataItem->AuthorName :
 -		'<a href="' . $this->DataItem->AuthorWebsite . '">' . $this->DataItem->AuthorName . '</a>' %>
 +		htmlentities($this->DataItem->AuthorName,ENT_QUOTES,'UTF-8') :
 +		'<a href="' . htmlentities($this->DataItem->AuthorWebsite) . '">' . htmlentities($this->DataItem->AuthorName,ENT_QUOTES,'UTF-8') . '</a>' %>
  </div>
  <div class="comment-content">
 -<%# $this->DataItem->Content %>
 +<%# nl2br(htmlentities($this->DataItem->Content,ENT_QUOTES,'UTF-8')) %>
  </div>
  </div>
  	</prop:ItemTemplate>
 @@ -65,7 +69,7 @@ by  	ValidationGroup="comment""
  	Display="Dynamic"
  	Text="...is required"
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error1" />
  <br/>
  <com:TTextBox ID="CommentAuthor" />
  <br/>
 @@ -76,14 +80,14 @@ by  	ValidationGroup="comment""
  	Display="Dynamic"
  	Text="...is required"
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error1" />
  <com:TEmailAddressValidator
  	ControlToValidate="CommentEmail"
  	ValidationGroup="comment"
  	Display="Dynamic"
  	Text="*"
  	ErrorMessage="You entered an invalid email address."
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error2" />
  <br/>
  <com:TTextBox ID="CommentEmail" />
  <br/>
 @@ -99,14 +103,16 @@ by  	ValidationGroup="comment"
  	Display="Dynamic"
  	Text="...is required"
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error1" />
  <br/>
  <com:TTextBox ID="CommentContent" TextMode="MultiLine" Columns="55" Rows="10"/>
  <br/>
 +<br/>
  <com:TLinkButton
  	Text="Submit"
  	ValidationGroup="comment"
 +	CssClass="link-button"
  	OnClick="submitCommentButtonClicked" />
  </div>
 diff --git a/demos/blog/protected/Pages/Posts/ViewPost.php b/demos/blog/protected/Pages/Posts/ViewPost.php index 309bedc1..84f33cff 100644 --- a/demos/blog/protected/Pages/Posts/ViewPost.php +++ b/demos/blog/protected/Pages/Posts/ViewPost.php @@ -1,40 +1,57 @@  <?php
 +/**
 + * ViewPost class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * ViewPost class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class ViewPost extends BlogPage
  {
 -	private $_postID=null;
  	private $_post=null;
 -	public function getPostID()
 -	{
 -		if($this->_postID===null)
 -			$this->_postID=TPropertyValue::ensureInteger($this->Request['id']);
 -		return $this->_postID;
 -	}
 -
 -	public function getCurrentPost()
 +	public function onInit($param)
  	{
 +		parent::onInit($param);
 +		$id=TPropertyValue::ensureInteger($this->Request['id']);
 +		$this->_post=$this->DataAccess->queryPostByID($id);
  		if($this->_post===null)
 -		{
 -			if(($this->_post=$this->DataAccess->queryPostByID($this->getPostID()))===null)
 -				$this->reportError(BlogErrors::ERROR_POST_NOT_FOUND);
 -		}
 -		return $this->_post;
 +			throw new BlogException(500,'post_id_invalid',$id);
 +		// if post is not published, only the author and admin can view it
 +		if($this->_post->Status!==PostRecord::STATUS_PUBLISHED && !$this->User->IsAdmin && $this->User->ID!==$this->_post->AuthorID)
 +			throw new BlogException(500,'post_view_disallowed',$id);
 +		$this->Title=htmlentities($this->_post->Title,ENT_QUOTES,'UTF-8');
  	}
  	public function getCanEditPost()
  	{
  		$user=$this->getUser();
 -		$authorID=$this->getCurrentPost()->AuthorID;
 -		return $authorID===$user->getID() || $user->isInRole('admin');
 +		return $user->getIsAdmin() || $user->getID()===$this->_post->AuthorID;
 +	}
 +
 +	public function getCurrentPost()
 +	{
 +		return $this->_post;
  	}
  	public function onLoad($param)
  	{
  		parent::onLoad($param);
 -		$this->CategoryList->DataSource=$this->DataAccess->queryCategoriesByPostID($this->getPostID());
 +		$this->Status->Visible=$this->_post->Status!==PostRecord::STATUS_PUBLISHED;
 +		$this->CategoryList->DataSource=$this->DataAccess->queryCategoriesByPostID($this->_post->ID);
  		$this->CategoryList->dataBind();
 -		$this->CommentList->DataSource=$this->DataAccess->queryCommentsByPostID($this->getPostID());
 +		$this->CommentList->DataSource=$this->DataAccess->queryCommentsByPostID($this->_post->ID);
  		$this->CommentList->dataBind();
  	}
 @@ -44,11 +61,11 @@ class ViewPost extends BlogPage  		{
  			$commentRecord=new CommentRecord;
  			$commentRecord->PostID=$this->CurrentPost->ID;
 -			$commentRecord->AuthorName=$this->CommentAuthor->Text;
 +			$commentRecord->AuthorName=$this->CommentAuthor->SafeText;
  			$commentRecord->AuthorEmail=$this->CommentEmail->Text;
 -			$commentRecord->AuthorWebsite=$this->CommentWebsite->Text;
 +			$commentRecord->AuthorWebsite=$this->CommentWebsite->SafeText;
  			$commentRecord->AuthorIP=$this->Request->UserHostAddress;
 -			$commentRecord->Content=$this->CommentContent->Text;
 +			$commentRecord->Content=$this->CommentContent->SafeText;
  			$commentRecord->CreateTime=time();
  			$commentRecord->Status=0;
  			$this->DataAccess->insertComment($commentRecord);
 diff --git a/demos/blog/protected/Pages/Posts/config.xml b/demos/blog/protected/Pages/Posts/config.xml index 1c04e946..f3684e58 100644 --- a/demos/blog/protected/Pages/Posts/config.xml +++ b/demos/blog/protected/Pages/Posts/config.xml @@ -3,5 +3,7 @@  <configuration>
    <authorization>
      <deny pages="EditPost,NewPost,MyPost" users="?" />
 +    <allow pages="NewCategory,EditCategory" roles="admin" />
 +    <deny pages="NewCategory,EditCategory" users="*" />
    </authorization>
  </configuration>
\ No newline at end of file diff --git a/demos/blog/protected/Pages/SearchPost.page b/demos/blog/protected/Pages/SearchPost.page new file mode 100644 index 00000000..e3a71d44 --- /dev/null +++ b/demos/blog/protected/Pages/SearchPost.page @@ -0,0 +1,44 @@ +<com:TContent ID="Main">
 +
 +<div class="search-title">
 +Search results for <b><%= htmlentities($this->Request['keyword'],ENT_QUOTES,'UTF-8') %></b>:
 +</div>
 +
 +<com:TRepeater ID="PostList" EnableViewState="false">
 +	<prop:ItemTemplate>
 +<div class="post">
 +<div class="post-title">
 +<%# $this->DataItem->Title %>
 +</div>
 +<div class="post-time">
 +<%# date('l, F j, Y \a\t h:i:s a',$this->DataItem->CreateTime) %>
 +</div>
 +<div class="post-content">
 +<%# $this->DataItem->Content %>
 +</div>
 +<div class="post-footer">
 +posted by
 +<%# '<a href="' . $this->Service->constructUrl('Users.ViewUser',array('id'=>$this->DataItem->AuthorID)) . '">' . $this->DataItem->AuthorName . '</a>' %>
 +|
 +<%# '<a href="' . $this->Service->constructUrl('Posts.ViewPost',array('id'=>$this->DataItem->ID)) . '">PermaLink</a>' %>
 +|
 +<%# '<a href="' . $this->Service->constructUrl('Posts.ViewPost',array('id'=>$this->DataItem->ID)) . '#comments">Comments (' . $this->DataItem->CommentCount . ')</a>' %>
 +</div>
 +</div>
 +	</prop:ItemTemplate>
 +</com:TRepeater>
 +
 +<div class="postlist-pager">
 +<com:THyperLink
 +	ID="PrevPage"
 +	Visible="false"
 +	Text="< Previous Page"
 +	/>
 +<com:THyperLink
 +	ID="NextPage"
 +	Visible="false"
 +	Text="Next Page >"
 +	/>
 +</div>
 +
 +</com:TContent>
\ No newline at end of file diff --git a/demos/blog/protected/Pages/SearchPost.php b/demos/blog/protected/Pages/SearchPost.php new file mode 100644 index 00000000..53e8401c --- /dev/null +++ b/demos/blog/protected/Pages/SearchPost.php @@ -0,0 +1,76 @@ +<?php
 +
 +class SearchPost extends BlogPage
 +{
 +	private $_posts;
 +
 +	public function onInit($param)
 +	{
 +		parent::onInit($param);
 +		$this->_posts=$this->DataAccess->queryPosts(
 +				$this->getPostFilter(),
 +				'',
 +				'ORDER BY create_time DESC',
 +				'LIMIT '.$this->getPageOffset().','.$this->getPageSize());
 +	}
 +
 +	private function getPostFilter()
 +	{
 +		$filter='a.status=0';
 +		$keywords=explode(' ',$this->Request['keyword']);
 +		foreach($keywords as $keyword)
 +		{
 +			if(($keyword=$this->DataAccess->escapeString(trim($keyword)))!=='')
 +				$filter.=" AND content LIKE '%$keyword%'";
 +		}
 +		return $filter;
 +	}
 +
 +	private function getPageOffset()
 +	{
 +		if(($offset=TPropertyValue::ensureInteger($this->Request['offset']))<=0)
 +			$offset=0;
 +		return $offset;
 +	}
 +
 +	private function getPageSize()
 +	{
 +		if(($limit=TPropertyValue::ensureInteger($this->Request['limit']))<=0)
 +			$limit=TPropertyValue::ensureInteger($this->Application->Parameters['PostPerPage']);
 +		return $limit;
 +	}
 +
 +	private function formUrl($newOffset)
 +	{
 +		$gets=array();
 +		$gets['offset']=$newOffset;
 +		if($this->Request['limit']!==null)
 +			$gets['limit']=$this->Request['limit'];
 +		if($this->Request['time']!==null)
 +			$gets['time']=$this->Request['time'];
 +		if($this->Request['cat']!==null)
 +			$gets['cat']=$this->Request['cat'];
 +		return $this->Service->constructUrl('Posts.ListPost',$gets);
 +	}
 +
 +	public function onLoad($param)
 +	{
 +		parent::onLoad($param);
 +		$this->PostList->DataSource=$this->_posts;
 +		$this->PostList->dataBind();
 +		if($this->getPageOffset()>0)
 +		{
 +			if(($offset=$this->getPageOffset()-$this->getPageSize())<0)
 +				$offset=0;
 +			$this->PrevPage->NavigateUrl=$this->formUrl($offset);
 +			$this->PrevPage->Visible=true;
 +		}
 +		if(count($this->_posts)===$this->getPageSize())
 +		{
 +			$this->NextPage->NavigateUrl=$this->formUrl($this->getPageOffset()+$this->getPageSize());
 +			$this->NextPage->Visible=true;
 +		}
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Users/EditUser.page b/demos/blog/protected/Pages/Users/EditUser.page index 8c21fd50..0155dc26 100644 --- a/demos/blog/protected/Pages/Users/EditUser.page +++ b/demos/blog/protected/Pages/Users/EditUser.page @@ -1,14 +1,12 @@ -<com:TContent ID="Main">
 -
 -<h2>Update Profile</h2>
 +<%@ Title="Edit Profile" %>
 -<com:TValidationSummary Display="Dynamic" ValidationGroup="user" />
 +<com:TContent ID="Main">
 -<span class="input-label">Username</span>
 -<br/>
 -<com:TLabel ID="Username" />
 +<h2>Update Profile: <com:TLabel ID="Username" /></h2>
 -<br/>
 +<com:TValidationSummary
 +	Display="Dynamic"
 +	ValidationGroup="user" />
  <span class="input-label">Full name</span>
  <br/>
 @@ -26,7 +24,7 @@  	RegularExpression="[\w\.]{6,16}"
  	Text="*"
  	ErrorMessage="Your password must contain only letters, digits and underscores, and it must contain at least 6 and at most 16 characters."
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error1" />
  <br/>
 @@ -40,7 +38,7 @@  	Display="Dynamic"
  	Text="*"
  	ErrorMessage="Your password entries did not match."
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error3" />
  <br/>
 @@ -52,23 +50,28 @@  	ValidationGroup="user"
  	Text="*"
  	ErrorMessage="Please provide your email address."
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error1" />
  <com:TEmailAddressValidator
  	ControlToValidate="Email"
  	ValidationGroup="user"
  	Display="Dynamic"
  	Text="*"
  	ErrorMessage="You entered an invalid email address."
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error2" />
  <br/>
  <span class="input-label">Personal Website</span>
  <br/>
 -<com:TTextBox ID="Website" AutoTrim="true" />
 +<com:TTextBox ID="Website" AutoTrim="true" Columns="40"/>
  <br/>
 +<br/>
 -<com:TLinkButton Text="Save" ValidationGroup="user" OnClick="saveButtonClicked" />
 +<com:TLinkButton
 +	Text="Save"
 +	ValidationGroup="user"
 +	CssClass="link-button"
 +	OnClick="saveButtonClicked" />
  </com:TContent>
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Users/EditUser.php b/demos/blog/protected/Pages/Users/EditUser.php index e3efcfd1..73eef8bb 100644 --- a/demos/blog/protected/Pages/Users/EditUser.php +++ b/demos/blog/protected/Pages/Users/EditUser.php @@ -1,13 +1,39 @@  <?php
 +/**
 + * EditUser class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * EditUser class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class EditUser extends BlogPage
  {
 -	public function getCurrentUser()
 +	private $_userRecord=null;
 +
 +	public function onInit($param)
  	{
 -		if(($user=$this->DataAccess->queryUserByID($this->User->ID))!==null)
 -			return $user;
 +		parent::onInit($param);
 +		if(($id=$this->Request['id'])!==null)
 +		{
 +			$id=TPropertyValue::ensureInteger($id);
 +			if(!$this->User->IsAdmin && $this->User->ID!==$id)
 +				throw new BlogException(500,'profile_edit_disallowed',$id);
 +		}
  		else
 -			throw new BlogException('xxx');
 +			$id=$this->User->ID;
 +		if(($this->_userRecord=$this->DataAccess->queryUserByID($id))===null)
 +			throw new BlogException(500,'profile_id_invalid',$id);
  	}
  	public function onLoad($param)
 @@ -15,7 +41,7 @@ class EditUser extends BlogPage  		parent::onLoad($param);
  		if(!$this->IsPostBack)
  		{
 -			$userRecord=$this->getCurrentUser();
 +			$userRecord=$this->_userRecord;
  			$this->Username->Text=$userRecord->Name;
  			$this->FullName->Text=$userRecord->FullName;
  			$this->Email->Text=$userRecord->Email;
 @@ -27,7 +53,7 @@ class EditUser extends BlogPage  	{
  		if($this->IsValid)
  		{
 -			$userRecord=$this->getCurrentUser();
 +			$userRecord=$this->_userRecord;
  			if($this->Password->Text!=='')
  				$userRecord->Password=md5($this->Password->Text);
  			$userRecord->FullName=$this->FullName->Text;
 diff --git a/demos/blog/protected/Pages/Users/NewUser.page b/demos/blog/protected/Pages/Users/NewUser.page index eba2dcec..f096ffb1 100644 --- a/demos/blog/protected/Pages/Users/NewUser.page +++ b/demos/blog/protected/Pages/Users/NewUser.page @@ -1,35 +1,39 @@ +<%@ Title="Create New Account" %>
 +
  <com:TContent ID="Main">
  <h2>Create New Account</h2>
 -<com:TValidationSummary Display="Dynamic" ValidationGroup="NewUser" />
 +<com:TValidationSummary
 +	Display="Dynamic"
 +	ValidationGroup="user" />
  <span class="input-label">Username</span>
  <br/>
  <com:TTextBox ID="Username" />
  <com:TRequiredFieldValidator
  	ControlToValidate="Username"
 -	ValidationGroup="NewUser"
 +	ValidationGroup="user"
  	Display="Dynamic"
  	Text="*"
  	ErrorMessage="Please choose a username."
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error1" />
  <com:TRegularExpressionValidator
  	ControlToValidate="Username"
 -	ValidationGroup="NewUser"
 +	ValidationGroup="user"
  	Display="Dynamic"
  	RegularExpression="[\w]{3,16}"
  	Text="*"
  	ErrorMessage="Your username must contain only letters, digits and underscores, and it must contain at least 3 and at most 16 characters."
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error2" />
  <com:TCustomValidator
  	ControlToValidate="Username"
 -	ValidationGroup="NewUser"
 +	ValidationGroup="user"
  	Display="Dynamic"
  	OnServerValidate="checkUsername"
  	Text="*"
  	ErrorMessage="Sorry, your username is taken by someone else. Please choose another username."
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error3" />
  <br/>
 @@ -44,19 +48,19 @@  <com:TTextBox ID="Password" TextMode="Password" />
  <com:TRequiredFieldValidator
  	ControlToValidate="Password"
 -	ValidationGroup="NewUser"
 +	ValidationGroup="user"
  	Display="Dynamic"
  	Text="*"
  	ErrorMessage="Please choose a password."
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error1" />
  <com:TRegularExpressionValidator
  	ControlToValidate="Password"
 -	ValidationGroup="NewUser"
 +	ValidationGroup="user"
  	Display="Dynamic"
  	RegularExpression="[\w\.]{6,16}"
  	Text="*"
  	ErrorMessage="Your password must contain only letters, digits and underscores, and it must contain at least 6 and at most 16 characters."
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error2" />
  <br/>
 @@ -66,11 +70,11 @@  <com:TCompareValidator
  	ControlToValidate="Password"
  	ControlToCompare="Password2"
 -	ValidationGroup="NewUser"
 +	ValidationGroup="user"
  	Display="Dynamic"
  	Text="*"
  	ErrorMessage="Your password entries did not match."
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error3" />
  <br/>
 @@ -79,26 +83,31 @@  <com:TTextBox ID="Email" />
  <com:TRequiredFieldValidator
  	ControlToValidate="Email"
 -	ValidationGroup="NewUser"
 +	ValidationGroup="user"
  	Text="*"
  	ErrorMessage="Please provide your email address."
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error1" />
  <com:TEmailAddressValidator
  	ControlToValidate="Email"
 -	ValidationGroup="NewUser"
 +	ValidationGroup="user"
  	Display="Dynamic"
  	Text="*"
  	ErrorMessage="You entered an invalid email address."
 -	ControlCssClass="inputerror" />
 +	ControlCssClass="input-error2" />
  <br/>
  <span class="input-label">Personal Website</span>
  <br/>
 -<com:TTextBox ID="Website" AutoTrim="true" />
 +<com:TTextBox ID="Website" AutoTrim="true" Columns="40"/>
  <br/>
 +<br/>
 -<com:TLinkButton Text="Register" ValidationGroup="NewUser" OnClick="createUser" />
 +<com:TLinkButton
 +	Text="Register"
 +	ValidationGroup="user"
 +	CssClass="link-button"
 +	OnClick="createUser" />
  </com:TContent>
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Users/NewUser.php b/demos/blog/protected/Pages/Users/NewUser.php index 166abf66..50a8100b 100644 --- a/demos/blog/protected/Pages/Users/NewUser.php +++ b/demos/blog/protected/Pages/Users/NewUser.php @@ -1,10 +1,33 @@  <?php
 +/**
 + * NewUser class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * NewUser class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class NewUser extends BlogPage
  {
 +	public function onInit($param)
 +	{
 +		if(!$this->User->IsAdmin && !TPropertyValue::ensureBoolean($this->Application->Parameters['MultipleUser']))
 +			throw new BlogException(500,'newuser_registration_disallowed');
 +	}
 +
  	public function checkUsername($sender,$param)
  	{
 -		$username=$this->Username->Text;
 +		$username=strtolower($this->Username->Text);
  		$param->IsValid=$this->DataAccess->queryUserByName($username)===null;
  	}
 @@ -13,13 +36,17 @@ class NewUser extends BlogPage  		if($this->IsValid)
  		{
  			$userRecord=new UserRecord;
 -			$userRecord->Name=$this->Username->Text;
 +			$userRecord->Name=strtolower($this->Username->Text);
  			$userRecord->FullName=$this->FullName->Text;
  			$userRecord->Role=0;
  			$userRecord->Password=md5($this->Password->Text);
  			$userRecord->Email=$this->Email->Text;
  			$userRecord->CreateTime=time();
  			$userRecord->Website=$this->Website->Text;
 +			if(TPropertyValue::ensureBoolean($this->Application->Parameters['AccountApproval']))
 +				$userRecord->Status=UserRecord::STATUS_PENDING;
 +			else
 +				$userRecord->Status=UserRecord::STATUS_NORMAL;
  			$this->DataAccess->insertUser($userRecord);
  			$authManager=$this->Application->getModule('auth');
  			$authManager->login($this->Username->Text,$this->Password->Text);
 diff --git a/demos/blog/protected/Pages/Users/ViewUser.page b/demos/blog/protected/Pages/Users/ViewUser.page index 2dba6b77..faae720b 100644 --- a/demos/blog/protected/Pages/Users/ViewUser.page +++ b/demos/blog/protected/Pages/Users/ViewUser.page @@ -1,21 +1,40 @@ +<%@ Title="View User Profile" %>
 +
  <com:TContent ID="Main">
  <h2>User Profile</h2>
 -Username: <%= $this->CurrentUser->Name %>
 -<br/>
 -
 -Full name: <%= $this->CurrentUser->FullName %>
 -<br/>
 -
 -Email: <%= $this->CurrentUser->Email %>
 +<table class="profile-table">
 +<tr>
 +  <td class="profile-table-label">Username</td>
 +  <td class="profile-table-value"><%= $this->Profile->Name %></td>
 +</tr>
 +<tr>
 +  <td class="profile-table-label">Full name</td>
 +  <td class="profile-table-value"><%= htmlentities($this->Profile->FullName,ENT_QUOTES,'UTF-8') %></td>
 +</tr>
 +<tr>
 +  <td class="profile-table-label">Email</td>
 +  <td class="profile-table-value"><%= $this->Profile->Email %></td>
 +</tr>
 +<tr>
 +  <td class="profile-table-label">Role</td>
 +  <td class="profile-table-value"><%= $this->Profile->Role===0? 'Normal user':'Administrator' %></td>
 +</tr>
 +<tr>
 +  <td class="profile-table-label">Website</td>
 +  <td class="profile-table-value"><%= htmlentities($this->Profile->Website,ENT_QUOTES,'UTF-8') %></td>
 +</tr>
 +<tr>
 +  <td class="profile-table-label">Member since</td>
 +  <td class="profile-table-value"><%= date('l, F j, Y',$this->Profile->CreateTime) %></td>
 +</tr>
 +</table>
  <br/>
 -
 -Privilege: <%= $this->CurrentUser->Role===0? 'User':'Administrator' %>
 -<br/>
 -
 -Personal website: <%= $this->CurrentUser->Website %>
 -<br/>
 -
 +<com:THyperLink
 +	Text="Update"
 +	NavigateUrl=<%= $this->Service->constructUrl('Users.EditUser',array('id'=>$this->Profile->ID)) %>
 +	Visible=<%= $this->User->IsAdmin || $this->Profile->ID===$this->User->ID %>
 +	CssClass="link-button" />
  </com:TContent>
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Users/ViewUser.php b/demos/blog/protected/Pages/Users/ViewUser.php index 3485f56b..453ae349 100644 --- a/demos/blog/protected/Pages/Users/ViewUser.php +++ b/demos/blog/protected/Pages/Users/ViewUser.php @@ -1,18 +1,41 @@  <?php
 +/**
 + * ViewUser class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * ViewUser class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class ViewUser extends BlogPage
  {
 -	private $_currentUser=null;
 +	private $_userRecord=null;
 -	public function getCurrentUser()
 +	public function onInit($param)
  	{
 -		if($this->_currentUser===null)
 -		{
 -			$id=TPropertyValue::ensureInteger($this->Request['id']);
 -			if(($this->_currentUser=$this->DataAccess->queryUserByID($id))===null)
 -				throw new BlogException('xxx');
 -		}
 -		return $this->_currentUser;
 +		parent::onInit($param);
 +		if(($id=$this->Request['id'])!==null)
 +			$id=TPropertyValue::ensureInteger($id);
 +		else
 +			$id=$this->User->ID;
 +		if(($this->_userRecord=$this->DataAccess->queryUserByID($id))===null)
 +			throw new BlogException(500,'profile_id_invalid',$id);
 +		$this->_userRecord->Email=strtr(strtoupper($this->_userRecord->Email),array('@'=>' at ','.'=>' dot '));
 +	}
 +
 +	public function getProfile()
 +	{
 +		return $this->_userRecord;
  	}
  }
 diff --git a/demos/blog/protected/Portlets/AccountPortlet.php b/demos/blog/protected/Portlets/AccountPortlet.php index 0f0e60c6..3618d92d 100644 --- a/demos/blog/protected/Portlets/AccountPortlet.php +++ b/demos/blog/protected/Portlets/AccountPortlet.php @@ -1,7 +1,24 @@  <?php
 +/**
 + * AccountPortlet class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
  Prado::using('Application.Portlets.Portlet');
 +/**
 + * AccountPortlet class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class AccountPortlet extends Portlet
  {
  	public function logout($sender,$param)
 diff --git a/demos/blog/protected/Portlets/AccountPortlet.tpl b/demos/blog/protected/Portlets/AccountPortlet.tpl index 2a401f41..a55b7857 100644 --- a/demos/blog/protected/Portlets/AccountPortlet.tpl +++ b/demos/blog/protected/Portlets/AccountPortlet.tpl @@ -9,7 +9,7 @@ Welcome, <b><%= $this->User->Name %></b>!  <li><a href="<%= $this->Service->constructUrl('Posts.MyPost') %>">My post</a></li>
  <li><a href="<%= $this->Service->constructUrl('Users.ViewUser',array('id'=>$this->User->ID)) %>">Profile</a></li>
  <%%
 -if($this->User->isInRole('admin'))
 +if($this->User->IsAdmin)
      echo '<li><a href="'.$this->Service->constructUrl('Admin.PostMan').'">Admin</a></li>';
  %>
  <li><com:TLinkButton Text="Logout" OnClick="logout" /></li>
 diff --git a/demos/blog/protected/Portlets/ArchivePortlet.php b/demos/blog/protected/Portlets/ArchivePortlet.php index a004c7a9..c50f0785 100644 --- a/demos/blog/protected/Portlets/ArchivePortlet.php +++ b/demos/blog/protected/Portlets/ArchivePortlet.php @@ -1,7 +1,24 @@  <?php
 +/**
 + * ArchivePortlet class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
  Prado::using('Application.Portlets.Portlet');
 +/**
 + * ArchivePortlet class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class ArchivePortlet extends Portlet
  {
  	private function makeMonthTime($timestamp)
 diff --git a/demos/blog/protected/Portlets/CategoryPortlet.php b/demos/blog/protected/Portlets/CategoryPortlet.php index 9c2033aa..e0c417bb 100644 --- a/demos/blog/protected/Portlets/CategoryPortlet.php +++ b/demos/blog/protected/Portlets/CategoryPortlet.php @@ -1,13 +1,36 @@  <?php
 +/**
 + * CategoryPortlet class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
  Prado::using('Application.Portlets.Portlet');
 +/**
 + * CategoryPortlet class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class CategoryPortlet extends Portlet
  {
  	public function onLoad($param)
  	{
  		parent::onLoad($param);
 -		$this->CategoryList->DataSource=$this->Application->getModule('data')->queryCategories();
 +		$cats=$this->Application->getModule('data')->queryCategories();
 +		foreach($cats as $cat)
 +		{
 +			$cat->ID=$this->Service->constructUrl('Posts.ListPost',array('cat'=>$cat->ID));
 +			$cat->Name.=' (' . $cat->PostCount .')';
 +		}
 +		$this->CategoryList->DataSource=$cats;
  		$this->CategoryList->dataBind();
  	}
  }
 diff --git a/demos/blog/protected/Portlets/CategoryPortlet.tpl b/demos/blog/protected/Portlets/CategoryPortlet.tpl index acbd3bec..dd5623ff 100644 --- a/demos/blog/protected/Portlets/CategoryPortlet.tpl +++ b/demos/blog/protected/Portlets/CategoryPortlet.tpl @@ -6,19 +6,17 @@ Categories  	Text="[+]"
  	Tooltip="Create a new category"
  	NavigateUrl=<%= $this->Service->constructUrl('Posts.NewCategory') %>
 -	Visible=<%= $this->User->isInRole('admin') %> />
 +	Visible=<%= $this->User->IsAdmin %> />
  </h2>
  <div class="portlet-content">
 -<ul>
 -<com:TRepeater ID="CategoryList" EnableViewState="false">
 -	<prop:ItemTemplate>
 -	<li>
 -	<a href="<%# $this->Service->constructUrl('Posts.ListPost',array('cat'=>$this->DataItem->ID)) %>"><%# $this->DataItem->Name . ' (' . $this->DataItem->PostCount . ')' %></a>
 -	</li>
 -	</prop:ItemTemplate>
 -</com:TRepeater>
 -</ul>
 +<com:TBulletedList
 +	ID="CategoryList"
 +	DisplayMode="HyperLink"
 +	DataTextField="Name"
 +	DataValueField="ID"
 +	EnableViewState="false"
 +	/>
  </div><!-- end of portlet-content -->
  </div><!-- end of portlet -->
 diff --git a/demos/blog/protected/Portlets/LoginPortlet.php b/demos/blog/protected/Portlets/LoginPortlet.php index 0085c17f..ae9373cb 100644 --- a/demos/blog/protected/Portlets/LoginPortlet.php +++ b/demos/blog/protected/Portlets/LoginPortlet.php @@ -1,13 +1,30 @@  <?php
 +/**
 + * LoginPortlet class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
  Prado::using('Application.Portlets.Portlet');
 +/**
 + * LoginPortlet class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class LoginPortlet extends Portlet
  {
  	public function validateUser($sender,$param)
  	{
  		$authManager=$this->Application->getModule('auth');
 -		if(!$authManager->login($this->Username->Text,$this->Password->Text))
 +		if(!$authManager->login(strtolower($this->Username->Text),$this->Password->Text))
  			$param->IsValid=false;
  	}
 diff --git a/demos/blog/protected/Portlets/LoginPortlet.tpl b/demos/blog/protected/Portlets/LoginPortlet.tpl index 6f8c5d4a..f2ac7f36 100644 --- a/demos/blog/protected/Portlets/LoginPortlet.tpl +++ b/demos/blog/protected/Portlets/LoginPortlet.tpl @@ -23,13 +23,19 @@ Password  <br/>
  <com:TTextBox ID="Password" TextMode="Password" />
 -<br/>
 +<br/><br/>
 +
  <com:TLinkButton
  	ID="LoginButton"
  	Text="Login"
  	ValidationGroup="login"
 +	CssClass="link-button"
  	OnClick="loginButtonClicked" />
 -| <a href="<%= $this->Service->constructUrl('Users.NewUser') %>">Register</a>
 +<com:THyperLink
 +	Text="Register"
 +	NavigateUrl=<%= $this->Service->constructUrl('Users.NewUser') %>
 +	Visible=<%= TPropertyValue::ensureBoolean($this->Application->Parameters['MultipleUser']) %>
 +	CssClass="link-button" />
  </com:TPanel><!-- end of portlet-content -->
 diff --git a/demos/blog/protected/Portlets/Portlet.php b/demos/blog/protected/Portlets/Portlet.php index 4b1c80e9..a3b03a71 100644 --- a/demos/blog/protected/Portlets/Portlet.php +++ b/demos/blog/protected/Portlets/Portlet.php @@ -1,5 +1,22 @@  <?php
 +/**
 + * Portlet class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
 +/**
 + * Portlet class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class Portlet extends TTemplateControl
  {
  }
 diff --git a/demos/blog/protected/Portlets/SearchPortlet.php b/demos/blog/protected/Portlets/SearchPortlet.php index 1bad7f1c..102bf79d 100644 --- a/demos/blog/protected/Portlets/SearchPortlet.php +++ b/demos/blog/protected/Portlets/SearchPortlet.php @@ -1,7 +1,24 @@  <?php
 +/**
 + * SearchPortlet class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + */
  Prado::using('Application.Portlets.Portlet');
 +/**
 + * SearchPortlet class
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + */
  class SearchPortlet extends Portlet
  {
  	public function onInit($param)
 diff --git a/demos/blog/protected/Portlets/SearchPortlet.tpl b/demos/blog/protected/Portlets/SearchPortlet.tpl index f88fca7e..32cbbf1d 100644 --- a/demos/blog/protected/Portlets/SearchPortlet.tpl +++ b/demos/blog/protected/Portlets/SearchPortlet.tpl @@ -11,10 +11,12 @@ Keyword  	Display="Dynamic"/>
  <br/>
  <com:TTextBox ID="Keyword" />
 +<br/><br/>
  <com:TLinkButton
  	ID="SearchButton"
  	Text="Search"
  	ValidationGroup="search"
 +	CssClass="link-button"
  	OnClick="search" />
  </com:TPanel><!-- end of portlet-content -->
 diff --git a/demos/blog/protected/application.xml b/demos/blog/protected/application.xml index 39c66431..4a18c74b 100644 --- a/demos/blog/protected/application.xml +++ b/demos/blog/protected/application.xml @@ -1,24 +1,19 @@  <?xml version="1.0" encoding="utf-8"?>
 -<application id="personal" mode="Debug">
 +<application id="blog" mode="Debug">
    <paths>
      <using namespace="Application.Common.*" />
    </paths>
    <!-- modules configured and loaded for all services -->
    <modules>
 -    <!-- Remove this comment mark to enable caching
 -    <module id="cache" class="System.Caching.TSqliteCache" />
 -    -->
      <!-- Remove this comment mark to enable PATH url format
      <module id="request" class="THttpRequest" UrlFormat="Path" />
      -->
 -    <!--
 -    <module id="session" class="THttpSession" />
 +    <module id="cache" class="System.Caching.TSqliteCache" />
 +    <module class="Application.Common.BlogErrorHandler" />
      <module id="log" class="System.Util.TLogRouter">
 -      <route class="TBrowserLogRoute" />
 -      <route class="TFileLogRoute" Categories="System" Levels="Notice,Warning,Error,Alert,Fatal" />
 +      <route class="TFileLogRoute" Categories="BlogApplication" />
      </module>
 -    -->
      <module class="System.Util.TParameterModule" ParameterFile="Application.Data.Settings" />
    </modules>
    <services>
 diff --git a/demos/blog/themes/Fall/style.css b/demos/blog/themes/Fall/style.css new file mode 100644 index 00000000..27975b05 --- /dev/null +++ b/demos/blog/themes/Fall/style.css @@ -0,0 +1,356 @@ +html {
 +	margin: 0;
 +	padding: 0;
 +}
 +
 +body {
 +	margin: 0;
 +	padding: 0;
 +	font-family: verdana, 'trebuchet ms', sans-serif;
 +	font-size: 10pt;
 +	color: #333;
 +	background-color: gray;
 +	min-width:750px;
 +}
 +
 +form {
 +	margin: 0;
 +	padding: 0;
 +}
 +
 +a {
 +	color: #806C40;
 +}
 +
 +a:hover {
 +	color: red;
 +}
 +
 +a img {
 +	border: 0px none;
 +}
 +
 +#page {
 +	background-color:#fff;
 +	margin:0 auto;
 +	width:800px;
 +}
 +
 +#header {
 +	background-color: #FFD980;
 +	border-bottom: 1px solid silver;
 +}
 +
 +#header h1 {
 +	padding:5px;
 +	padding-left: 20px;
 +    margin:0;
 +	font-size: 16pt;
 +}
 +
 +#header h2 {
 +	padding:5px;
 +	padding-left: 20px;
 +    margin:0;
 +   	color: #806C40;
 +	font-size: 11pt;
 +}
 +
 +#header a {
 +	color: #806C40;
 +	text-decoration: none;
 +}
 +
 +#main {
 +	background-color:#fff;
 +	float:left;
 +	width:560px;
 +	padding: 20px;
 +}
 +
 +#main h2 {
 +	border-bottom: 1px solid silver;
 +}
 +
 +#sidebar {
 +	background-color:#FFF7E6;
 +	float:right;
 +	width:200px;
 +}
 +
 +#sidebar ul {
 +	margin-bottom:0;
 +}
 +
 +#sidebar h3, #sidebar p {
 +	padding:0 10px 0 0;
 +}
 +
 +#footer {
 +	background-color:#fff;
 +	clear:both;
 +	color: gray;
 +	font-size:8pt;
 +	text-align:center;
 +	padding-top:25px;
 +	padding-bottom:10px;
 +}
 +
 +.portlet {
 +	margin: 10px;
 +	border-bottom: 1px solid silver;
 +	border-right: 1px solid silver;
 +	background-color: #FFECBF;
 +}
 +
 +.portlet-title {
 +	/* ie win (5, 5.5, 6) bugfix */
 +	p\osition: relative;
 +	width: 100%;
 +	w\idth: auto;
 +
 +	margin: 0;
 +	border-left: 5px solid #BFA260;
 +	padding: 5px;
 +	color: #fff;
 +	background-color: #FFD980;
 +	font-size: 8pt;
 +	font-weight: bold;
 +	line-height: 1;
 +	text-transform: uppercase;
 +}
 +
 +.portlet-title a {
 +	color: #806C40;
 +	text-decoration: none;
 +	text-transform: none;
 +}
 +
 +.portlet-title a:hover {
 +	color: red;
 +}
 +
 +.portlet-content {
 +	margin: 0 0 10px 0;
 +	padding: 10px 10px 0 10px;
 +	font-size: 10px;
 +}
 +
 +.portlet-content ul {
 +	margin: 0 15px 10px 15px;
 +	padding: 0;
 +	list-style: square;
 +}
 +
 +.portlet-content li {
 +	color: #666;
 +	margin-top: 3px;
 +}
 +
 +.portlet-content a {
 +	text-decoration: none;
 +}
 +
 +.portlet-content a:hover {
 +	color: red;
 +}
 +
 +.post {
 +	margin-bottom: 15px;
 +}
 +
 +.post-title {
 +	font-size: 14pt;
 +	border-bottom: 1px silver solid;
 +}
 +
 +.post-time {
 +	font-size: 8pt;
 +	color: gray;
 +}
 +
 +.post-content {
 +	margin-top: 10px;
 +	margin-bottom: 10px;
 +}
 +
 +.post-footer {
 +	text-align: right;
 +	font-size: 8pt;
 +}
 +
 +.post-footer a {
 +	color: #806C40;
 +}
 +
 +.comments {
 +	border-top: 1px silver solid;
 +}
 +
 +.comments h3 {
 +	font-size: 12pt;
 +}
 +
 +.comment {
 +	margin-bottom: 10px;
 +}
 +
 +.comment-header {
 +	background-color: #FFF7E6;
 +	padding: 3px;
 +	font-size: 8pt;
 +}
 +
 +.grid {
 +	width: 100%;
 +}
 +
 +.grid td {
 +	padding: 3px;
 +}
 +
 +.grid-header {
 +	color: #fff;
 +	background-color: #FFD980;
 +}
 +
 +.grid-row1 {
 +	background-color: #FFECBF;
 +}
 +
 +.grid-row2 {
 +	background-color: #FFF7E6;
 +}
 +
 +.grid-row-selected {
 +	background-color: lightyellow;
 +}
 +
 +.grid-pager {
 +	text-align: right;
 +	color: silver;
 +}
 +
 +.grid-pager a {
 +	color: green;
 +	text-decoration: none;
 +}
 +
 +.submenu {
 +	margin-bottom: 10px;
 +	border-bottom: 5px solid #FFD980;
 +	padding-right: 10px;
 +	text-align: right;
 +}
 +
 +.submenu ul {
 +	margin:0;
 +	padding:0;
 +	list-style:none;
 +}
 +
 +.submenu li {
 +	display:inline;
 +	margin:0;
 +	padding:0;
 +}
 +
 +.submenu-active {
 +	color: white;
 +	text-decoration: none;
 +	background-color: #FFD980;
 +	padding: 3px 5px 0 5px;
 +}
 +
 +.submenu-inactive {
 +	text-decoration: none;
 +	background-color: #FFECBF;
 +	padding: 3px 5px 0 5px;
 +}
 +
 +.input-label {
 +}
 +
 +.input-error1, .input-error2, .input-error3 {
 +	border: 1px solid red;
 +	background-color: lightyellow;
 +}
 +
 +.link-button {
 +}
 +
 +.link-button:link, .link-button:visited {
 +	color:#284E98;
 +	padding: 3px;
 +	background-color:#FFECBF;
 +	text-decoration: none;
 +	margin-right: 2px;
 +	border-right:1px solid gray;
 +	border-bottom:1px solid gray;
 +}
 +
 +.link-button:link.active, .link-button:visited.active, .link-button:hover {
 +	color:red;
 +	background-color:#FFF7E6;
 +}
 +
 +.profile-table {
 +	width: 100%;
 +	background-color: #aaa;
 +	border-collapse: collapse;
 +}
 +
 +.profile-table td {
 +	padding: 5px;
 +	border: 1px solid #BFA260;
 +}
 +
 +.profile-table-label {
 +	background-color: #FFD980;
 +	color: white;
 +	font-weight: bold;
 +}
 +
 +.profile-table-value {
 +	background-color: #FFECBF;
 +}
 +
 +.category {
 +	padding: 5px;
 +	margin-bottom: 10px;
 +	border-bottom: 1px solid silver;
 +	border-right: 1px solid silver;
 +	background-color: #FFECBF;
 +}
 +
 +.category-name {
 +	font-weight: bold;
 +}
 +
 +.category-name a {
 +	color: #806C40;
 +	text-decoration: none;
 +	text-transform: none;
 +}
 +
 +.category-description {
 +	font-style: italic;
 +}
 +
 +.postlist-pager {
 +	text-align: right;
 +	margin-top: 30px;
 +	border-top: 1px solid silver;
 +}
 +
 +.postlist-pager a {
 +	text-decoration: none;
 +}
 +
 +.search-title {
 +	padding: 5px;
 +	margin-bottom: 10px;
 +	border-bottom: 1px solid silver;
 +	border-right: 1px solid silver;
 +	background-color: #FFECBF;
 +}
 diff --git a/demos/blog/themes/Spring/style.css b/demos/blog/themes/Spring/style.css new file mode 100644 index 00000000..7066669c --- /dev/null +++ b/demos/blog/themes/Spring/style.css @@ -0,0 +1,356 @@ +html {
 +	margin: 0;
 +	padding: 0;
 +}
 +
 +body {
 +	margin: 0;
 +	padding: 0;
 +	font-family: verdana, 'trebuchet ms', sans-serif;
 +	font-size: 10pt;
 +	color: #333;
 +	background-color: gray;
 +	min-width:750px;
 +}
 +
 +form {
 +	margin: 0;
 +	padding: 0;
 +}
 +
 +a {
 +	color: #008F00;
 +}
 +
 +a:hover {
 +	color: red;
 +}
 +
 +a img {
 +	border: 0px none;
 +}
 +
 +#page {
 +	background-color:#fff;
 +	margin:0 auto;
 +	width:800px;
 +}
 +
 +#header {
 +	background-color: #008F00;
 +	border-bottom: 1px solid silver;
 +}
 +
 +#header h1 {
 +	padding:5px;
 +	padding-left: 20px;
 +    margin:0;
 +	font-size: 16pt;
 +}
 +
 +#header h2 {
 +	padding:5px;
 +	padding-left: 20px;
 +    margin:0;
 +   	color: #EEE;
 +	font-size: 11pt;
 +}
 +
 +#header a {
 +	color: #EEE;
 +	text-decoration: none;
 +}
 +
 +#main {
 +	background-color:#fff;
 +	float:left;
 +	width:560px;
 +	padding: 20px;
 +}
 +
 +#main h2 {
 +	border-bottom: 1px solid silver;
 +}
 +
 +#sidebar {
 +	background-color:#E6FFE6;
 +	float:right;
 +	width:200px;
 +}
 +
 +#sidebar ul {
 +	margin-bottom:0;
 +}
 +
 +#sidebar h3, #sidebar p {
 +	padding:0 10px 0 0;
 +}
 +
 +#footer {
 +	background-color:#fff;
 +	clear:both;
 +	color: gray;
 +	font-size:8pt;
 +	text-align:center;
 +	padding-top:25px;
 +	padding-bottom:10px;
 +}
 +
 +.portlet {
 +	margin: 10px;
 +	border-bottom: 1px solid silver;
 +	border-right: 1px solid silver;
 +	background-color: #B6F2B6;
 +}
 +
 +.portlet-title {
 +	/* ie win (5, 5.5, 6) bugfix */
 +	p\osition: relative;
 +	width: 100%;
 +	w\idth: auto;
 +
 +	margin: 0;
 +	border-left: 5px solid #BFA260;
 +	padding: 5px;
 +	color: #fff;
 +	background-color: #008F00;
 +	font-size: 8pt;
 +	font-weight: bold;
 +	line-height: 1;
 +	text-transform: uppercase;
 +}
 +
 +.portlet-title a {
 +	color: #008F00;
 +	text-decoration: none;
 +	text-transform: none;
 +}
 +
 +.portlet-title a:hover {
 +	color: red;
 +}
 +
 +.portlet-content {
 +	margin: 0 0 10px 0;
 +	padding: 10px 10px 0 10px;
 +	font-size: 10px;
 +}
 +
 +.portlet-content ul {
 +	margin: 0 15px 10px 15px;
 +	padding: 0;
 +	list-style: square;
 +}
 +
 +.portlet-content li {
 +	color: #666;
 +	margin-top: 3px;
 +}
 +
 +.portlet-content a {
 +	text-decoration: none;
 +}
 +
 +.portlet-content a:hover {
 +	color: red;
 +}
 +
 +.post {
 +	margin-bottom: 15px;
 +}
 +
 +.post-title {
 +	font-size: 14pt;
 +	border-bottom: 1px silver solid;
 +}
 +
 +.post-time {
 +	font-size: 8pt;
 +	color: gray;
 +}
 +
 +.post-content {
 +	margin-top: 10px;
 +	margin-bottom: 10px;
 +}
 +
 +.post-footer {
 +	text-align: right;
 +	font-size: 8pt;
 +}
 +
 +.post-footer a {
 +	color: #008F00;
 +}
 +
 +.comments {
 +	border-top: 1px silver solid;
 +}
 +
 +.comments h3 {
 +	font-size: 12pt;
 +}
 +
 +.comment {
 +	margin-bottom: 10px;
 +}
 +
 +.comment-header {
 +	background-color: #E6FFE6;
 +	padding: 3px;
 +	font-size: 8pt;
 +}
 +
 +.grid {
 +	width: 100%;
 +}
 +
 +.grid td {
 +	padding: 3px;
 +}
 +
 +.grid-header {
 +	color: #fff;
 +	background-color: #008F00;
 +}
 +
 +.grid-row1 {
 +	background-color: #B6F2B6;
 +}
 +
 +.grid-row2 {
 +	background-color: #E6FFE6;
 +}
 +
 +.grid-row-selected {
 +	background-color: lightyellow;
 +}
 +
 +.grid-pager {
 +	text-align: right;
 +	color: silver;
 +}
 +
 +.grid-pager a {
 +	color: green;
 +	text-decoration: none;
 +}
 +
 +.submenu {
 +	margin-bottom: 10px;
 +	border-bottom: 5px solid #008F00;
 +	padding-right: 10px;
 +	text-align: right;
 +}
 +
 +.submenu ul {
 +	margin:0;
 +	padding:0;
 +	list-style:none;
 +}
 +
 +.submenu li {
 +	display:inline;
 +	margin:0;
 +	padding:0;
 +}
 +
 +.submenu-active {
 +	text-decoration: none;
 +	color: white;
 +	background-color: #008F00;
 +	padding: 3px 5px 0 5px;
 +}
 +
 +.submenu-inactive {
 +	text-decoration: none;
 +	background-color: #B6F2B6;
 +	padding: 3px 5px 0 5px;
 +}
 +
 +.input-label {
 +}
 +
 +.input-error1, .input-error2, .input-error3 {
 +	border: 1px solid red;
 +	background-color: lightyellow;
 +}
 +
 +.link-button {
 +}
 +
 +.link-button:link, .link-button:visited {
 +	color:#284E98;
 +	padding: 3px;
 +	background-color:#B6F2B6;
 +	text-decoration: none;
 +	margin-right: 2px;
 +	border-right:1px solid gray;
 +	border-bottom:1px solid gray;
 +}
 +
 +.link-button:link.active, .link-button:visited.active, .link-button:hover {
 +	color:red;
 +	background-color:#E6FFE6;
 +}
 +
 +.profile-table {
 +	width: 100%;
 +	background-color: #aaa;
 +	border-collapse: collapse;
 +}
 +
 +.profile-table td {
 +	padding: 5px;
 +	border: 1px solid #BFA260;
 +}
 +
 +.profile-table-label {
 +	background-color: #008F00;
 +	color: white;
 +	font-weight: bold;
 +}
 +
 +.profile-table-value {
 +	background-color: #B6F2B6;
 +}
 +
 +.category {
 +	padding: 5px;
 +	margin-bottom: 10px;
 +	border-bottom: 1px solid silver;
 +	border-right: 1px solid silver;
 +	background-color: #B6F2B6;
 +}
 +
 +.category-name {
 +	font-weight: bold;
 +}
 +
 +.category-name a {
 +	color: #008F00;
 +	text-decoration: none;
 +	text-transform: none;
 +}
 +
 +.category-description {
 +	font-style: italic;
 +}
 +
 +.postlist-pager {
 +	text-align: right;
 +	margin-top: 30px;
 +	border-top: 1px solid silver;
 +}
 +
 +.postlist-pager a {
 +	text-decoration: none;
 +}
 +
 +.search-title {
 +	padding: 5px;
 +	margin-bottom: 10px;
 +	border-bottom: 1px solid silver;
 +	border-right: 1px solid silver;
 +	background-color: #B6F2B6;
 +}
 diff --git a/demos/blog/themes/Summer/style.css b/demos/blog/themes/Summer/style.css new file mode 100644 index 00000000..068860d1 --- /dev/null +++ b/demos/blog/themes/Summer/style.css @@ -0,0 +1,356 @@ +html {
 +	margin: 0;
 +	padding: 0;
 +}
 +
 +body {
 +	margin: 0;
 +	padding: 0;
 +	font-family: verdana, 'trebuchet ms', sans-serif;
 +	font-size: 10pt;
 +	color: #333;
 +	background-color: gray;
 +	min-width:750px;
 +}
 +
 +form {
 +	margin: 0;
 +	padding: 0;
 +}
 +
 +a {
 +	color: #BF6060;
 +}
 +
 +a:hover {
 +	color: red;
 +}
 +
 +a img {
 +	border: 0px none;
 +}
 +
 +#page {
 +	background-color:#fff;
 +	margin:0 auto;
 +	width:800px;
 +}
 +
 +#header {
 +	background-color: #F2B6B6;
 +	border-bottom: 1px solid silver;
 +}
 +
 +#header h1 {
 +	padding:5px;
 +	padding-left: 20px;
 +    margin:0;
 +	font-size: 16pt;
 +}
 +
 +#header h2 {
 +	padding:5px;
 +	padding-left: 20px;
 +    margin:0;
 +   	color: #BF6060;
 +	font-size: 11pt;
 +}
 +
 +#header a {
 +	color: #BF6060;
 +	text-decoration: none;
 +}
 +
 +#main {
 +	background-color:#fff;
 +	float:left;
 +	width:560px;
 +	padding: 20px;
 +}
 +
 +#main h2 {
 +	border-bottom: 1px solid silver;
 +}
 +
 +#sidebar {
 +	background-color:#FFE6E6;
 +	float:right;
 +	width:200px;
 +}
 +
 +#sidebar ul {
 +	margin-bottom:0;
 +}
 +
 +#sidebar h3, #sidebar p {
 +	padding:0 10px 0 0;
 +}
 +
 +#footer {
 +	background-color:#fff;
 +	clear:both;
 +	color: gray;
 +	font-size:8pt;
 +	text-align:center;
 +	padding-top:25px;
 +	padding-bottom:10px;
 +}
 +
 +.portlet {
 +	margin: 10px;
 +	border-bottom: 1px solid silver;
 +	border-right: 1px solid silver;
 +	background-color: #FFBFBF;
 +}
 +
 +.portlet-title {
 +	/* ie win (5, 5.5, 6) bugfix */
 +	p\osition: relative;
 +	width: 100%;
 +	w\idth: auto;
 +
 +	margin: 0;
 +	border-left: 5px solid #BFA260;
 +	padding: 5px;
 +	color: #fff;
 +	background-color: #FF8080;
 +	font-size: 8pt;
 +	font-weight: bold;
 +	line-height: 1;
 +	text-transform: uppercase;
 +}
 +
 +.portlet-title a {
 +	color: #BF6060;
 +	text-decoration: none;
 +	text-transform: none;
 +}
 +
 +.portlet-title a:hover {
 +	color: red;
 +}
 +
 +.portlet-content {
 +	margin: 0 0 10px 0;
 +	padding: 10px 10px 0 10px;
 +	font-size: 10px;
 +}
 +
 +.portlet-content ul {
 +	margin: 0 15px 10px 15px;
 +	padding: 0;
 +	list-style: square;
 +}
 +
 +.portlet-content li {
 +	color: #666;
 +	margin-top: 3px;
 +}
 +
 +.portlet-content a {
 +	text-decoration: none;
 +}
 +
 +.portlet-content a:hover {
 +	color: red;
 +}
 +
 +.post {
 +	margin-bottom: 15px;
 +}
 +
 +.post-title {
 +	font-size: 14pt;
 +	border-bottom: 1px silver solid;
 +}
 +
 +.post-time {
 +	font-size: 8pt;
 +	color: gray;
 +}
 +
 +.post-content {
 +	margin-top: 10px;
 +	margin-bottom: 10px;
 +}
 +
 +.post-footer {
 +	text-align: right;
 +	font-size: 8pt;
 +}
 +
 +.post-footer a {
 +	color: #BF6060;
 +}
 +
 +.comments {
 +	border-top: 1px silver solid;
 +}
 +
 +.comments h3 {
 +	font-size: 12pt;
 +}
 +
 +.comment {
 +	margin-bottom: 10px;
 +}
 +
 +.comment-header {
 +	background-color: #FFE6E6;
 +	padding: 3px;
 +	font-size: 8pt;
 +}
 +
 +.grid {
 +	width: 100%;
 +}
 +
 +.grid td {
 +	padding: 3px;
 +}
 +
 +.grid-header {
 +	color: #fff;
 +	background-color: #FF8080;
 +}
 +
 +.grid-row1 {
 +	background-color: #FFBFBF;
 +}
 +
 +.grid-row2 {
 +	background-color: #FFE6E6;
 +}
 +
 +.grid-row-selected {
 +	background-color: lightyellow;
 +}
 +
 +.grid-pager {
 +	text-align: right;
 +	color: silver;
 +}
 +
 +.grid-pager a {
 +	color: green;
 +	text-decoration: none;
 +}
 +
 +.submenu {
 +	margin-bottom: 10px;
 +	border-bottom: 5px solid #FF8080;
 +	padding-right: 10px;
 +	text-align: right;
 +}
 +
 +.submenu ul {
 +	margin:0;
 +	padding:0;
 +	list-style:none;
 +}
 +
 +.submenu li {
 +	display:inline;
 +	margin:0;
 +	padding:0;
 +}
 +
 +.submenu-active {
 +	color: white;
 +	text-decoration: none;
 +	background-color: #FF8080;
 +	padding: 3px 5px 0 5px;
 +}
 +
 +.submenu-inactive {
 +	text-decoration: none;
 +	background-color: #FFBFBF;
 +	padding: 3px 5px 0 5px;
 +}
 +
 +.input-label {
 +}
 +
 +.input-error1, .input-error2, .input-error3 {
 +	border: 1px solid red;
 +	background-color: lightyellow;
 +}
 +
 +.link-button {
 +}
 +
 +.link-button:link, .link-button:visited {
 +	color:#284E98;
 +	padding: 3px;
 +	background-color:#FFBFBF;
 +	text-decoration: none;
 +	margin-right: 2px;
 +	border-right:1px solid gray;
 +	border-bottom:1px solid gray;
 +}
 +
 +.link-button:link.active, .link-button:visited.active, .link-button:hover {
 +	color:red;
 +	background-color:#FFE6E6;
 +}
 +
 +.profile-table {
 +	width: 100%;
 +	background-color: #aaa;
 +	border-collapse: collapse;
 +}
 +
 +.profile-table td {
 +	padding: 5px;
 +	border: 1px solid #BFA260;
 +}
 +
 +.profile-table-label {
 +	background-color: #FF8080;
 +	color: white;
 +	font-weight: bold;
 +}
 +
 +.profile-table-value {
 +	background-color: #FFBFBF;
 +}
 +
 +.category {
 +	padding: 5px;
 +	margin-bottom: 10px;
 +	border-bottom: 1px solid silver;
 +	border-right: 1px solid silver;
 +	background-color: #FFBFBF;
 +}
 +
 +.category-name {
 +	font-weight: bold;
 +}
 +
 +.category-name a {
 +	color: #BF6060;
 +	text-decoration: none;
 +	text-transform: none;
 +}
 +
 +.category-description {
 +	font-style: italic;
 +}
 +
 +.postlist-pager {
 +	text-align: right;
 +	margin-top: 30px;
 +	border-top: 1px solid silver;
 +}
 +
 +.postlist-pager a {
 +	text-decoration: none;
 +}
 +
 +.search-title {
 +	padding: 5px;
 +	margin-bottom: 10px;
 +	border-bottom: 1px solid silver;
 +	border-right: 1px solid silver;
 +	background-color: #FFBFBF;
 +}
 diff --git a/demos/blog/themes/Basic/style.css b/demos/blog/themes/Winter/style.css index b8e9ca89..4eadd18e 100644 --- a/demos/blog/themes/Basic/style.css +++ b/demos/blog/themes/Winter/style.css @@ -7,7 +7,7 @@ body {  	margin: 0;
  	padding: 0;
  	font-family: verdana, 'trebuchet ms', sans-serif;
 -	font-size: 12px;
 +	font-size: 10pt;
  	color: #333;
  	background: #36414d;
  	min-width:750px;
 @@ -19,7 +19,11 @@ form {  }
  a {
 -	text-decoration: underline;
 +	color: #36414d;
 +}
 +
 +a:hover {
 +	color: red;
  }
  a img {
 @@ -51,6 +55,11 @@ a img {  	font-size: 12pt;
  }
 +#header a {
 +	color: black;
 +	text-decoration: none;
 +}
 +
  #main {
  	background:#fff;
  	float:left;
 @@ -258,4 +267,91 @@ a img {  	text-decoration: none;
  	background: #dae0e6;
  	padding: 3px 5px 0 5px;
 -}
\ No newline at end of file +}
 +
 +.input-label {
 +}
 +
 +.input-error1, .input-error2, .input-error3 {
 +	border: 1px solid red;
 +	background-color: lightyellow;
 +}
 +
 +.link-button {
 +}
 +
 +.link-button:link, .link-button:visited {
 +	color:#284E98;
 +	padding: 3px;
 +	background-color:#dae0e6;
 +	text-decoration: none;
 +	margin-right: 2px;
 +	border-right:1px solid gray;
 +	border-bottom:1px solid gray;
 +}
 +
 +.link-button:link.active, .link-button:visited.active, .link-button:hover {
 +	color:red;
 +	background-color:#e6ecf2;
 +}
 +
 +.profile-table {
 +	width: 100%;
 +	background-color: #aaa;
 +	border-collapse: collapse;
 +}
 +
 +.profile-table td {
 +	padding: 5px;
 +	border: 1px solid #36414d;
 +}
 +
 +.profile-table-label {
 +	background-color: #a3b8cc;
 +	color: white;
 +	font-weight: bold;
 +}
 +
 +.profile-table-value {
 +	background-color: #dae0e6;
 +}
 +
 +.category {
 +	padding: 5px;
 +	margin-bottom: 10px;
 +	border-bottom: 1px solid silver;
 +	border-right: 1px solid silver;
 +	background: #dae0e6;
 +}
 +
 +.category-name {
 +	font-weight: bold;
 +}
 +
 +.category-name a {
 +	color: yellow;
 +	text-decoration: none;
 +	text-transform: none;
 +}
 +
 +.category-description {
 +	font-style: italic;
 +}
 +
 +.postlist-pager {
 +	text-align: right;
 +	margin-top: 30px;
 +	border-top: 1px solid silver;
 +}
 +
 +.postlist-pager a {
 +	text-decoration: none;
 +}
 +
 +.search-title {
 +	padding: 5px;
 +	margin-bottom: 10px;
 +	border-bottom: 1px solid silver;
 +	border-right: 1px solid silver;
 +	background: #dae0e6;
 +}
  | 
