From 05869f23f798c9393e2bc6d310d56a97a11d1acd Mon Sep 17 00:00:00 2001 From: xue <> Date: Mon, 29 May 2006 02:05:19 +0000 Subject: Added blog demo (not done yet) --- demos/blog/index.php | 18 + demos/blog/protected/Common/BlogDataModule.php | 535 +++++++++++++++++++++ demos/blog/protected/Common/BlogErrors.php | 23 + demos/blog/protected/Common/BlogException.php | 14 + demos/blog/protected/Common/BlogPage.php | 26 + demos/blog/protected/Common/BlogUser.php | 38 ++ demos/blog/protected/Common/BlogUserManager.php | 56 +++ demos/blog/protected/Common/XListMenu.php | 127 +++++ demos/blog/protected/Common/messages.txt | 4 + demos/blog/protected/Common/schema.sql | 70 +++ demos/blog/protected/Data/Options.xml | 8 + demos/blog/protected/Layouts/MainLayout.php | 7 + demos/blog/protected/Layouts/MainLayout.tpl | 47 ++ demos/blog/protected/Pages/Admin/AdminMenu.php | 7 + demos/blog/protected/Pages/Admin/AdminMenu.tpl | 16 + demos/blog/protected/Pages/Admin/ConfigMan.page | 56 +++ demos/blog/protected/Pages/Admin/ConfigMan.php | 15 + demos/blog/protected/Pages/Admin/PostMan.page | 76 +++ demos/blog/protected/Pages/Admin/PostMan.php | 56 +++ demos/blog/protected/Pages/Admin/Settings.page | 4 + demos/blog/protected/Pages/Admin/UserMan.page | 95 ++++ demos/blog/protected/Pages/Admin/UserMan.php | 58 +++ demos/blog/protected/Pages/Admin/config.xml | 8 + demos/blog/protected/Pages/ErrorReport.page | 15 + demos/blog/protected/Pages/ErrorReport.php | 12 + demos/blog/protected/Pages/Posts/EditCategory.page | 36 ++ demos/blog/protected/Pages/Posts/EditCategory.php | 44 ++ demos/blog/protected/Pages/Posts/EditPost.page | 41 ++ demos/blog/protected/Pages/Posts/EditPost.php | 51 ++ demos/blog/protected/Pages/Posts/ListPost.page | 27 ++ demos/blog/protected/Pages/Posts/ListPost.php | 44 ++ demos/blog/protected/Pages/Posts/MyPost.page | 46 ++ demos/blog/protected/Pages/Posts/MyPost.php | 34 ++ demos/blog/protected/Pages/Posts/NewCategory.page | 36 ++ demos/blog/protected/Pages/Posts/NewCategory.php | 24 + demos/blog/protected/Pages/Posts/NewPost.page | 41 ++ demos/blog/protected/Pages/Posts/NewPost.php | 34 ++ demos/blog/protected/Pages/Posts/ViewPost.page | 113 +++++ demos/blog/protected/Pages/Posts/ViewPost.php | 73 +++ demos/blog/protected/Pages/Posts/config.xml | 7 + demos/blog/protected/Pages/Users/EditUser.page | 74 +++ demos/blog/protected/Pages/Users/EditUser.php | 43 ++ demos/blog/protected/Pages/Users/NewUser.page | 104 ++++ demos/blog/protected/Pages/Users/NewUser.php | 31 ++ demos/blog/protected/Pages/Users/ViewUser.page | 21 + demos/blog/protected/Pages/Users/ViewUser.php | 19 + demos/blog/protected/Pages/Users/config.xml | 7 + demos/blog/protected/Portlets/AccountPortlet.php | 14 + demos/blog/protected/Portlets/AccountPortlet.tpl | 20 + demos/blog/protected/Portlets/ArchivePortlet.php | 45 ++ demos/blog/protected/Portlets/ArchivePortlet.tpl | 15 + demos/blog/protected/Portlets/CategoryPortlet.php | 15 + demos/blog/protected/Portlets/CategoryPortlet.tpl | 24 + demos/blog/protected/Portlets/LoginPortlet.php | 22 + demos/blog/protected/Portlets/LoginPortlet.tpl | 36 ++ demos/blog/protected/Portlets/Portlet.php | 7 + demos/blog/protected/Portlets/SearchPortlet.php | 22 + demos/blog/protected/Portlets/SearchPortlet.tpl | 21 + demos/blog/protected/application.xml | 38 ++ demos/blog/sitemap.txt | 106 ++++ demos/blog/themes/Basic/style.css | 261 ++++++++++ 61 files changed, 2987 insertions(+) create mode 100644 demos/blog/index.php create mode 100644 demos/blog/protected/Common/BlogDataModule.php create mode 100644 demos/blog/protected/Common/BlogErrors.php create mode 100644 demos/blog/protected/Common/BlogException.php create mode 100644 demos/blog/protected/Common/BlogPage.php create mode 100644 demos/blog/protected/Common/BlogUser.php create mode 100644 demos/blog/protected/Common/BlogUserManager.php create mode 100644 demos/blog/protected/Common/XListMenu.php create mode 100644 demos/blog/protected/Common/messages.txt create mode 100644 demos/blog/protected/Common/schema.sql create mode 100644 demos/blog/protected/Data/Options.xml create mode 100644 demos/blog/protected/Layouts/MainLayout.php create mode 100644 demos/blog/protected/Layouts/MainLayout.tpl create mode 100644 demos/blog/protected/Pages/Admin/AdminMenu.php create mode 100644 demos/blog/protected/Pages/Admin/AdminMenu.tpl create mode 100644 demos/blog/protected/Pages/Admin/ConfigMan.page create mode 100644 demos/blog/protected/Pages/Admin/ConfigMan.php create mode 100644 demos/blog/protected/Pages/Admin/PostMan.page create mode 100644 demos/blog/protected/Pages/Admin/PostMan.php create mode 100644 demos/blog/protected/Pages/Admin/Settings.page create mode 100644 demos/blog/protected/Pages/Admin/UserMan.page create mode 100644 demos/blog/protected/Pages/Admin/UserMan.php create mode 100644 demos/blog/protected/Pages/Admin/config.xml create mode 100644 demos/blog/protected/Pages/ErrorReport.page create mode 100644 demos/blog/protected/Pages/ErrorReport.php create mode 100644 demos/blog/protected/Pages/Posts/EditCategory.page create mode 100644 demos/blog/protected/Pages/Posts/EditCategory.php create mode 100644 demos/blog/protected/Pages/Posts/EditPost.page create mode 100644 demos/blog/protected/Pages/Posts/EditPost.php create mode 100644 demos/blog/protected/Pages/Posts/ListPost.page create mode 100644 demos/blog/protected/Pages/Posts/ListPost.php create mode 100644 demos/blog/protected/Pages/Posts/MyPost.page create mode 100644 demos/blog/protected/Pages/Posts/MyPost.php create mode 100644 demos/blog/protected/Pages/Posts/NewCategory.page create mode 100644 demos/blog/protected/Pages/Posts/NewCategory.php create mode 100644 demos/blog/protected/Pages/Posts/NewPost.page create mode 100644 demos/blog/protected/Pages/Posts/NewPost.php create mode 100644 demos/blog/protected/Pages/Posts/ViewPost.page create mode 100644 demos/blog/protected/Pages/Posts/ViewPost.php create mode 100644 demos/blog/protected/Pages/Posts/config.xml create mode 100644 demos/blog/protected/Pages/Users/EditUser.page create mode 100644 demos/blog/protected/Pages/Users/EditUser.php create mode 100644 demos/blog/protected/Pages/Users/NewUser.page create mode 100644 demos/blog/protected/Pages/Users/NewUser.php create mode 100644 demos/blog/protected/Pages/Users/ViewUser.page create mode 100644 demos/blog/protected/Pages/Users/ViewUser.php create mode 100644 demos/blog/protected/Pages/Users/config.xml create mode 100644 demos/blog/protected/Portlets/AccountPortlet.php create mode 100644 demos/blog/protected/Portlets/AccountPortlet.tpl create mode 100644 demos/blog/protected/Portlets/ArchivePortlet.php create mode 100644 demos/blog/protected/Portlets/ArchivePortlet.tpl create mode 100644 demos/blog/protected/Portlets/CategoryPortlet.php create mode 100644 demos/blog/protected/Portlets/CategoryPortlet.tpl create mode 100644 demos/blog/protected/Portlets/LoginPortlet.php create mode 100644 demos/blog/protected/Portlets/LoginPortlet.tpl create mode 100644 demos/blog/protected/Portlets/Portlet.php create mode 100644 demos/blog/protected/Portlets/SearchPortlet.php create mode 100644 demos/blog/protected/Portlets/SearchPortlet.tpl create mode 100644 demos/blog/protected/application.xml create mode 100644 demos/blog/sitemap.txt create mode 100644 demos/blog/themes/Basic/style.css (limited to 'demos') diff --git a/demos/blog/index.php b/demos/blog/index.php new file mode 100644 index 00000000..43c0b436 --- /dev/null +++ b/demos/blog/index.php @@ -0,0 +1,18 @@ +run(); + +?> \ No newline at end of file diff --git a/demos/blog/protected/Common/BlogDataModule.php b/demos/blog/protected/Common/BlogDataModule.php new file mode 100644 index 00000000..714743e7 --- /dev/null +++ b/demos/blog/protected/Common/BlogDataModule.php @@ -0,0 +1,535 @@ +connectDatabase(); + } + + public function getDbFile() + { + if($this->_dbFile===null) + $this->_dbFile=Prado::getPathOfNamespace(self::DEFAULT_DB_FILE,self::DB_FILE_EXT); + return $this->_dbFile; + } + + public function setDbFile($value) + { + if(($this->_dbFile=Prado::getPathOfNamespace($value,self::DB_FILE_EXT))===null) + throw new BlogException('blogdatamodule_dbfile_invalid',$value); + } + + protected function createDatabase() + { + $schemaFile=dirname(__FILE__).'/schema.sql'; + $statements=explode(';',file_get_contents($schemaFile)); + foreach($statements as $statement) + { + 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); + } + } + } + + protected function connectDatabase() + { + $dbFile=$this->getDbFile(); + $newDb=!is_file($dbFile); + $error=''; + if(($this->_db=sqlite_open($dbFile,0666,$error))===false) + throw new BlogException('blogdatamodule_dbconnect_failed',$error); + if($newDb) + $this->createDatabase(); + } + + protected function generateModifier($filter,$orderBy,$limit) + { + $modifier=''; + if($filter!=='') + $modifier=' WHERE '.$filter; + if($orderBy!=='') + $modifier.=' ORDER BY '.$orderBy; + if($limit!=='') + $modifier.=' LIMIT '.$limit; + return $modifier; + } + + public function query($sql) + { + 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); + } + + protected function populateUserRecord($row) + { + $userRecord=new UserRecord; + $userRecord->ID=(integer)$row['id']; + $userRecord->Name=$row['name']; + $userRecord->FullName=$row['full_name']; + $userRecord->Role=(integer)$row['role']; + $userRecord->Password=$row['passwd']; + $userRecord->VerifyCode=$row['vcode']; + $userRecord->Email=$row['email']; + $userRecord->CreateTime=(integer)$row['reg_time']; + $userRecord->Status=(integer)$row['status']; + $userRecord->Website=$row['website']; + return $userRecord; + } + + public function queryUsers($filter='',$orderBy='',$limit='') + { + if($filter!=='') + $filter='WHERE '.$filter; + $sql="SELECT * FROM tblUsers $filter $orderBy $limit"; + $result=$this->query($sql); + $rows=sqlite_fetch_all($result,SQLITE_ASSOC); + $users=array(); + foreach($rows as $row) + $users[]=$this->populateUserRecord($row); + return $users; + } + + public function queryUserCount($filter) + { + if($filter!=='') + $filter='WHERE '.$filter; + $sql="SELECT COUNT(id) AS user_count FROM tblUsers $filter"; + $result=$this->query($sql); + if(($row=sqlite_fetch_array($result,SQLITE_ASSOC))!==false) + return $row['user_count']; + else + return 0; + } + + public function queryUserByID($id) + { + $sql="SELECT * FROM tblUsers WHERE id=$id"; + $result=$this->query($sql); + if(($row=sqlite_fetch_array($result,SQLITE_ASSOC))!==false) + return $this->populateUserRecord($row); + else + return null; + } + + public function queryUserByName($name) + { + $name=sqlite_escape_string($name); + $sql="SELECT * FROM tblUsers WHERE name='$name'"; + $result=$this->query($sql); + if(($row=sqlite_fetch_array($result,SQLITE_ASSOC))!==false) + return $this->populateUserRecord($row); + else + return null; + } + + public function insertUser($user) + { + $name=sqlite_escape_string($user->Name); + $fullName=sqlite_escape_string($user->FullName); + $passwd=sqlite_escape_string($user->Password); + $email=sqlite_escape_string($user->Email); + $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')"; + $this->query($sql); + $user->ID=sqlite_last_insert_rowid($this->_db); + } + + public function updateUser($user) + { + $name=sqlite_escape_string($user->Name); + $fullName=sqlite_escape_string($user->FullName); + $passwd=sqlite_escape_string($user->Password); + $email=sqlite_escape_string($user->Email); + $website=sqlite_escape_string($user->Website); + $sql="UPDATE tblUsers SET + name='$name', + full_name='$fullName', + role={$user->Role}, + passwd='$passwd', + vcode='{$user->VerifyCode}', + email='$email', + status={$user->Status}, + website='$website' + WHERE id={$user->ID}"; + $this->query($sql); + } + + public function deleteUser($id) + { + $this->query("DELETE FROM tblUsers WHERE id=$id"); + } + + protected function populatePostRecord($row) + { + $postRecord=new PostRecord; + $postRecord->ID=(integer)$row['id']; + $postRecord->AuthorID=(integer)$row['author_id']; + if($row['author_full_name']!=='') + $postRecord->AuthorName=$row['author_full_name']; + else + $postRecord->AuthorName=$row['author_name']; + $postRecord->CreateTime=(integer)$row['create_time']; + $postRecord->ModifyTime=(integer)$row['modify_time']; + $postRecord->Title=$row['title']; + $postRecord->Content=$row['content']; + $postRecord->Status=(integer)$row['status']; + $postRecord->CommentCount=(integer)$row['comment_count']; + return $postRecord; + } + + public function queryPosts($authorFilter,$timeFilter,$categoryFilter,$orderBy,$limit) + { + $filter=''; + if($authorFilter!=='') + $filter.=" AND $authorFilter"; + if($timeFilter!=='') + $filter.=" AND $timeFilter"; + if($categoryFilter!=='') + $filter.=" AND a.id IN (SELECT post_id AS id FROM tblPost2Category WHERE $categoryFilter)"; + $sql="SELECT a.id AS id, + a.author_id AS author_id, + b.name AS author_name, + b.full_name AS author_full_name, + a.create_time AS create_time, + a.modify_time AS modify_time, + a.title AS title, + a.content AS content, + a.status AS status, + a.comment_count AS comment_count + FROM tblPosts a, tblUsers b + WHERE a.author_id=b.id $filter $orderBy $limit"; + $result=$this->query($sql); + $rows=sqlite_fetch_all($result,SQLITE_ASSOC); + $posts=array(); + foreach($rows as $row) + $posts[]=$this->populatePostRecord($row); + return $posts; + } + + public function queryPostCount($authorFilter,$timeFilter,$categoryFilter) + { + $filter=''; + if($authorFilter!=='') + $filter.=" AND $authorFilter"; + if($timeFilter!=='') + $filter.=" AND $timeFilter"; + if($categoryFilter!=='') + $filter.=" AND a.id IN (SELECT post_id AS id FROM tblPost2Category WHERE $categoryFilter)"; + $sql="SELECT COUNT(a.id) AS post_count + FROM tblPosts a, tblUsers b + WHERE a.author_id=b.id $filter"; + $result=$this->query($sql); + if(($row=sqlite_fetch_array($result,SQLITE_ASSOC))!==false) + return $row['post_count']; + else + return 0; + } + + public function queryPostByID($id) + { + $sql="SELECT a.id AS id, + a.author_id AS author_id, + b.name AS author_name, + b.full_name AS author_full_name, + a.create_time AS create_time, + a.modify_time AS modify_time, + a.title AS title, + a.content AS content, + a.status AS status, + a.comment_count AS comment_count + FROM tblPosts a, tblUsers b + WHERE a.id=$id AND a.author_id=b.id"; + $result=$this->query($sql); + if(($row=sqlite_fetch_array($result,SQLITE_ASSOC))!==false) + return $this->populatePostRecord($row); + else + return null; + } + + public function insertPost($post,$catIDs) + { + $title=sqlite_escape_string($post->Title); + $content=sqlite_escape_string($post->Content); + $sql="INSERT INTO tblPosts + (author_id,create_time,title,content,status) + VALUES ({$post->AuthorID},{$post->CreateTime},'$title','$content',{$post->Status})"; + $this->query($sql); + $post->ID=sqlite_last_insert_rowid($this->_db); + foreach($catIDs as $catID) + $this->insertPostCategory($post->ID,$catID); + } + + public function updatePost($post,$newCatIDs=null) + { + if($newCatIDs!==null) + { + $cats=$this->queryCategoriesByPostID($post->ID); + $catIDs=array(); + foreach($cats as $cat) + $catIDs[]=$cat->ID; + $deleteIDs=array_diff($catIDs,$newCatIDs); + foreach($deleteIDs as $id) + $this->deletePostCategory($post->ID,$id); + $insertIDs=array_diff($newCatIDs,$catIDs); + foreach($insertIDs as $id) + $this->insertPostCategory($post->ID,$id); + } + + $title=sqlite_escape_string($post->Title); + $content=sqlite_escape_string($post->Content); + $sql="UPDATE tblPosts SET + modify_time={$post->ModifyTime}, + title='$title', + content='$content', + status={$post->Status} + WHERE id={$post->ID}"; + $this->query($sql); + } + + public function deletePost($id) + { + $cats=$this->queryCategoriesByPostID($id); + foreach($cats as $cat) + $this->deletePostCategory($id,$cat->ID); + $this->query("DELETE FROM tblComments WHERE post_id=$id"); + $this->query("DELETE FROM tblPosts WHERE id=$id"); + } + + protected function populateCommentRecord($row) + { + $commentRecord=new CommentRecord; + $commentRecord->ID=(integer)$row['id']; + $commentRecord->PostID=(integer)$row['post_id']; + $commentRecord->AuthorName=$row['author_name']; + $commentRecord->AuthorEmail=$row['author_email']; + $commentRecord->AuthorWebsite=$row['author_website']; + $commentRecord->AuthorIP=$row['author_ip']; + $commentRecord->CreateTime=(integer)$row['create_time']; + $commentRecord->Content=$row['content']; + $commentRecord->Status=(integer)$row['status']; + return $commentRecord; + } + + public function queryCommentsByPostID($id) + { + $sql="SELECT * FROM tblComments WHERE post_id=$id"; + $result=$this->query($sql); + $rows=sqlite_fetch_all($result,SQLITE_ASSOC); + $comments=array(); + foreach($rows as $row) + $comments[]=$this->populateCommentRecord($row); + return $comments; + } + + public function insertComment($comment) + { + $authorName=sqlite_escape_string($comment->AuthorName); + $authorEmail=sqlite_escape_string($comment->AuthorEmail); + $authorWebsite=sqlite_escape_string($comment->AuthorWebsite); + $content=sqlite_escape_string($comment->Content); + $sql="INSERT INTO tblComments + (post_id,author_name,author_email,author_website,author_ip,create_time,status,content) + VALUES ({$comment->PostID},'$authorName','$authorEmail','$authorWebsite','{$comment->AuthorIP}',{$comment->CreateTime},{$comment->Status},'$content')"; + $this->query($sql); + $comment->ID=sqlite_last_insert_rowid($this->_db); + $this->query("UPDATE tblPosts SET comment_count=comment_count+1 WHERE id={$comment->PostID}"); + } + + public function updateComment($comment) + { + $authorName=sqlite_escape_string($comment->AuthorName); + $authorEmail=sqlite_escape_string($comment->AuthorEmail); + $content=sqlite_escape_string($comment->Content); + $sql="UPDATE tblComments SET status={$comment->Status} WHERE id={$comment->ID}"; + $this->query($sql); + } + + public function deleteComment($id) + { + $result=$this->query("SELECT post_id FROM tblComments WHERE id=$id"); + if(($row=sqlite_fetch_array($result,SQLITE_ASSOC))!==false) + { + $postID=$row['post_id']; + $this->query("DELETE FROM tblComments WHERE id=$id"); + $this->query("UPDATE tblPosts SET comment_count=comment_count-1 WHERE id=$postID"); + } + } + + protected function populateCategoryRecord($row) + { + $catRecord=new CategoryRecord; + $catRecord->ID=(integer)$row['id']; + $catRecord->Name=$row['name']; + $catRecord->Description=$row['description']; + $catRecord->PostCount=$row['post_count']; + return $catRecord; + } + + public function queryCategories() + { + $sql="SELECT * FROM tblCategories"; + $result=$this->query($sql); + $rows=sqlite_fetch_all($result,SQLITE_ASSOC); + $cats=array(); + foreach($rows as $row) + $cats[]=$this->populateCategoryRecord($row); + return $cats; + } + + public function queryCategoriesByPostID($postID) + { + $sql="SELECT a.id AS id, + a.name AS name, + 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"; + $result=$this->query($sql); + $rows=sqlite_fetch_all($result,SQLITE_ASSOC); + $cats=array(); + foreach($rows as $row) + $cats[]=$this->populateCategoryRecord($row); + return $cats; + } + + public function queryCategoryByID($id) + { + $sql="SELECT * FROM tblCategories WHERE id=$id"; + $result=$this->query($sql); + if(($row=sqlite_fetch_array($result,SQLITE_ASSOC))!==false) + return $this->populateCategoryRecord($row); + else + return null; + } + + public function queryCategoryByName($name) + { + $name=sqlite_escape_string($name); + $sql="SELECT * FROM tblCategories WHERE name='$name'"; + $result=$this->query($sql); + if(($row=sqlite_fetch_array($result,SQLITE_ASSOC))!==false) + return $this->populateCategoryRecord($row); + else + return null; + } + + public function insertCategory($category) + { + $name=sqlite_escape_string($category->Name); + $description=sqlite_escape_string($category->Description); + $sql="INSERT INTO tblCategories + (name,description) + VALUES ('$name','$description')"; + $this->query($sql); + $category->ID=sqlite_last_insert_rowid($this->_db); + } + + public function updateCategory($category) + { + $name=sqlite_escape_string($category->Name); + $description=sqlite_escape_string($category->Description); + $sql="UPDATE tblCategories SET name='$name', description='$description', post_count={$category->PostCount} WHERE id={$category->ID}"; + $this->query($sql); + } + + public function deleteCategory($id) + { + $sql="DELETE FROM tblPost2Category WHERE category_id=$id"; + $this->query($sql); + $sql="DELETE FROM tblCategories WHERE id=$id"; + $this->query($sql); + } + + public function insertPostCategory($postID,$categoryID) + { + $sql="INSERT INTO tblPost2Category (post_id, category_id) VALUES ($postID, $categoryID)"; + $this->query($sql); + $sql="UPDATE tblCategories SET post_count=post_count+1 WHERE id=$categoryID"; + $this->query($sql); + } + + public function deletePostCategory($postID,$categoryID) + { + $sql="DELETE FROM tblPost2Category WHERE post_id=$postID AND category_id=$categoryID"; + if($this->query($sql)>0) + { + $sql="UPDATE tblCategories SET post_count=post_count-1 WHERE id=$categoryID"; + $this->query($sql); + } + } + + public function queryEarliestPostTime() + { + $sql="SELECT MIN(create_time) AS create_time FROM tblPosts"; + $result=$this->query($sql); + if(($row=sqlite_fetch_array($result,SQLITE_ASSOC))!==false) + return $row['create_time']; + else + return time(); + } +} + +class UserRecord +{ + public $ID; + public $Name; + public $FullName; + public $Role; + public $Password; + public $VerifyCode; + public $Email; + public $CreateTime; + public $Status; + public $Website; +} + +class PostRecord +{ + public $ID; + public $AuthorID; + public $AuthorName; + public $CreateTime; + public $ModifyTime; + public $Title; + public $Content; + public $Status; + public $CommentCount; +} + +class CommentRecord +{ + public $ID; + public $PostID; + public $AuthorName; + public $AuthorEmail; + public $AuthorWebsite; + public $AuthorIP; + public $CreateTime; + public $Status; + public $Content; +} + +class CategoryRecord +{ + public $ID; + public $Name; + public $Description; + public $PostCount; +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Common/BlogErrors.php b/demos/blog/protected/Common/BlogErrors.php new file mode 100644 index 00000000..501ec1c9 --- /dev/null +++ b/demos/blog/protected/Common/BlogErrors.php @@ -0,0 +1,23 @@ +'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 new file mode 100644 index 00000000..ab8020d1 --- /dev/null +++ b/demos/blog/protected/Common/BlogException.php @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/demos/blog/protected/Common/BlogPage.php b/demos/blog/protected/Common/BlogPage.php new file mode 100644 index 00000000..f1634a80 --- /dev/null +++ b/demos/blog/protected/Common/BlogPage.php @@ -0,0 +1,26 @@ +getApplication()->getModule('data'); + } + + public function gotoDefaultPage() + { + $this->Response->redirect($this->Service->constructUrl($this->Service->DefaultPage)); + } + + public function gotoPage($pagePath,$getParameters=null) + { + $this->Response->redirect($this->Service->constructUrl($pagePath,$getParameters)); + } + + public function reportError($errorCode) + { + $this->gotoPage('ErrorReport',array('id'=>$errorCode)); + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Common/BlogUser.php b/demos/blog/protected/Common/BlogUser.php new file mode 100644 index 00000000..af49c8d7 --- /dev/null +++ b/demos/blog/protected/Common/BlogUser.php @@ -0,0 +1,38 @@ +_id; + } + + public function setID($value) + { + $this->_id=$value; + } + + public function saveToString() + { + $a=array($this->_id,parent::saveToString()); + return serialize($a); + } + + public function loadFromString($data) + { + if(!empty($data)) + { + list($id,$str)=unserialize($data); + $this->_id=$id; + return parent::loadFromString($str); + } + else + return $this; + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Common/BlogUserManager.php b/demos/blog/protected/Common/BlogUserManager.php new file mode 100644 index 00000000..c3ddb80b --- /dev/null +++ b/demos/blog/protected/Common/BlogUserManager.php @@ -0,0 +1,56 @@ +Application->getModule('data'); + if(($userRecord=$db->queryUserByName($username))!==null) + { + $user=new BlogUser($this); + $user->setID($userRecord->ID); + $user->setName($username); + $user->setIsGuest(false); + $user->setRoles($userRecord->Role===0?'user':'admin'); + return $user; + } + else + return null; + } + } + + /** + * Validates if the username and password are correct. + * @param string user name + * @param string password + * @return boolean true if validation is successful, false otherwise. + */ + public function validateUser($username,$password) + { + $db=$this->Application->getModule('data'); + if(($userRecord=$db->queryUserByName($username))!==null) + return $userRecord->Password===md5($password); + else + return false; + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Common/XListMenu.php b/demos/blog/protected/Common/XListMenu.php new file mode 100644 index 00000000..f8223585 --- /dev/null +++ b/demos/blog/protected/Common/XListMenu.php @@ -0,0 +1,127 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2006 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Revision: $ $Date: $ + */ + +Prado::using('System.Web.UI.WebControls.TListControl'); + +/** + * XListMenu class + * + * XListMenu displays a list of hyperlinks that can be used for page menus. + * Menu items adjust their css class automatically according to the current + * page displayed. In particular, a menu item is considered as active if + * the URL it represents is for the page currently displayed. + * + * Usage of XListMenu is similar to PRADO list controls. Each list item has + * two extra properties: {@link XListMenuItem::setPagePath PagePath} and + * {@link XListMenuItem::setNavigateUrl NavigateUrl}. The former is used to + * determine if the item is active or not, while the latter specifies the + * URL for the item. If the latter is not specified, a URL to the page is + * generated automatically. + * + * In template, you may use the following tags to specify a menu: + * + * + * + * + * + * + * + * @author Qiang Xue + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2006 PradoSoft + * @license http://www.pradosoft.com/license/ + */ +class XListMenu extends TListControl +{ + public function addParsedObject($object) + { + if($object instanceof XListMenuItem) + parent::addParsedObject($object); + } + + public function getActiveCssClass() + { + return $this->getViewState('ActiveCssClass',''); + } + + public function setActiveCssClass($value) + { + $this->setViewState('ActiveCssClass',$value,''); + } + + public function getInactiveCssClass() + { + return $this->getViewState('InactiveCssClass',''); + } + + public function setInactiveCssClass($value) + { + $this->setViewState('InactiveCssClass',$value,''); + } + + public function render($writer) + { + if(($activeClass=$this->getActiveCssClass())!=='') + $activeClass=' class="'.$activeClass.'"'; + if(($inactiveClass=$this->getInactiveCssClass())!=='') + $inactiveClass=' class="'.$inactiveClass.'"'; + $currentPagePath=$this->getPage()->getPagePath(); + $writer->write(""); + } +} + +class XListMenuItem extends TListItem +{ + public function getPagePath() + { + return $this->getValue(); + } + + public function setPagePath($value) + { + $this->setValue($value); + } + + public function getNavigateUrl() + { + return $this->hasAttribute('NavigateUrl')?$this->getAttribute('NavigateUrl'):''; + } + + public function setNavigateUrl($value) + { + $this->setAttribute('NavigateUrl',$value); + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Common/messages.txt b/demos/blog/protected/Common/messages.txt new file mode 100644 index 00000000..deb15ee3 --- /dev/null +++ b/demos/blog/protected/Common/messages.txt @@ -0,0 +1,4 @@ +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 diff --git a/demos/blog/protected/Common/schema.sql b/demos/blog/protected/Common/schema.sql new file mode 100644 index 00000000..49f6f429 --- /dev/null +++ b/demos/blog/protected/Common/schema.sql @@ -0,0 +1,70 @@ +CREATE TABLE tblUsers ( + id INTEGER NOT NULL PRIMARY KEY, + name VARCHAR(128) NOT NULL UNIQUE, + full_name VARCHAR(128) DEFAULT '', + role INTEGER NOT NULL DEFAULT 0, /* 0: user, 1: admin */ + passwd VARCHAR(128) NOT NULL, + vcode VARCHAR(128) DEFAULT '', + email VARCHAR(128) NOT NULL, + reg_time INTEGER NOT NULL, + status INTEGER NOT NULL DEFAULT 0, /* 0: normal, 1: disabled, 2: pending approval */ + website VARCHAR(128) DEFAULT '' +); + +CREATE TABLE tblPosts ( + id INTEGER NOT NULL PRIMARY KEY, + author_id INTEGER NOT NULL, + create_time INTEGER NOT NULL, + modify_time INTEGER DEFAULT 0, + title VARCHAR(256) NOT NULL, + content TEXT NOT NULL, + status INTEGER NOT NULL DEFAULT 0, /* 0: published, 1: draft, 2: pending approval */ + comment_count INTEGER NOT NULL DEFAULT 0 +); + +CREATE TABLE tblComments ( + id INTEGER NOT NULL PRIMARY KEY, + post_id INTEGER NOT NULL, + author_name VARCHAR(64) NOT NULL, + author_email VARCHAR(128) NOT NULL, + author_website VARCHAR(128) DEFAULT '', + author_ip CHAR(16) NOT NULL, + create_time INTEGER NOT NULL, + status INTEGER NOT NULL DEFAULT 0, /* 0: published, 1: pending approval */ + content TEXT NOT NULL +); + +CREATE TABLE tblCategories ( + id INTEGER NOT NULL PRIMARY KEY, + name VARCHAR(128) NOT NULL UNIQUE, + description TEXT DEFAULT '', + post_count INTEGER NOT NULL DEFAULT 0 +); + +CREATE TABLE tblAttachments ( + id VARCHAR(128) NOT NULL PRIMARY KEY, + post_id INTEGER NOT NULL, + create_time INTEGER NOT NULL, + file_name VARCHAR(128) NOT NULL, + file_size INTEGER NOT NULL, + mime_type VARCHAR(32) NOT NULL DEFAULT 'text/html', + download_count INTEGER NOT NULL DEFAULT 0 +); + +CREATE TABLE tblPost2Category ( + post_id INTEGER NOT NULL, + category_id INTEGER NOT NULL, + PRIMARY KEY (post_id, category_id) +); + +INSERT INTO tblUsers (id,name,full_name,role,status,passwd,email,reg_time,website) + VALUES (1,'admin','Prado User',1,0,'4d688da592969d0a56b5accec3ce8554','admin@example.com',1148819681,'http://www.pradosoft.com'); + +INSERT INTO tblPosts (id,author_id,create_time,title,content,status) + VALUES (1,1,1148819691,'Welcome to Prado Weblog','Congratulations! You have successfully installed Prado Weblog. An administrator account has been created. Please login with admin/prado and update your password as soon as possible.',0); + +INSERT INTO tblCategories (name,description,post_count) + VALUES ('Miscellaneous','This category holds posts on any topic.',1); + +INSERT INTO tblPost2Category (post_id,category_id) + VALUES (1,1); diff --git a/demos/blog/protected/Data/Options.xml b/demos/blog/protected/Data/Options.xml new file mode 100644 index 00000000..02e51a98 --- /dev/null +++ b/demos/blog/protected/Data/Options.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/demos/blog/protected/Layouts/MainLayout.php b/demos/blog/protected/Layouts/MainLayout.php new file mode 100644 index 00000000..253d6c03 --- /dev/null +++ b/demos/blog/protected/Layouts/MainLayout.php @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/demos/blog/protected/Layouts/MainLayout.tpl b/demos/blog/protected/Layouts/MainLayout.tpl new file mode 100644 index 00000000..f171de7f --- /dev/null +++ b/demos/blog/protected/Layouts/MainLayout.tpl @@ -0,0 +1,47 @@ + + + + > + + + + + + + + +
+ + + + +
+ +
+ + + + + +
+
+ + \ No newline at end of file diff --git a/demos/blog/protected/Pages/Admin/AdminMenu.php b/demos/blog/protected/Pages/Admin/AdminMenu.php new file mode 100644 index 00000000..40f40b88 --- /dev/null +++ b/demos/blog/protected/Pages/Admin/AdminMenu.php @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/demos/blog/protected/Pages/Admin/AdminMenu.tpl b/demos/blog/protected/Pages/Admin/AdminMenu.tpl new file mode 100644 index 00000000..596f3ed2 --- /dev/null +++ b/demos/blog/protected/Pages/Admin/AdminMenu.tpl @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/demos/blog/protected/Pages/Admin/ConfigMan.page b/demos/blog/protected/Pages/Admin/ConfigMan.page new file mode 100644 index 00000000..ad728284 --- /dev/null +++ b/demos/blog/protected/Pages/Admin/ConfigMan.page @@ -0,0 +1,56 @@ + + +

Administration Center

+ + + + + +Title +
+ +
+ +Subtitle +
+ +
+ +Owner name +
+ +
+ +Owner email +
+ +
+ +Site theme +
+ +
+ +
+ + + + + +
+ + +
+ +
+ + + + +
+ +
+ + + +
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Admin/ConfigMan.php b/demos/blog/protected/Pages/Admin/ConfigMan.php new file mode 100644 index 00000000..dcbe1537 --- /dev/null +++ b/demos/blog/protected/Pages/Admin/ConfigMan.php @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/demos/blog/protected/Pages/Admin/PostMan.page b/demos/blog/protected/Pages/Admin/PostMan.page new file mode 100644 index 00000000..8ba8ef29 --- /dev/null +++ b/demos/blog/protected/Pages/Admin/PostMan.page @@ -0,0 +1,76 @@ + + +

Administration Center

+ + + + + + + + + <%# + $this->Parent->DataItem->Status===0 ? + 'Published' : + ($this->Parent->DataItem->Status===1 ? 'Draft' : 'Pending') + %> + + + Parent->DataItem->Status %> > + + + + + + + + + + +
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Admin/PostMan.php b/demos/blog/protected/Pages/Admin/PostMan.php new file mode 100644 index 00000000..a99332eb --- /dev/null +++ b/demos/blog/protected/Pages/Admin/PostMan.php @@ -0,0 +1,56 @@ +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->dataBind(); + } + + public function onLoad($param) + { + parent::onLoad($param); + if(!$this->IsPostBack) + $this->bindData(); + } + + public function changePage($sender,$param) + { + $this->PostGrid->CurrentPageIndex=$param->NewPageIndex; + $this->bindData(); + } + + public function pagerCreated($sender,$param) + { + $param->Pager->Controls->insertAt(0,'Page: '); + } + + public function editItem($sender,$param) + { + $this->PostGrid->EditItemIndex=$param->Item->ItemIndex; + $this->bindData(); + } + + public function saveItem($sender,$param) + { + $item=$param->Item; + $postID=$this->PostGrid->DataKeys[$item->ItemIndex]; + $postRecord=$this->DataAccess->queryPostByID($postID); + $postRecord->Status=TPropertyValue::ensureInteger($item->Cells[2]->PostStatus->SelectedValue); + $this->DataAccess->updatePost($postRecord); + $this->PostGrid->EditItemIndex=-1; + $this->bindData(); + } + + public function cancelItem($sender,$param) + { + $this->PostGrid->EditItemIndex=-1; + $this->bindData(); + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Pages/Admin/Settings.page b/demos/blog/protected/Pages/Admin/Settings.page new file mode 100644 index 00000000..48dfde96 --- /dev/null +++ b/demos/blog/protected/Pages/Admin/Settings.page @@ -0,0 +1,4 @@ + +Welcome, User->Name %> />! +This page contains site settings accessible only to site admin. + \ No newline at end of file diff --git a/demos/blog/protected/Pages/Admin/UserMan.page b/demos/blog/protected/Pages/Admin/UserMan.page new file mode 100644 index 00000000..a8b634c6 --- /dev/null +++ b/demos/blog/protected/Pages/Admin/UserMan.page @@ -0,0 +1,95 @@ + + +

Administration Center

+ + + + + + + + <%# $this->Parent->DataItem->Role===0 ? 'User' : 'Admin' %> + + + Parent->DataItem->Role %> > + + + + + + + + <%# + $this->Parent->DataItem->Status===0 ? + 'Normal' : + ($this->Parent->DataItem->Status===1 ? 'Disabled' : 'Pending') + %> + + + Parent->DataItem->Status %> > + + + + + + + + # + ''.{0}.'' + + + + + + +
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Admin/UserMan.php b/demos/blog/protected/Pages/Admin/UserMan.php new file mode 100644 index 00000000..1cb62482 --- /dev/null +++ b/demos/blog/protected/Pages/Admin/UserMan.php @@ -0,0 +1,58 @@ +User->ID; + $offset=$this->UserGrid->CurrentPageIndex*$this->UserGrid->PageSize; + $limit=$this->UserGrid->PageSize; + $this->UserGrid->DataSource=$this->DataAccess->queryUsers('','ORDER BY status DESC, name ASC',"LIMIT $offset,$limit"); + $this->UserGrid->VirtualItemCount=$this->DataAccess->queryUserCount(''); + $this->UserGrid->dataBind(); + } + + public function onLoad($param) + { + parent::onLoad($param); + if(!$this->IsPostBack) + $this->bindData(); + } + + public function changePage($sender,$param) + { + $this->UserGrid->CurrentPageIndex=$param->NewPageIndex; + $this->bindData(); + } + + public function pagerCreated($sender,$param) + { + $param->Pager->Controls->insertAt(0,'Page: '); + } + + public function editItem($sender,$param) + { + $this->UserGrid->EditItemIndex=$param->Item->ItemIndex; + $this->bindData(); + } + + public function saveItem($sender,$param) + { + $item=$param->Item; + $userID=$this->UserGrid->DataKeys[$item->ItemIndex]; + $userRecord=$this->DataAccess->queryUserByID($userID); + $userRecord->Role=TPropertyValue::ensureInteger($item->Cells[1]->UserRole->SelectedValue); + $userRecord->Status=TPropertyValue::ensureInteger($item->Cells[2]->UserStatus->SelectedValue); + $this->DataAccess->updateUser($userRecord); + $this->UserGrid->EditItemIndex=-1; + $this->bindData(); + } + + public function cancelItem($sender,$param) + { + $this->UserGrid->EditItemIndex=-1; + $this->bindData(); + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Pages/Admin/config.xml b/demos/blog/protected/Pages/Admin/config.xml new file mode 100644 index 00000000..c99e5892 --- /dev/null +++ b/demos/blog/protected/Pages/Admin/config.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/demos/blog/protected/Pages/ErrorReport.page b/demos/blog/protected/Pages/ErrorReport.page new file mode 100644 index 00000000..a9b461d9 --- /dev/null +++ b/demos/blog/protected/Pages/ErrorReport.page @@ -0,0 +1,15 @@ + + +

Error

+ +

+<%= $this->ErrorMessage %> +

+ +

+Please report to us +if you believe this error is caused by our system. Thanks! +

+ + +
\ No newline at end of file diff --git a/demos/blog/protected/Pages/ErrorReport.php b/demos/blog/protected/Pages/ErrorReport.php new file mode 100644 index 00000000..3b24170f --- /dev/null +++ b/demos/blog/protected/Pages/ErrorReport.php @@ -0,0 +1,12 @@ +Request['id']); + return BlogErrors::getMessage($id); + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/EditCategory.page b/demos/blog/protected/Pages/Posts/EditCategory.page new file mode 100644 index 00000000..fdde2648 --- /dev/null +++ b/demos/blog/protected/Pages/Posts/EditCategory.page @@ -0,0 +1,36 @@ + + +

Update Post Category

+ +Category name + + +
+ +
+ +Description +
+ +
+ + + +
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/EditCategory.php b/demos/blog/protected/Pages/Posts/EditCategory.php new file mode 100644 index 00000000..fd2d0707 --- /dev/null +++ b/demos/blog/protected/Pages/Posts/EditCategory.php @@ -0,0 +1,44 @@ +Request['id']); + if(($cat=$this->DataAccess->queryCategoryByID($id))!==null) + return $cat; + else + throw new BlogException('xxx'); + } + + public function onLoad($param) + { + parent::onLoad($param); + if(!$this->IsPostBack) + { + $catRecord=$this->getCurrentCategory(); + $this->CategoryName->Text=$catRecord->Name; + $this->CategoryDescription->Text=$catRecord->Description; + } + } + + public function saveButtonClicked($sender,$param) + { + 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)); + } + } + + public function checkCategoryName($sender,$param) + { + $name=$this->CategoryName->Text; + $param->IsValid=$this->DataAccess->queryCategoryByName($name)===null; + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/EditPost.page b/demos/blog/protected/Pages/Posts/EditPost.page new file mode 100644 index 00000000..591f5945 --- /dev/null +++ b/demos/blog/protected/Pages/Posts/EditPost.page @@ -0,0 +1,41 @@ + + +

Update Post

+ +Title + +
+ +
+ +Content + +
+ +
+ +Categories
+ +
+ + +
+ + + +
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/EditPost.php b/demos/blog/protected/Pages/Posts/EditPost.php new file mode 100644 index 00000000..57e92b1c --- /dev/null +++ b/demos/blog/protected/Pages/Posts/EditPost.php @@ -0,0 +1,51 @@ +Request['id']); + if(($post=$this->DataAccess->queryPostByID($id))!==null) + return $post; + else + throw new BlogException('xxx'); + } + + public function onLoad($param) + { + parent::onLoad($param); + if(!$this->IsPostBack) + { + $postRecord=$this->getCurrentPost(); + $this->Title->Text=$postRecord->Title; + $this->Content->Text=$postRecord->Content; + $this->DraftMode->Checked=$postRecord->Status===0; + $this->Categories->DataSource=$this->DataAccess->queryCategories(); + $this->Categories->dataBind(); + $cats=$this->DataAccess->queryCategoriesByPostID($postRecord->ID); + $catIDs=array(); + foreach($cats as $cat) + $catIDs[]=$cat->ID; + $this->Categories->SelectedValues=$catIDs; + } + } + + public function saveButtonClicked($sender,$param) + { + if($this->IsValid) + { + $postRecord=$this->getCurrentPost(); + $postRecord->Title=$this->Title->Text; + $postRecord->Content=$this->Content->Text; + $postRecord->Status=$this->DraftMode->Checked?0:1; + $postRecord->ModifyTime=time(); + $cats=array(); + foreach($this->Categories->SelectedValues as $value) + $cats[]=TPropertyValue::ensureInteger($value); + $this->DataAccess->updatePost($postRecord,$cats); + $this->gotoPage('Posts.ViewPost',array('id'=>$postRecord->ID)); + } + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/ListPost.page b/demos/blog/protected/Pages/Posts/ListPost.page new file mode 100644 index 00000000..15fc3d0c --- /dev/null +++ b/demos/blog/protected/Pages/Posts/ListPost.page @@ -0,0 +1,27 @@ + + + + +
+
+<%# $this->DataItem->Title %> +
+
+<%# date('l, F j, Y \a\t h:i:s a',$this->DataItem->CreateTime) %> +
+
+<%# $this->DataItem->Content %> +
+ +
+
+
+ +
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/ListPost.php b/demos/blog/protected/Pages/Posts/ListPost.php new file mode 100644 index 00000000..6d56b543 --- /dev/null +++ b/demos/blog/protected/Pages/Posts/ListPost.php @@ -0,0 +1,44 @@ +Request['time']))>0) + { + $year=(integer)($time/100); + $month=$time%100; + $startTime=mktime(0,0,0,$month,1,$year); + if(++$month>12) + { + $month=1; + $year++; + } + $endTime=mktime(0,0,0,$month,1,$year); + $timeFilter="create_time>=$startTime AND create_time<$endTime"; + } + if(($catID=$this->Request['cat'])!==null) + { + $catID=TPropertyValue::ensureInteger($catID); + $catFilter="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"); + } + + public function onLoad($param) + { + parent::onLoad($param); + $this->PostList->DataSource=$this->getPosts(); + $this->PostList->dataBind(); + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/MyPost.page b/demos/blog/protected/Pages/Posts/MyPost.page new file mode 100644 index 00000000..95a32ac9 --- /dev/null +++ b/demos/blog/protected/Pages/Posts/MyPost.page @@ -0,0 +1,46 @@ + + +

My Posts

+ + + + + + + + +
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/MyPost.php b/demos/blog/protected/Pages/Posts/MyPost.php new file mode 100644 index 00000000..be03ca63 --- /dev/null +++ b/demos/blog/protected/Pages/Posts/MyPost.php @@ -0,0 +1,34 @@ +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->dataBind(); + } + + public function onLoad($param) + { + parent::onLoad($param); + if(!$this->IsPostBack) + $this->bindData(); + } + + public function changePage($sender,$param) + { + $this->PostGrid->CurrentPageIndex=$param->NewPageIndex; + $this->bindData(); + } + + public function pagerCreated($sender,$param) + { + $param->Pager->Controls->insertAt(0,'Page: '); + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/NewCategory.page b/demos/blog/protected/Pages/Posts/NewCategory.page new file mode 100644 index 00000000..92fe1468 --- /dev/null +++ b/demos/blog/protected/Pages/Posts/NewCategory.page @@ -0,0 +1,36 @@ + + +

New Post Category

+ +Category name + + +
+ +
+ +Description +
+ +
+ + + +
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/NewCategory.php b/demos/blog/protected/Pages/Posts/NewCategory.php new file mode 100644 index 00000000..d36f6af1 --- /dev/null +++ b/demos/blog/protected/Pages/Posts/NewCategory.php @@ -0,0 +1,24 @@ +IsValid) + { + $categoryRecord=new CategoryRecord; + $categoryRecord->Name=$this->CategoryName->Text; + $categoryRecord->Description=$this->CategoryDescription->Text; + $this->DataAccess->insertCategory($categoryRecord); + $this->gotoPage('Posts.ListPost',array('cat'=>$categoryRecord->ID)); + } + } + + public function checkCategoryName($sender,$param) + { + $name=$this->CategoryName->Text; + $param->IsValid=$this->DataAccess->queryCategoryByName($name)===null; + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/NewPost.page b/demos/blog/protected/Pages/Posts/NewPost.page new file mode 100644 index 00000000..a49188f6 --- /dev/null +++ b/demos/blog/protected/Pages/Posts/NewPost.page @@ -0,0 +1,41 @@ + + +

Write a New Post

+ +Title + +
+ +
+ +Content + +
+ +
+ +Categories
+ +
+ + +
+ + + +
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/NewPost.php b/demos/blog/protected/Pages/Posts/NewPost.php new file mode 100644 index 00000000..055c7f92 --- /dev/null +++ b/demos/blog/protected/Pages/Posts/NewPost.php @@ -0,0 +1,34 @@ +IsPostBack) + { + $this->Categories->DataSource=$this->DataAccess->queryCategories(); + $this->Categories->dataBind(); + } + } + + public function saveButtonClicked($sender,$param) + { + if($this->IsValid) + { + $postRecord=new PostRecord; + $postRecord->Title=$this->Title->Text; + $postRecord->Content=$this->Content->Text; + $postRecord->Status=$this->DraftMode->Checked?0:1; + $postRecord->CreateTime=time(); + $postRecord->AuthorID=$this->User->ID; + $cats=array(); + foreach($this->Categories->SelectedValues as $value) + $cats[]=TPropertyValue::ensureInteger($value); + $this->DataAccess->insertPost($postRecord,$cats); + $this->gotoPage('Posts.ViewPost',array('id'=>$postRecord->ID)); + } + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/ViewPost.page b/demos/blog/protected/Pages/Posts/ViewPost.page new file mode 100644 index 00000000..4b233615 --- /dev/null +++ b/demos/blog/protected/Pages/Posts/ViewPost.page @@ -0,0 +1,113 @@ + + +
+
+<%= $this->CurrentPost->Title %> +
+
+<%= date('l, F j, Y \a\t h:i:s a',$this->CurrentPost->CreateTime) %> +by +<%= '' . $this->CurrentPost->AuthorName . '' %> +<%= $this->CanEditPost ? '| Edit | ' : ''; +%> +CanEditPost %> + Attributes.onclick="if(!confirm('Are you sure to delete this post? This will also delete all related comments.')) return false;" + /> +
+
+<%= $this->CurrentPost->Content %> +
+ +
+ +
+ +

Comments

+ + + +
+
+DataItem->ID %> + Visible=<%= $this->Page->CanEditPost %> Style="float:right"/> +<%# date('F j, Y \a\t h:i:s a',$this->DataItem->CreateTime) %> +by +<%# $this->DataItem->AuthorWebsite==='' ? + $this->DataItem->AuthorName : + '' . $this->DataItem->AuthorName . '' %> +
+
+<%# $this->DataItem->Content %> +
+
+
+
+ +

Leave your comment

+ +Name + +
+ +
+ +Email address + + +
+ +
+ +Personal website +
+ +
+ +Comment + +
+ +
+ + + +
+
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/ViewPost.php b/demos/blog/protected/Pages/Posts/ViewPost.php new file mode 100644 index 00000000..309bedc1 --- /dev/null +++ b/demos/blog/protected/Pages/Posts/ViewPost.php @@ -0,0 +1,73 @@ +_postID===null) + $this->_postID=TPropertyValue::ensureInteger($this->Request['id']); + return $this->_postID; + } + + public function getCurrentPost() + { + if($this->_post===null) + { + if(($this->_post=$this->DataAccess->queryPostByID($this->getPostID()))===null) + $this->reportError(BlogErrors::ERROR_POST_NOT_FOUND); + } + return $this->_post; + } + + public function getCanEditPost() + { + $user=$this->getUser(); + $authorID=$this->getCurrentPost()->AuthorID; + return $authorID===$user->getID() || $user->isInRole('admin'); + } + + public function onLoad($param) + { + parent::onLoad($param); + $this->CategoryList->DataSource=$this->DataAccess->queryCategoriesByPostID($this->getPostID()); + $this->CategoryList->dataBind(); + $this->CommentList->DataSource=$this->DataAccess->queryCommentsByPostID($this->getPostID()); + $this->CommentList->dataBind(); + } + + public function submitCommentButtonClicked($sender,$param) + { + if($this->IsValid) + { + $commentRecord=new CommentRecord; + $commentRecord->PostID=$this->CurrentPost->ID; + $commentRecord->AuthorName=$this->CommentAuthor->Text; + $commentRecord->AuthorEmail=$this->CommentEmail->Text; + $commentRecord->AuthorWebsite=$this->CommentWebsite->Text; + $commentRecord->AuthorIP=$this->Request->UserHostAddress; + $commentRecord->Content=$this->CommentContent->Text; + $commentRecord->CreateTime=time(); + $commentRecord->Status=0; + $this->DataAccess->insertComment($commentRecord); + $this->Response->reload(); + } + } + + public function deleteButtonClicked($sender,$param) + { + $this->DataAccess->deletePost($this->PostID); + $this->gotoDefaultPage(); + } + + public function repeaterItemCommand($sender,$param) + { + $id=TPropertyValue::ensureInteger($param->CommandParameter); + $this->DataAccess->deleteComment($id); + $this->Response->reload(); + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Pages/Posts/config.xml b/demos/blog/protected/Pages/Posts/config.xml new file mode 100644 index 00000000..1c04e946 --- /dev/null +++ b/demos/blog/protected/Pages/Posts/config.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/demos/blog/protected/Pages/Users/EditUser.page b/demos/blog/protected/Pages/Users/EditUser.page new file mode 100644 index 00000000..8c21fd50 --- /dev/null +++ b/demos/blog/protected/Pages/Users/EditUser.page @@ -0,0 +1,74 @@ + + +

Update Profile

+ + + +Username +
+ + +
+ +Full name +
+ + +
+ +Password +
+ + + +
+ +Re-type Password +
+ + + +
+ +Email Address +
+ + + + +
+ +Personal Website +
+ + +
+ + + +
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Users/EditUser.php b/demos/blog/protected/Pages/Users/EditUser.php new file mode 100644 index 00000000..e3efcfd1 --- /dev/null +++ b/demos/blog/protected/Pages/Users/EditUser.php @@ -0,0 +1,43 @@ +DataAccess->queryUserByID($this->User->ID))!==null) + return $user; + else + throw new BlogException('xxx'); + } + + public function onLoad($param) + { + parent::onLoad($param); + if(!$this->IsPostBack) + { + $userRecord=$this->getCurrentUser(); + $this->Username->Text=$userRecord->Name; + $this->FullName->Text=$userRecord->FullName; + $this->Email->Text=$userRecord->Email; + $this->Website->Text=$userRecord->Website; + } + } + + public function saveButtonClicked($sender,$param) + { + if($this->IsValid) + { + $userRecord=$this->getCurrentUser(); + if($this->Password->Text!=='') + $userRecord->Password=md5($this->Password->Text); + $userRecord->FullName=$this->FullName->Text; + $userRecord->Email=$this->Email->Text; + $userRecord->Website=$this->Website->Text; + $this->DataAccess->updateUser($userRecord); + $authManager=$this->Application->getModule('auth'); + $this->gotoPage('Users.ViewUser',array('id'=>$userRecord->ID)); + } + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Pages/Users/NewUser.page b/demos/blog/protected/Pages/Users/NewUser.page new file mode 100644 index 00000000..eba2dcec --- /dev/null +++ b/demos/blog/protected/Pages/Users/NewUser.page @@ -0,0 +1,104 @@ + + +

Create New Account

+ + + +Username +
+ + + + + +
+ +Full name +
+ + +
+ +Password +
+ + + + +
+ +Re-type Password +
+ + + +
+ +Email Address +
+ + + + +
+ +Personal Website +
+ + +
+ + + +
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Users/NewUser.php b/demos/blog/protected/Pages/Users/NewUser.php new file mode 100644 index 00000000..166abf66 --- /dev/null +++ b/demos/blog/protected/Pages/Users/NewUser.php @@ -0,0 +1,31 @@ +Username->Text; + $param->IsValid=$this->DataAccess->queryUserByName($username)===null; + } + + public function createUser($sender,$param) + { + if($this->IsValid) + { + $userRecord=new UserRecord; + $userRecord->Name=$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; + $this->DataAccess->insertUser($userRecord); + $authManager=$this->Application->getModule('auth'); + $authManager->login($this->Username->Text,$this->Password->Text); + $this->gotoDefaultPage(); + } + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Pages/Users/ViewUser.page b/demos/blog/protected/Pages/Users/ViewUser.page new file mode 100644 index 00000000..2dba6b77 --- /dev/null +++ b/demos/blog/protected/Pages/Users/ViewUser.page @@ -0,0 +1,21 @@ + + +

User Profile

+ +Username: <%= $this->CurrentUser->Name %> +
+ +Full name: <%= $this->CurrentUser->FullName %> +
+ +Email: <%= $this->CurrentUser->Email %> +
+ +Privilege: <%= $this->CurrentUser->Role===0? 'User':'Administrator' %> +
+ +Personal website: <%= $this->CurrentUser->Website %> +
+ + +
\ No newline at end of file diff --git a/demos/blog/protected/Pages/Users/ViewUser.php b/demos/blog/protected/Pages/Users/ViewUser.php new file mode 100644 index 00000000..3485f56b --- /dev/null +++ b/demos/blog/protected/Pages/Users/ViewUser.php @@ -0,0 +1,19 @@ +_currentUser===null) + { + $id=TPropertyValue::ensureInteger($this->Request['id']); + if(($this->_currentUser=$this->DataAccess->queryUserByID($id))===null) + throw new BlogException('xxx'); + } + return $this->_currentUser; + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Pages/Users/config.xml b/demos/blog/protected/Pages/Users/config.xml new file mode 100644 index 00000000..df8e4ad1 --- /dev/null +++ b/demos/blog/protected/Pages/Users/config.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/demos/blog/protected/Portlets/AccountPortlet.php b/demos/blog/protected/Portlets/AccountPortlet.php new file mode 100644 index 00000000..0f0e60c6 --- /dev/null +++ b/demos/blog/protected/Portlets/AccountPortlet.php @@ -0,0 +1,14 @@ +Application->getModule('auth')->logout(); + $this->Response->reload(); + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Portlets/AccountPortlet.tpl b/demos/blog/protected/Portlets/AccountPortlet.tpl new file mode 100644 index 00000000..2a401f41 --- /dev/null +++ b/demos/blog/protected/Portlets/AccountPortlet.tpl @@ -0,0 +1,20 @@ +
+ +

