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 | |
parent | 7f508e187e4539a16cdbb1dd6a4b1133c53cf24d (diff) |
Blog demo is completed.
60 files changed, 2261 insertions, 252 deletions
diff --git a/.gitattributes b/.gitattributes index 7a91eef7..089a43be 100644 --- a/.gitattributes +++ b/.gitattributes @@ -26,7 +26,7 @@ buildscripts/texbuilder/pages.php -text buildscripts/texbuilder/prado3_quick_start.tex -text demos/blog/index.php -text demos/blog/protected/Common/BlogDataModule.php -text -demos/blog/protected/Common/BlogErrors.php -text +demos/blog/protected/Common/BlogErrorHandler.php -text demos/blog/protected/Common/BlogException.php -text demos/blog/protected/Common/BlogPage.php -text demos/blog/protected/Common/BlogUser.php -text @@ -43,7 +43,6 @@ demos/blog/protected/Pages/Admin/ConfigMan.page -text demos/blog/protected/Pages/Admin/ConfigMan.php -text demos/blog/protected/Pages/Admin/PostMan.page -text demos/blog/protected/Pages/Admin/PostMan.php -text -demos/blog/protected/Pages/Admin/Settings.page -text demos/blog/protected/Pages/Admin/UserMan.page -text demos/blog/protected/Pages/Admin/UserMan.php -text demos/blog/protected/Pages/Admin/config.xml -text @@ -64,6 +63,8 @@ demos/blog/protected/Pages/Posts/NewPost.php -text demos/blog/protected/Pages/Posts/ViewPost.page -text demos/blog/protected/Pages/Posts/ViewPost.php -text demos/blog/protected/Pages/Posts/config.xml -text +demos/blog/protected/Pages/SearchPost.page -text +demos/blog/protected/Pages/SearchPost.php -text demos/blog/protected/Pages/Users/EditUser.page -text demos/blog/protected/Pages/Users/EditUser.php -text demos/blog/protected/Pages/Users/NewUser.page -text @@ -83,7 +84,10 @@ demos/blog/protected/Portlets/Portlet.php -text demos/blog/protected/Portlets/SearchPortlet.php -text demos/blog/protected/Portlets/SearchPortlet.tpl -text demos/blog/protected/application.xml -text -demos/blog/themes/Basic/style.css -text +demos/blog/themes/Fall/style.css -text +demos/blog/themes/Spring/style.css -text +demos/blog/themes/Summer/style.css -text +demos/blog/themes/Winter/style.css -text demos/composer/index.php -text demos/composer/index2.php -text demos/composer/protected/pages/ClassDefinition.php -text @@ -22,6 +22,7 @@ CHG: Ticket#151 - URL format is modified to handle empty GET values (Qiang) CHG: Ticket#153 - TAssetManager now ignores .svn directories (Qiang)
NEW: TTableHeaderRow, TTableFooterRow and table section support (Qiang)
NEW: TCompositeControl (Qiang)
+NEW: Blog demo (Qiang)
Version 3.0.0 May 1, 2006
=========================
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
-
-// post status: 0 - draft, 1 - published
-// comment status: 0 - awaiting approval, 1 - published
+/**
+ * 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: $
+ */
+
+/**
+ * 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;
+}
diff --git a/framework/Web/UI/WebControls/THyperLink.php b/framework/Web/UI/WebControls/THyperLink.php index 1a5db69d..5489727c 100644 --- a/framework/Web/UI/WebControls/THyperLink.php +++ b/framework/Web/UI/WebControls/THyperLink.php @@ -22,10 +22,6 @@ * If both {@link getImageUrl ImageUrl} and {@link getText Text} are empty,
* the content enclosed within the control tag will be rendered.
*
- * Note, {@link getText Text} is not HTML-encoded when displayed.
- * Make sure it does not contain unwanted characters that may bring
- * security vulnerabilities.
- *
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Revision: $ $Date: $
* @package System.Web.UI.WebControls
@@ -66,7 +62,7 @@ class THyperLink extends TWebControl if(($imageUrl=$this->getImageUrl())==='')
{
if(($text=$this->getText())!=='')
- $writer->write($text);
+ $writer->write(THttpUtility::htmlEncode($text));
else
parent::renderContents($writer);
}
@@ -77,7 +73,7 @@ class THyperLink extends TWebControl if(($toolTip=$this->getToolTip())!=='')
$image->setToolTip($toolTip);
if(($text=$this->getText())!=='')
- $image->setAlternateText($text);
+ $image->setAlternateText(THttpUtility::htmlEncode($text));
$image->renderControl($writer);
}
}
|