DbEntry 开发实践:Wiki 系统(五)
上回书说到,VisualWiki系统已经基本可以运行,我们现在来考虑给他加个路径功能。举例来说,我们从Home页,点击Hello链接,进入Hello页,这时,我们希望有Home和Hello两个链接在Wiki页顶端。再点击Hello页中的Next链接,进入Next页,这时,我们希望有Home、Hello、Next三个链接在Wiki页顶端。
需求就是这样,不过,如何实现呢?应该可以对Article设置对自己的一对多关系,那么在数据库中它们的父子关系就是确定的。不过,我却不太希望这样,对于Wiki来说,Wiki页都是独立的似乎更符合常规,那么这个路径怎么生成呢?
考虑之后,其实这个路径信息不必保存在数据库内,而只需要在url里面就足够了。具体就是增加一个path参数,用来解析路径信息,这里面有两个选择,一是path里是路径Wiki页的名称,另一个是path里是路径Wiki页的Id,我选择了后者,多个Id之间用下划线连接。
当然,这个改动也牵涉到GenerateShowText函数,所以先来修改它的单元测试吧,它应该增加一个path参数,当其为null时,处理方式和以前一样,否则将path加入生成的链接里:
恩,path也是一个常用常量了,所以也把它加入Const,修改后的GenerateShowText如下:
运行单元测试,全部通过,再编译Web项目,因为我们修改了GenerateShowText的参数,所以出现两个错误,现在我们在Show.aspx加入path参数,在Page_Load里把当前页面的Id加入path序列里,不过对于Home页的子页面而言,是不需要path信息的,修改后的Show.aspx的代码部分是:
现在运行程序,进入Home页,编辑它以增加一个链接,点击链接,进入新页,再编辑它增加一个链接,可以卡这个链接里已经包含了path信息。现在生成链接部分已经完成,就差在Wiki页顶端显示路径了。生成这个导航栏根据的基本信息就是title和path,所以应该增加一个help函数,写个单元测试先:
再添加path参数,然后在Page_Load里添加如下的代码:
再次运行程序,一路点击Wiki页内的链接,确认页顶的导航栏都显示正确。这时,进行编辑操作,会发现可能出现路径缺失现象,因为Edit.aspx页面还没有处理path参数,我们打开Edit.aspx页面,添加path参数,然后修改生成的用于Redirect的url为:
再次运行程序,仍然有路径缺失现象,发现是进入编辑页面的时候,路径就被丢弃了,所以我们修改SetLink函数,增加path参数:
再次运行程序,终于全部正常了。至此,Wiki编辑功能全部完成,只是界面还有点儿惨不忍睹,下一步我们就要进行一些界面调整,不过现在,提交代码先。目前的代码:VisualWiki5.7z
未完待续……
需求就是这样,不过,如何实现呢?应该可以对Article设置对自己的一对多关系,那么在数据库中它们的父子关系就是确定的。不过,我却不太希望这样,对于Wiki来说,Wiki页都是独立的似乎更符合常规,那么这个路径怎么生成呢?
考虑之后,其实这个路径信息不必保存在数据库内,而只需要在url里面就足够了。具体就是增加一个path参数,用来解析路径信息,这里面有两个选择,一是path里是路径Wiki页的名称,另一个是path里是路径Wiki页的Id,我选择了后者,多个Id之间用下划线连接。
当然,这个改动也牵涉到GenerateShowText函数,所以先来修改它的单元测试吧,它应该增加一个path参数,当其为null时,处理方式和以前一样,否则将path加入生成的链接里:
代码
[Test]
public void TestTestGenerateShowTestWithPath()
{
var text = "abc [[bb]] xyz";
var act = CommonHelper.GenerateShowText(text, "1_2");
Assert.AreEqual("abc <a href=\"Show.aspx?path=1_2&title=bb\">bb</a> xyz", act);
}
public void TestTestGenerateShowTestWithPath()
{
var text = "abc [[bb]] xyz";
var act = CommonHelper.GenerateShowText(text, "1_2");
Assert.AreEqual("abc <a href=\"Show.aspx?path=1_2&title=bb\">bb</a> xyz", act);
}
恩,path也是一个常用常量了,所以也把它加入Const,修改后的GenerateShowText如下:
代码
public static string GenerateShowText(string text, string path)
{
return ProcessSymbol(text, "[[", "]]",
title =>
{
var url = new UrlBuilder("Show.aspx");
if (!string.IsNullOrEmpty(path))
{
url.Add(Const.PathName, path);
}
url.Add(Const.TitleName, RemoveHtmlTag(title));
var link = HtmlBuilder.New.a(url.ToString()).include(title).end;
return link.ToString();
});
}
{
return ProcessSymbol(text, "[[", "]]",
title =>
{
var url = new UrlBuilder("Show.aspx");
if (!string.IsNullOrEmpty(path))
{
url.Add(Const.PathName, path);
}
url.Add(Const.TitleName, RemoveHtmlTag(title));
var link = HtmlBuilder.New.a(url.ToString()).include(title).end;
return link.ToString();
});
}
运行单元测试,全部通过,再编译Web项目,因为我们修改了GenerateShowText的参数,所以出现两个错误,现在我们在Show.aspx加入path参数,在Page_Load里把当前页面的Id加入path序列里,不过对于Home页的子页面而言,是不需要path信息的,修改后的Show.aspx的代码部分是:
代码
[HttpParameter(AllowEmpty = true)] public long? HistoryID;
[HttpParameter] public string title;
[HttpParameter(AllowEmpty = true)] public string path;
protected void Page_Load(object sender, EventArgs e)
{
if (HistoryID == null)
{
var article = Article.FindByTitle(title);
if (article != null && article.Title != Const.HomeName)
{
if (string.IsNullOrEmpty(path))
{
path = article.Id.ToString();
}
else
{
path += "_" + article.Id;
}
}
ContextHolder.Text
= article != null
? CommonHelper.GenerateShowText(article.Content, path)
: "The wiki page does not exist. The page will be created the first time you edit it. ";
}
else
{
var h = ArticleHistory.FindById(HistoryID.Value);
if(h != null)
{
ContextHolder.Text = CommonHelper.GenerateShowText(h.Content, null);
}
}
}
[HttpParameter] public string title;
[HttpParameter(AllowEmpty = true)] public string path;
protected void Page_Load(object sender, EventArgs e)
{
if (HistoryID == null)
{
var article = Article.FindByTitle(title);
if (article != null && article.Title != Const.HomeName)
{
if (string.IsNullOrEmpty(path))
{
path = article.Id.ToString();
}
else
{
path += "_" + article.Id;
}
}
ContextHolder.Text
= article != null
? CommonHelper.GenerateShowText(article.Content, path)
: "The wiki page does not exist. The page will be created the first time you edit it. ";
}
else
{
var h = ArticleHistory.FindById(HistoryID.Value);
if(h != null)
{
ContextHolder.Text = CommonHelper.GenerateShowText(h.Content, null);
}
}
}
现在运行程序,进入Home页,编辑它以增加一个链接,点击链接,进入新页,再编辑它增加一个链接,可以卡这个链接里已经包含了path信息。现在生成链接部分已经完成,就差在Wiki页顶端显示路径了。生成这个导航栏根据的基本信息就是title和path,所以应该增加一个help函数,写个单元测试先:
代码
[Test]
public void TestGetNavigationBar()
{
DbEntry.Context.DropAndCreate(typeof(Article));
Article.New.Init("Home", "abc [[Hello]] xyz").Save();
Article.New.Init("Hello", "abc [[Next]] xyz").Save();
Article.New.Init("Next", "abc [[Last]] xyz").Save();
var result = CommonHelper.GetNavigationBar("Home", null);
Assert.AreEqual(@"<a href=""Show.aspx?title=Home"">Home</a>", result);
result = CommonHelper.GetNavigationBar("Hello", null);
Assert.AreEqual(@"<a href=""Show.aspx?title=Home"">Home</a> > <a href=""Show.aspx?title=Hello"">Hello</a>", result);
result = CommonHelper.GetNavigationBar("Next", "2");
Assert.AreEqual(@"<a href=""Show.aspx?title=Home"">Home</a> > <a href=""Show.aspx?title=Hello"">Hello</a> > <a href=""Show.aspx?path=2&title=Next"">Hello</a>", result);
result = CommonHelper.GetNavigationBar("Last", "2_3");
Assert.AreEqual(@"<a href=""Show.aspx?title=Home"">Home</a> > <a href=""Show.aspx?title=Hello"">Hello</a> > <a href=""Show.aspx?path=2&title=Next"">Hello</a> > <a href=""Show.aspx?path=2_3&title=Last"">Hello</a>", result);
}
public void TestGetNavigationBar()
{
DbEntry.Context.DropAndCreate(typeof(Article));
Article.New.Init("Home", "abc [[Hello]] xyz").Save();
Article.New.Init("Hello", "abc [[Next]] xyz").Save();
Article.New.Init("Next", "abc [[Last]] xyz").Save();
var result = CommonHelper.GetNavigationBar("Home", null);
Assert.AreEqual(@"<a href=""Show.aspx?title=Home"">Home</a>", result);
result = CommonHelper.GetNavigationBar("Hello", null);
Assert.AreEqual(@"<a href=""Show.aspx?title=Home"">Home</a> > <a href=""Show.aspx?title=Hello"">Hello</a>", result);
result = CommonHelper.GetNavigationBar("Next", "2");
Assert.AreEqual(@"<a href=""Show.aspx?title=Home"">Home</a> > <a href=""Show.aspx?title=Hello"">Hello</a> > <a href=""Show.aspx?path=2&title=Next"">Hello</a>", result);
result = CommonHelper.GetNavigationBar("Last", "2_3");
Assert.AreEqual(@"<a href=""Show.aspx?title=Home"">Home</a> > <a href=""Show.aspx?title=Hello"">Hello</a> > <a href=""Show.aspx?path=2&title=Next"">Hello</a> > <a href=""Show.aspx?path=2_3&title=Last"">Hello</a>", result);
}
代码
public static string GetNavigationBar(string title, string path)
{
var buildUrls = new StringBuilder();
string buildPath = "";
buildUrls.Append(GetNavigationItem(Const.HomeName, null)).Append(Const.MenuSpliter);
if (title != null)
{
if (path != null)
{
string[] ss = path.Split(Const.ParameterSpliter);
foreach (var s in ss)
{
buildUrls.Append(GetNavigationItemById(s, buildPath));
buildUrls.Append(Const.MenuSpliter);
if (buildPath == "")
{
buildPath = s;
}
else
{
buildPath += Const.ParameterSpliter + s;
}
}
}
if (title != Const.HomeName)
{
buildUrls.Append(GetNavigationItem(title, path)).Append(Const.MenuSpliter);
}
}
buildUrls.Length -= Const.MenuSpliter.Length;
return buildUrls.ToString();
}
private static string GetNavigationItemById(string sid, string buildPath)
{
var id = long.Parse(sid);
var article = Article.FindById(id);
return GetNavigationItem(article.Title, buildPath);
}
private static string GetNavigationItem(string title, string path)
{
var html = HtmlBuilder.New;
var url = new UrlBuilder("Show.aspx");
if (!string.IsNullOrEmpty(path))
{
url.Add(Const.PathName, path);
}
url.Add(Const.TitleName, title);
return html.a(url.ToString()).text(title).end.ToString();
}
{
var buildUrls = new StringBuilder();
string buildPath = "";
buildUrls.Append(GetNavigationItem(Const.HomeName, null)).Append(Const.MenuSpliter);
if (title != null)
{
if (path != null)
{
string[] ss = path.Split(Const.ParameterSpliter);
foreach (var s in ss)
{
buildUrls.Append(GetNavigationItemById(s, buildPath));
buildUrls.Append(Const.MenuSpliter);
if (buildPath == "")
{
buildPath = s;
}
else
{
buildPath += Const.ParameterSpliter + s;
}
}
}
if (title != Const.HomeName)
{
buildUrls.Append(GetNavigationItem(title, path)).Append(Const.MenuSpliter);
}
}
buildUrls.Length -= Const.MenuSpliter.Length;
return buildUrls.ToString();
}
private static string GetNavigationItemById(string sid, string buildPath)
{
var id = long.Parse(sid);
var article = Article.FindById(id);
return GetNavigationItem(article.Title, buildPath);
}
private static string GetNavigationItem(string title, string path)
{
var html = HtmlBuilder.New;
var url = new UrlBuilder("Show.aspx");
if (!string.IsNullOrEmpty(path))
{
url.Add(Const.PathName, path);
}
url.Add(Const.TitleName, title);
return html.a(url.ToString()).text(title).end.ToString();
}
<asp:Label ID="NavigationBar" runat="server" Text="Home"></asp:Label> +++++++
再添加path参数,然后在Page_Load里添加如下的代码:
NavigationBar.Text = CommonHelper.GetNavigationBar(title, path);
再次运行程序,一路点击Wiki页内的链接,确认页顶的导航栏都显示正确。这时,进行编辑操作,会发现可能出现路径缺失现象,因为Edit.aspx页面还没有处理path参数,我们打开Edit.aspx页面,添加path参数,然后修改生成的用于Redirect的url为:
Response.Redirect(new UrlBuilder("Show.aspx").Add(Const.PathName, path).Add(Const.TitleName, title).ToString());
再次运行程序,仍然有路径缺失现象,发现是进入编辑页面的时候,路径就被丢弃了,所以我们修改SetLink函数,增加path参数:
代码
public static void SetLink(HyperLink link, string pageName, string linkPageName, string title, string path)
{
if (pageName.ToLower() == linkPageName.ToLower())
{
link.Enabled = false;
}
else
{
link.Enabled = true;
link.NavigateUrl = new UrlBuilder(linkPageName).Add(Const.PathName, path).Add(Const.TitleName, title).ToString();
}
}
{
if (pageName.ToLower() == linkPageName.ToLower())
{
link.Enabled = false;
}
else
{
link.Enabled = true;
link.NavigateUrl = new UrlBuilder(linkPageName).Add(Const.PathName, path).Add(Const.TitleName, title).ToString();
}
}
再次运行程序,终于全部正常了。至此,Wiki编辑功能全部完成,只是界面还有点儿惨不忍睹,下一步我们就要进行一些界面调整,不过现在,提交代码先。目前的代码:VisualWiki5.7z
未完待续……