Account

+ +
+Welcome, <%= $this->User->Name %>! + + +
+ +
diff --git a/demos/blog/protected/Portlets/ArchivePortlet.php b/demos/blog/protected/Portlets/ArchivePortlet.php new file mode 100644 index 00000000..a004c7a9 --- /dev/null +++ b/demos/blog/protected/Portlets/ArchivePortlet.php @@ -0,0 +1,45 @@ +Application->getModule('data')->queryEarliestPostTime(); + if(empty($startTime)) // if no posts + $startTime=$currentTime; + + // obtain the timestamp for the initial month + $date=getdate($startTime); + $startTime=mktime(0,0,0,$date['mon'],1,$date['year']); + + $date=getdate($currentTime); + $month=$date['mon']; + $year=$date['year']; + + $timestamps=array(); + while(true) + { + if(($timestamp=mktime(0,0,0,$month,1,$year))<$startTime) + break; + $timestamps[]=$timestamp; + if(--$month===0) + { + $month=12; + $year--; + } + } + $this->MonthList->DataSource=$timestamps; + $this->MonthList->dataBind(); + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Portlets/ArchivePortlet.tpl b/demos/blog/protected/Portlets/ArchivePortlet.tpl new file mode 100644 index 00000000..c576e9f5 --- /dev/null +++ b/demos/blog/protected/Portlets/ArchivePortlet.tpl @@ -0,0 +1,15 @@ +
+ +

