聪明的Web导航

发表于:2007-05-25来源:作者:点击数: 标签:web聪明Domino很好多方面
Domino在很多方面做的很好,但是也有许多做的不好的地方。自从Notes 数据库 可以用浏览器来打开之时,Domino 服务器 就在一些很简单的任务方面做的一团糟。很多时候我们要改进Domino服务器产生的代码,甚至是重写。 本文将关注Domino产生的视图/文档导航代码
Domino在很多方面做的很好,但是也有许多做的不好的地方。自从Notes数据库可以用浏览器来打开之时,Domino服务器就在一些很简单的任务方面做的一团糟。很多时候我们要改进Domino服务器产生的代码,甚至是重写。

本文将关注Domino产生的视图/文档导航代码。当你打开一个Domino视图的时候几乎很难看到所有的文档,这就需要需要指向下一页的链接,类似的情 况是当你转到下一页的时候就需要一个“上一页”链接。当你打开一个文档时如果有上一文档和下一文档的链接也是个不错的想法--否则就要回到视图去单击当前 文档上面/下面的文档链接。Domino可以很容易的生成所有的这些链接,但是运行的效果不是很理想,我们来动手解决它。

问题在哪儿?

Domino很多时候就是在元素上面加上双向的箭头,这在实际操作的时候很简单,生成的代码能正常运行,就是有些难看。要在视图的多个页面之间导航的时候,最简单的方法就是在$$ViewTemplate上创建两个操作热点,公式很简单:

@DbCommand( "Domino"; "ViewPreviousPage")

下一页的公式也同样简单,下面的图形是我们在Domino Designer里面的表单:


如我前面所说的,这些代码能正确运行,那么问题出在哪儿呢?让我们来看看公式所生成的HTML代码:

<< Previous

它就是执行一个名为_doClick()的JavaScript函数,这个函数只是简单的重新载入页面,但是传给服务器一个字符串,用它来告诉服务器在页面上按下了什么“按钮”,服务器可以通过这个函数来决定返回什么页面,为什么这么复杂呢?

这种代码有两个问题,第一个问题是它依赖于启用JavaScript的浏览器,第二个问题是Internet搜索引擎不能抓取这个视图下面的任何链接,也 就不会去索引这些文档,搜索引擎只喜欢那些使用href属性的链接,而现在这种情况是没有指向任何东西,搜索引擎不会去跟踪onClick时间所调用的任 何代码。

现在局域网里面绝大多数的Domino数据库都不会被搜索引擎抓取,而且我们几乎可以保证绝大多数的浏览器(或者用户)没有禁用任何东西。

但是在Internet上就是另外一回事了,根本就没有所有用户共享的一个通用环境,不止这些,而且搜索引擎是占有统治地位的,这就要求你要让站点尽可能的容易访问,不论是用户还是搜索引擎。

在文档级别也存在类似的问题,我们可以创建类似的上一文档和下一文档的链接,只需使用如@Command([NavigateNext])的公式即可,这种情况下生成的代码并不是很坏,但是依然存在问题,它生成的URL和下面的比较类似:

/db.nsf/ViewID/DocID?Navigate&To=Next

当你单击这个链接的时候,服务器返回给浏览器一个状态为302的HTTP回应,它告诉浏览器定位要找的文档并传给它正确的URL,这种情况下返回的就是下一个文档的URL。

现在还不能确认,但是可以假想搜索引擎(比如Google)不会喜欢这种链接。

可访问性先放在一边,还有一个较小的问题值得一提,它不仅是逻辑的问题,因为它并不象你所期望的那样运行。当你第一次打开一个视图或者打开视图里第一个文 档的时候,你回经常看到“上一页”链接,这种情况下单击链接就是重复的载入当前页面,当在文档中单击的时候,就会回到打开它的视图,在视图的最后一页或者 视图里面最后一个文档中也有类似的问题。还有一个比较奇怪的问题就是在视图的上一页和下一页之间跳转的时候,下一页里面的第一个文档就是上一页里面的最后 一个文档。

你可能会说这是吹毛求疵,但是现在这些都是用户/客户对网站的基本要求了。

解决这个问题

不要失望,这个问题可以解决,但是需要我们自己编写一些代码。

所说的两种情况中都要用到一个WebQueryOpen代理,一种情况是$$ViewTemplate,另外一种情况是文档(译者注:其实是生成文档的表单)。如果你确实不喜欢这个想法,那就不要继续看下去了。这种情况下的性能可能有些损失,但是好处也是显而易见的。

使用代理的话我们就可以得到视图的句柄并且计算出它里面有多少文档,使用这些信息我们就可以在表单上面使用一些简单的@函数来创建所需的链接,我们还可以告诉用户他们所处的页数以及共有多少页。

在文档级别中,代理在视图中定位当前entry并且搜索它上面和下面的entry,在这些信息的基础上,就可以知道是否显示上一个文档和下一个文档链接,其实并不只能做到这些,还可以提供一些文档的高级信息,比如标题。


为视图编码

代理只是简单的告诉我们在视图里面一共有多少文档,我们下面的工作可以使用@函数来在实际的表单上进行。

开始的时候我在得到总数的时候使用了下面的代码:

Set nav = view.CreateViewNav()
Call doc.ReplaceItemValue( "Total", nav.Count)

