đến các bài báo), Categories (Chứa các thông tin liên quan đến đầu mục các bài báo), Comments (Chứa các thông tin liên quan đến bình luận của các bài báo) Mổi quan hệ giữa bảng Articles với bảng Comments được thiết lập thông qua
khóa ngoại là ArticleID với updates và deletes là kiểu Cascade do đó khi xóa một
Artile thì các Comments tương ứng với Article đó cũng bị xóa.
Tương tự quan hệ giữa 2 bảng Categories và Articles được thiết lập thông qua
khóa ngoại là CategoryID với updates và deletes là kiểu do đó khi xóa một
Category thì các bài báo thuộc Category đó cũng bị xóa.
Hình 3.25 – Sơ đồ bảng Categories, Comments, Articles và quan hệ của chúng
7.4. Xây dựng lớp ArticleElement cho thiết lập cấu hình của module module
Các thuộc tính cấu hình trong thành phần <article> nằm trong phần <globalStore> thuộc tệp web.config sẽ được đọc bởi lớp ArticleElement . Lớp này kế thừa từ
Phần cấu hình của module bài báo, tin tức, blog trong tệp web.config
<globalStore>
<articles pageSize="10"/> </globalStore>
7.5. Model
Từ các bảng DL của module trong CSDL của hệ thống ta tạo được các lớp thực
thể tương ứng thông quan LINQ-to-SQL như sau:
Hình 3.26 – Sơ đồ các lớp thực thể Article, Comment, Category
Để hỗ trợ cho việc truy vấn các bảng dữ liệu của module . Vì các lớp thực thể Article, Comment, Category đều là các lớp partial do đó có thể thêm các thuộc tính và phương thức vào các lớp này ở một tệp khác tệp chứa định nghĩa của các lớp đó . Như vậy có thể dễ dàng mở rộng các lớp thực thể LINQ-to-SQL được tạo tự động từ các bảng DL trong CSDL của hệ thống.
Thuộc tính Mô tả
Như sơ đồ dưới ta có mở rộng cho lớp Article thực thể bằng việc thêm ba thuộc tính AverageRating, Location, Published và 2 phương thức là
IncrementViewCount, Rate.Thêm vào đó là một đối tượng
ArticleCollectionWrapper
Hình 3.27 – Sơ đồ các lớp mở rộng ArticlesQueries, Article, ArticleCollectionWrapper 7.6. Controller Phương thức hành động Bảo mật Các tham số
Index ---- string category, int page CategoryIndex ---- ----
ViewArticle ---- int id, string path RateArticle ---- int articleId, int rating ManageArticle Editor int page
ManageCategory Editor ---- ManageComment Editor ----
bool? approved, bool? listed,
bool? commentsEnabled, bool? onlyForMembers EditArticle Editor int articleId, int? categoryId, string title, string
summary, string body, string country, string state, string city,
DateTime? release-Date, DateTime? expireDate, bool? approved, bool? listed,
bool? commentsEnabled, bool? onlyForMembers RemoveArticle Editor int articleId, string remove
CreateCategory Editor string title, int? importance, string imageUrl, string description
EditCategory Editor int categoryId, string title, int? importance, string imageUrl, string description
RemoveCategory Editor int categoryId, int? newCategoryId,string remove CreateComment ---- int articleId, string name, string email,string body EditComment Editor int commentId, string name, string body
RemoveComment Editor int commented
7.7. View
Tên trang Đặc tả Đường dẫn ảo
Index.aspx Trang này hiển thị tất cả các bài báo hiện có trong hệ thống article articles/page{page}} articles/categories/{category} articles/categories/{category}/page{page}
CategoryIndex.aspx Trang này hiển thị những đầu mục
các bài báo articles/categories
ViewArticle.aspx Trang này cho phép xem chi tiết bài báo, viết lời bình luận về bài báo, cho điểm bài báo
articles/{id}/{*path}
ManageArticle.aspx Trang này liệt kê các bài báo hiện có trong hệ thống với hỗ trợ phân trang, và cho phép chỉnh sửa , xóa bài báo
editor/articles
editor/articles/page{page}
ManageCategory.aspx Trang này liệt kê các đầu mục báo hiện có trong hệ thống, và cho phép chỉnh sửa , xóa các đầu mục đó editor/articles/categories
ManageComments.aspx Trang này hiển thị tất cả các lời bình theo thứ tự từ trên xuống từ tính
theo thời gian và cho phép người dùng với vai trò editor xóa các lời
bình đó editor/articles/comments
editor/articles/comments/page{page}
CreateArticle.aspx Trang này cho phép bạn tạo mới hay chỉnh sửa một bài báo có trong hệ thống editor/articles/create editor/articles/edit/{articleId}
CreateCategory.aspx Trang này cho phép bạn tạo mới hay chỉnh sửa một đầu mục báo có trong hệ thống editor/articles/categories/create editor/articles/categories/edit/{categoryId}
RemoveArticle.aspx Trang này được dùng để xác nhận lại việc có hay không xóa một
bài báo editor/articles/remove/{articleId}
RemoveCategory.aspx Trang này được dùng để xác nhận lại việc có hay không xóa một đầu mục báo
editor/articles/categories/remove/{categoryId}
7.8. Sử dụng javascript
Tệp manage-category.js được sử dụng để thực thi các hành động phía người dùng trên trang CreateCategory.aspx
Phần đầu của tệp này dùng cho thông điệp thông tin cho các mục trong form
Create Category
$("#title").focus(function ()
{ ShowMessage(this, "Enter the title for your category."); }); $("#importance").focus(function ()
{ ShowMessage(this, "(optional) Enter the order of importance that you want the categories shown in."); });
$("#imageUrl").focus(function ()
{ ShowMessage(this, "The relative web path of an image you want to be shown with articles in this category."); });
$("#description").focus(function ()
{ ShowMessage(this, "Enter a short description of the category to display to your users."); });
function ValidateTitle () {
return VerifyRequiredField("#title", "required"); }
function ValidateImageUrl () {
return VerifyRequiredField("#imageUrl", "required"); }
function ValidateDescription () {
return VerifyRequiredField("#description", "required"); }
3 hàm này thực thi việc đảm bảo các trường title, imageUrl, và description có chứa
giá trị bởi lẽ chúng buộc phải có để có thể lưu một bản category vào CSDL. function ValidateCategory () {
var validTitle = ValidateTitle();
var validImage = ValidateImageUrl();
var validDescription = ValidateDescription();
return validTitle && validImage && validDescription; }
$("form.category-create").validate(ValidateCategory);
Hàm cuối cùng này của tệp manage-categories.js thực hiện việc đảm bảo cả ba trường đều phải chứa giá trị . Trong trường hơp cả ba trường đều có chứa giá trị
nó sẽ trả về giá trị true và như vậy hệ thống sẽ tiếp tục submit Form tạo Category.
Trong các trường hợp còn lại hệ thống sẽ không thể tiếp tục thực hiện việc submit
Form nói trên.
Tiếp đến là tệp manage-articles.js:
Phần đầu của tệp này cũng thực hiện việc tương tự với tệp trên tuy nhiên là cho trang CreateArticles
$("#title").focus(function ()
{ ShowMessage(this, "Enter the title for your article."); });
$("#summary").focus(function ()
{ ShowMessage(this, "(optional) Enter a summary for your
article to be displayed instead of body."); });
$("#body").focus(function ()
{ ShowMessage(this, "Enter the body of your article."); });
$("#country").focus(function ()
{ ShowMessage(this, "(optional) Enter the country that is
associated with this article."); });
$("#state").focus(function ()
{ ShowMessage(this, "(optional) Enter the state that is
associated with this article."); });
{ ShowMessage(this, "(optional) Enter the city that is
associated with this article."); });
$("#releaseDate").focus(function ()
{ ShowMessage(this, "(optional) This is the date that you want this article to be first show on the site. If left
blank todays day is used."); });
$("#expireDate").focus(function ()
{ ShowMessage(this, "(optional) This is the date that you
want this article to stop showing on the site."); });
function ValidateTitle () {
return VerifyRequiredField("#title", "required");
}
function ValidateBody () {
return VerifyRequiredField("#body", "required");
} function ValidateArticle () { return ValidateTitle() && ValidateBody(); } $("form.article-create").validate(ValidateArticle);
Phần tiếp theo của tệp này được dùng để tạo và gắn một thể hiện của TinyMCE
với TextArea có tên là body:
var bodyEditor;
$(document).ready(function () {
bodyEditor = new tinymce.Editor("body", __editorConfig); bodyEditor.onChange.add(function (ed) { bodyEditor.save(); });
bodyEditor.onClick.add(function (ed) { ShowMessage("#body",
"Enter the body of your article."); });
bodyEditor.render(); });
Phần code cuối cùng của tệp này dùng để dấu thông điệp của phần body mỗi khi một vùng textbox trên trang CreateArticle được sử dụng:
$(":input")
.focus(function () { HideMessage("#body"); }) .blur(function () { HideMessage("#body"); }); Tệp manage-comment.js
var id = $(this).attr("meta:id"); $.post( "/article/removecomment", { commentId: id }, function (data) { $("#comment-" +
data.object.commentId).next(".admin").fadeOut("slow", function () { $(this).remove() }); $("#comment-" + data.object.commentId).fadeOut("slow", function () { $(this).remove() }); }, "json" ); return false; }); Phần mã lệnh chỉnh sửa comment: $(".edit-comment").click(function () { var id = $(this).attr("meta:id"),
comment = $("#comment-" + id),
bodyText = comment.find(".body").text(), nameText = comment.find(".name").text();
// hide all the childrend
comment.children().hide(); var commentText = "";
commentText += "<form><div class=\"comment-header field\"><label for=\"name-" + id + "\">Commentor's Name</label><br/><input type=\"text\" id=\"name-" + id + "\" class=\"edit-name\" value=\"" + nameText + "\" /></div>";
commentText += "<div class=\"field\"><label for=\"body-" + id +
"\">Comment Body</label><br/><textarea class=\"edit-body\" id=\"body-" + id + "\">" + bodyText + "</textarea><br/><button type=\"button\" class=\"update\" meta:id=\"" + id + "\">Update</button> <button type=\"button\"
class=\"cancel\">Cancel</button></div></form>"; var commentForm = $(commentText);
// update the form
commentForm.find(".update").click(function () { var id = $(this).attr("meta:id");
var nameFormText = $(this).prevAll(".edit-name").val(); var bodyFormText = $(this).prevAll(".edit-body").val(); $.post(
"/article/editcomment",
{ commentId: id, name: nameFormText, body: bodyFormText },
function (data) {
var comment = $("#comment-" + data.object.commentId); comment.children("form").remove(); comment.children(".body").text(data.object.body); comment.children(".name").text(data.object.name); comment.children().show(); }, "json" ); });
// cancel the update
commentForm.find(".cancel").click(function () {
$(this).parents(".comment").children(":hidden").show(); $(this).parents("form").remove();
});
// add the form to the current comment
comment.append(commentForm); return false;
});
Tệp article.js
Phần code cho điểm một bài báo (rating article) . Để cho điểm một bài báo thì việc đầu tiên là phải gắn kết mã lệnh javascript xử lí việc cho điểm với sự kiện submit trên form cho điểm bài báo để mỗi khi người dùng nhấn nút cho điểm thì một yêu cầu AJAX sẽ được gửi tới phương thức hành động /article/ratearticle:
$("form.rate-article").submit(function () {
$.post(
"/article/ratearticle",
{ articleId: $("#articleId").val(), rating: $("#rating").val() }, RateArticleSuccess,
"json"
);
// don't allow submit because this is an ajax request
return false;
});
Bởi lẽ cái yêu cầu cho điểm này là bất đồng bộ nên ta sẽ cung cấp một phương
var value = data.object.averageRating; var imagePosition = "50"; if (value <= 1.3) imagePosition = "10"; else if (value <= 1.8) imagePosition = "15"; else if (value <= 2.3) imagePosition = "20"; else if (value <= 2.8) imagePosition = "25"; else if (value <= 3.3) imagePosition = "30"; else if (value <= 3.8) imagePosition = "35"; else if (value <= 4.3) imagePosition = "40"; else if (value <= 4.8) imagePosition = "45"; $("#article-rating-value")
.replaceWith("<img src=\"/Content/images/stars" + imagePosition + ".gif\" alt=\"" + value + "\" />");
$("form.rate-article :input").attr("disabled", "true");
$("form.rate-article").append("Your rating has been applied!"); }
Phần code cho xử lí thêm comment cũng như phần cho điểm bài báo phải thực
hiện 2 việc : Một là tạo một yêu cầu bất đồng bộ, hai là thực hiện đáp trả yêu cầu
function ValidateCommentName () {
return VerifyRequiredField("#comment-name", "required"); }
function ValidateCommentEmail () {
return VerifyRequiredField("#comment-email", "required"); }
function ValidateCommentBody () {
return VerifyRequiredField("#comment-body", "required"); }
function CreateCommentSuccess (data, textStatus) {
$(".new-comment").removeClass("new-comment").show("normal"); var commentText = "";
commentText += "<div id=\"comment-" + data.object.commentId + "\" class=\"comment new-comment\">";
commentText += "<div class=\"comment-header\">Comment posted by " + data.object.name + " 0 sec ago</div>";
commentText += "<blockquote>" + data.object.body + "</blockquote>"; commentText += "</div>";
var comment = $(commentText);
// clear the body box
$("#comment-body").val("");
// add the new comment to the other comments
comment .hide() .appendTo("#article-comments") .slideDown("slow"); } $("form.comment-create").submit(function () { var valid = ValidateCommentName()
&& ValidateCommentEmail() && ValidateCommentBody(); if (valid) { $.post( "/article/createcomment", { articleId: $("#articleId").val(), name: $("#comment-name").val(), email: $("#comment-email").val(), body: $("#comment-body").val() }, CreateCommentSuccess, "json" ); }
// don't allow submit because this is an ajax request
return false; });
7.9. Cấu hình định tuyến
Phần cấu hình định tuyến các trang dành cho mọi người dùng: routes.MapRoute(
"ArticleView",
"articles/{id}/{*path}",
new { controller = "Article", action = "ViewArticle", id = (string)null, path = (string)null },
new { id = "[0-9]+", path = "[a-zA-Z0-9\\-]*" } );
new { controller = "Article", action = "Index", category = (string)null, page = 1 },
new { category = "[a-zA-Z0-9\\-]+", page = "[0-9]+" } );
routes.MapRoute(
"ArticleCategoryViewIndexPaged",
"articles/categories/{category}/page{page}",
new { controller = "Article", action = "Index", category = (string)null, page = (int?)null },
new { category = "[a-zA-Z0-9\\-]+", page = "[0-9]+" } );
routes.MapRoute(
"ArticleCategoryIndex", "articles/categories",
new { controller = "Article", action = "CategoryIndex" } );
routes.MapRoute( "ArticleIndex", "Articles",
new { controller = "Article", action = "Index", category = (string)null, page = 1 }
);
routes.MapRoute(
"ArticleIndexPaged", "articles/page{page}",
new { controller = "Article", action = "Index", category = (string)null, page = (int?)null },
new { page = "[0-9]+" } );
Phần cấu hình định tuyến dành riêng cho người dùng có vai trò editor routes.MapRoute(
"ArticleCreate",
"editor/articles/create",
new { controller = "Article", action = "CreateArticle" } );
routes.MapRoute( "ArticleEdit",
"editor/articles/edit/{articleId}",
new { controller = "Article", action = "EditArticle", articleId = (int?)null }, new { articleId = "[0-9]+" }
);
routes.MapRoute(
"editor/articles/remove/{articleId}",
new { controller = "Article", action = "RemoveArticle", articleId = (int?)null }, new { articleId = "[0-9]+" } ); routes.MapRoute( "ArticleManage", "editor/articles",
new { controller = "Article", action = "ManageArticles", page = 1 } );
routes.MapRoute(
"ArticleManagePaged", "editor/articles/page{page}",
new { controller = "Article", action = "ManageArticles", page = (int?)null }, new { page = "[0-9]+" }
);
routes.MapRoute(
"ArticleCategoryCreate",
"editor/articles/categories/create",
new { controller = "Article", action = "CreateCategory" } );
routes.MapRoute(
"ArticleCategoryEdit",
"editor/articles/categories/edit/{categoryId}",
new { controller = "Article", action = "EditCategory", categoryId = (int?)null }, new { categoryId = "[0-9]+" } ); routes.MapRoute( "ArticleCategoryRemove", "editor/articles/categories/remove/{categoryId}",
new { controller = "Article", action = "RemoveCategory", categoryId = (int?)null }, new { categoryId = "[0-9]+" } ); routes.MapRoute( "ArticleCategoryManage", "editor/articles/categories",
new { controller = "Article", action = "ManageCategories" } );
);
routes.MapRoute(
"ArticleCommentManagePaged", "editor/articles/comments/page{page}",
new { controller = "Article", action = "ManageComments", page = (int?)null }, new { page = "[0-9]+" } ); #endregion #endregion #region Polls routes.MapRoute( "PollsIndex", "polls",
new { controller = "Poll", action = "Index", page = 1 } );
routes.MapRoute(
"PollsIndexPaged", "polls/page{page}",
new { controller = "Poll", action = "Index", page = (int?)null }, new { page = "[0-9]+" }
8. MODULE QUỐC TẾ HÓA 8.1. Tổng quan về module
GlobalStore Pte. có chuỗi các siêu thị có mặt ở nhiều nước vì vậy hệ thống siêu thị
trực tuyến của GlobalStore Pte. cần đáp ứng được việc thể hiện hệ thống dưới
nhiều ngôn ngữ khác nhau và sử dụng đúng các số liệu như tiền, cách viết ngày tháng, con số theo địa phương của người sử dụng hệ thống.
Người sử dụng hệ thống sẽ chọn lựa chức năng này của hệ thống thông qua quá
trình đăng kí hồ sơ hoặc chỉnh sửa hồ sơ chọn ngôn ngữ hiển thị của site.
8.2. Xây dựng module