Archives

+ + + +
diff --git a/demos/blog/protected/Portlets/CategoryPortlet.php b/demos/blog/protected/Portlets/CategoryPortlet.php new file mode 100644 index 00000000..9c2033aa --- /dev/null +++ b/demos/blog/protected/Portlets/CategoryPortlet.php @@ -0,0 +1,15 @@ +CategoryList->DataSource=$this->Application->getModule('data')->queryCategories(); + $this->CategoryList->dataBind(); + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Portlets/CategoryPortlet.tpl b/demos/blog/protected/Portlets/CategoryPortlet.tpl new file mode 100644 index 00000000..acbd3bec --- /dev/null +++ b/demos/blog/protected/Portlets/CategoryPortlet.tpl @@ -0,0 +1,24 @@ +
+ +

+Categories +Service->constructUrl('Posts.NewCategory') %> + Visible=<%= $this->User->isInRole('admin') %> /> +

+ + + +
diff --git a/demos/blog/protected/Portlets/LoginPortlet.php b/demos/blog/protected/Portlets/LoginPortlet.php new file mode 100644 index 00000000..0085c17f --- /dev/null +++ b/demos/blog/protected/Portlets/LoginPortlet.php @@ -0,0 +1,22 @@ +Application->getModule('auth'); + if(!$authManager->login($this->Username->Text,$this->Password->Text)) + $param->IsValid=false; + } + + public function loginButtonClicked($sender,$param) + { + if($this->Page->IsValid) + $this->Response->reload(); + //$this->Response->redirect($this->Application->getModule('auth')->getReturnUrl()); + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Portlets/LoginPortlet.tpl b/demos/blog/protected/Portlets/LoginPortlet.tpl new file mode 100644 index 00000000..6f8c5d4a --- /dev/null +++ b/demos/blog/protected/Portlets/LoginPortlet.tpl @@ -0,0 +1,36 @@ +
+ +

Login

+ + +Username + +
+ +
+ +Password + +
+ + +
+ +| Register + +
+ +
diff --git a/demos/blog/protected/Portlets/Portlet.php b/demos/blog/protected/Portlets/Portlet.php new file mode 100644 index 00000000..4b1c80e9 --- /dev/null +++ b/demos/blog/protected/Portlets/Portlet.php @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/demos/blog/protected/Portlets/SearchPortlet.php b/demos/blog/protected/Portlets/SearchPortlet.php new file mode 100644 index 00000000..1bad7f1c --- /dev/null +++ b/demos/blog/protected/Portlets/SearchPortlet.php @@ -0,0 +1,22 @@ +Page->IsPostBack && ($keyword=$this->Request['keyword'])!==null) + $this->Keyword->Text=$keyword; + } + + public function search($sender,$param) + { + $keyword=$this->Keyword->Text; + $url=$this->Service->constructUrl('SearchPost',array('keyword'=>$keyword)); + $this->Response->redirect($url); + } +} + +?> \ No newline at end of file diff --git a/demos/blog/protected/Portlets/SearchPortlet.tpl b/demos/blog/protected/Portlets/SearchPortlet.tpl new file mode 100644 index 00000000..f88fca7e --- /dev/null +++ b/demos/blog/protected/Portlets/SearchPortlet.tpl @@ -0,0 +1,21 @@ +
+ +