代码返回了我想要的结果,但是当向视图里面加入上千条文档之后,性能问题就凸显出来了,使用NotesViewEntryCollection也存在这个问题,经过一些测试和重写,发现最快的函数是视图的EntryCount属性。

Call doc.ReplaceItemValue( "Total", view.EntryCount)

然而这是R6的新特性并且不能用在分类视图中,有时候我们依然需要使用数据库的Search()函数,传给它和视图一样的搜索公式,如下所示:

Set col = db.Search("Form='article'", Nothing, 0)
Call doc.ReplaceItemValue( "Total", col.Count)

如果你的视图是分类视图,你就可以用复杂的公式来迎合你的需要,总体看来这是得到总数的最好的方法,下面的结果是一些不很科学的测试所得到的结果。
Approach/Documents

5,000

10,000

15,000

25,000

90,000

NotesViewNavigator.count

2s

7s

9s

-

-

NotesViewEntryCollection.count

-

-

3s

-

-

db.AllDocuments.count

-

-

0s

0s

-

db.Search.count

-

-

0s

1s

3s

view.EntryCount

-

-

-

-

0s


现在$$ViewTemplate表单上的Total域中就是所有文档的总数了,下面我们就来更正Domino产生的链接。

为了计算出是否显示链接和链接的指向,我们需要另外几个域。第一个是一个名为“Start”的数值类型的域,这个域检验URL中的&start= X,如果有那个参数(&start=X),它的值就会派上用场,如果没有那个参数,它就使用它的默认值1。我们还需要另外一个数值类型的域: ShowPerPage,它用来告诉我们视图每页上面显示的文档数目,如果URL使用了Count参数,并且域里面有值的话就会用这个域值,否则我们要硬 性指定一个数值(同样也是视图每页显示的行数)。本例中我选择了5并且在嵌入视图的“显示行数”属性中指定了相同的数值,如下图所示:


现在我们可以计算出要显示哪个链接和它的指向了,首先是“上一页”链接,这是一个包含下面公式的计算文本:

@If(Start<=1; @Return(" "); "");
newstart:=@If(Start-ShowPerPage<=1; 1; Start-ShowPerPage);
"+ "">« Previous"

我们首先做的是检查当前页面是不是第一页,如果是的话,计算文本就什么都不显示(一种隐藏链接的简单方法),就象没有生成它一样。

如果有一页的要显示的话,就会计算出它是不是开始的那个页面并生成指向它的链接。

下一页的代码和上面的很相似,不再赘述,另外一件要做的事情是显示页面的位置,代码如下:

@If(Total=0 | Total<=ShowPerPage ;
@Return("Page 1 of 1"); "");

div:=Total/ShowPerPage;
dif:=div-@Integer(div);
pages:=@Integer(div)+@If(dif=0;0;1);
"Page " + @Text(@Integer(Start/ShowPerPage)+1)
+ " of " + @Text(pages)

逻辑非常简单:用每页显示的文档数目去除总数,如果有余数,不管有多小,我们都要把值加上1,这就是页数。


为表单编码

为表单编码的过程和对视图的操作过程类似,只是所有的工作都是在WebQueryOpen代理中完成的,我们要做的只是得到当前文档的句柄并在视图里面进行定位。

通过文档对象的信息,我们可以计算出它是不是视图中的第一个或者最后一个文档,这样我们就可以决定我们是否需要创建链接并生成指向的具体文档的链接了。

尽管在视图里面我们由于性能原因不使用NotesViewNavigator对象,但是视图的大小好像并不影响计算当前文档信息所需的时间。

在我们开始计算之前,还需要在表单上面创建一些保存链接的域。因为没有必要保存它们,所以它可以是“显示时计算”类型的域,而且名字可以随意,我用的名字是PrevDocLink和NextDocLink,表单上面有了保存链接的域之后我们就可以开始编写代码了。

代码里面首先要做的是创建一个NotesViewNavigator对象并找到其中的当前文档,不要担心我们如何定义对象,代码其实就是很简单的两行:

Set nav = view.CreateViewNav()
Set ThisEntry = nav.GetEntry(doc)

有了这个信息我们就很容易知道它是不是视图里面第一个或者最后一个entry,我们还需要创建另外两个NotesViewEntry对象来达到我们的目 的,一个叫FirstEntry,另外一个叫LastEntry,接下来我们就可以测试当前文档是否是它们中的一个,下面的代码判计算它是不是第一个 entry:

Set FirstEntry = nav.GetFirstDocument

If ThisEntry.UniversalID = FirstEntry.UniversalID Then
Call doc.ReplaceItemValue( "PrevDocLink", "None Found")
Else
Call doc.ReplaceItemValue( "PrevDocLink",
"Open "+nav.GetPrev(ThisEntry).Document.GetItemValue("Title")(0)
+"
")
End If

代码确实不是那么复杂,首先判断当前文档是不是和第一个文档有相同的ID,如果相同,说明是第一条文档,那么就给“link”域赋上一个说明情况的值,或 者就是让它什么都不显示;如果不同,说明当前文档上面还有文档,我们就把指向它的链接赋到域中,为了让它看起来更具体一些,我们将链接的文档的真实标题显 示了出来。

生成下一条文档链接的代码和上面的很相似,你可以在附件中进行查看。

本文原文地址:Sensible Web Navigation[From:CodeStore]

原文转自:http://www.ltesting.net