Search

+ + +Keyword + +
+ + +
+ +
diff --git a/demos/blog/protected/application.xml b/demos/blog/protected/application.xml new file mode 100644 index 00000000..9bca115c --- /dev/null +++ b/demos/blog/protected/application.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demos/blog/sitemap.txt b/demos/blog/sitemap.txt new file mode 100644 index 00000000..8326855b --- /dev/null +++ b/demos/blog/sitemap.txt @@ -0,0 +1,106 @@ +Be careful about username case sensitivity!! + +Home : list of blogs filtered by a category or time range, with paging + +ViewBlog : read a single blog with all comments and a comment input form +NewBlog : create a new blog, with file attachment form and THtmlArea +EditBlog : edit an existing blog + +LoginUser : login page +NewUser : create a new user +EditUser : edit the current user + +Admin : whether allow multiple users, whether HTML is allowed (first user is always the admin) + +URL design: + +index.php?page=ListBlog×pan=123,456&limit=123,456 : list of latest blogs, equivalent to: +index.php?page=NewBlog +index.php?page=EditBlog&id=123 +index.php?page=ViewBlog&id=123 +index.php?page=NewUser +index.php?page=EditUser +index.php?page=ViewUser +index.php?page=Admin + + +Use Case 1: Add a post +1. Authorization check +2. display UI for adding post +3. input validation +4. add post to DB +5. display UI for post list + + +DB Logic needed: + +class Post extends DataObject +{ + public $xxx; +} + +class Comment extends DataObject +{ +} + +class UserProfile extends DataObject +{ + +} + +class DataObject extends TComponent +{ + protected static $mapping=array(); + + public function __construct($db) + { + } + + protected static function generateModifier($filter,$orderBy,$limit) + { + $modifier=''; + if($filter!=='') + $modifier=' WHERE '.$filter; + if($orderBy!=='') + $modifier.=' ORDER BY '.$orderBy; + if($limit!=='') + $modifier.=' LIMIT '.$limit; + return $modifier; + } + + public static function queryRow($filter='') + { + $modifier=self::generateModifier($filter,'',''); + } + + public static function query($filter='',$orderBy='',$limit='') + { + $modifier=self::generateModifier($filter,$orderBy,$limit); + } + + public function save() + { + } + + public function delete() + { + } +} + +public function queryUsers($filter='',$sortBy='',$limit='') +public function queryUser($id) +public function insertUser($user) +public function updateUser($user) +public function deleteUser($id) + +public function queryPosts($filter='',$sortBy='',$limit='') +public function queryPost($id) +public function insertPost($post) +public function updatePost($post) +public function deletePost($id) + +public function queryComments($filter='',$sortBy='',$limit='') +public function queryComment($id) +public function insertComment($comment) +public function updateComment($comment) +public function deleteComment($id) diff --git a/demos/blog/themes/Basic/style.css b/demos/blog/themes/Basic/style.css new file mode 100644 index 00000000..b8e9ca89 --- /dev/null +++ b/demos/blog/themes/Basic/style.css @@ -0,0 +1,261 @@ +html { + margin: 0; + padding: 0; +} + +body { + margin: 0; + padding: 0; + font-family: verdana, 'trebuchet ms', sans-serif; + font-size: 12px; + color: #333; + background: #36414d; + min-width:750px; +} + +form { + margin: 0; + padding: 0; +} + +a { + text-decoration: underline; +} + +a img { + border: 0px none; +} + +#page { + background:#fff; + margin:0 auto; + width:800px; +} + +#header { + background: #a3b8cc; + 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; + font-size: 12pt; +} + +#main { + background:#fff; + float:left; + width:560px; + padding: 20px; +} + +#main h2 { + border-bottom: 1px solid silver; +} + +#sidebar { + background:#e6ecf2; + float:right; + width:200px; +} + +#sidebar ul { + margin-bottom:0; +} + +#sidebar h3, #sidebar p { + padding:0 10px 0 0; +} + +#footer { + background:#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: #dae0e6; +} + +.portlet-title { + /* ie win (5, 5.5, 6) bugfix */ + p\osition: relative; + width: 100%; + w\idth: auto; + + margin: 0; + border-left: 5px solid #36414d; + border-bottom: 1px solid silver; + padding: 5px; + color: #fff; + background: #a3b8cc; + font-size: 8pt; + font-weight: bold; + line-height: 1; + text-transform: uppercase; +} + +.portlet-title a { + color: yellow; + text-decoration: none; + text-transform: none; +} + +.portlet-title a:hover { + color: red; +} + +.portlet-content { + margin: 0 0 10px 0; + border-top: 1px solid #cfd4d9; + 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 { + color: #36414d; + 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: #36414d; +} + +.comments { + border-top: 1px silver solid; +} + +.comments h3 { + font-size: 12pt; +} + +.comment { + margin-bottom: 10px; +} + +.comment-header { + background-color: #e6ecf2; + padding: 3px; + font-size: 8pt; +} + +.grid { + width: 100%; +} + +.grid td { + padding: 3px; +} + +.grid-header { + color: #fff; + background: #a3b8cc; +} + +.grid-row1 { + background: #dae0e6; +} + +.grid-row2 { + background: #e6ecf2; +} + +.grid-row-selected { + background: lightyellow; +} + +.grid-pager { + text-align: right; + color: silver; +} + +.grid-pager a { + color: green; + text-decoration: none; +} + +.submenu { + margin-bottom: 10px; + border-bottom: 5px solid #a3b8cc; + 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; + background: #a3b8cc; + padding: 3px 5px 0 5px; +} + +.submenu-inactive { + text-decoration: none; + background: #dae0e6; + padding: 3px 5px 0 5px; +} \ No newline at end of file -- cgit v1.2.3