您知道 Microsoft Internet Explorer 5.5 具有編輯 HTML 的內(nèi)置支持嗎?我一直想有一個基于 XML 的好工具來做聯(lián)機討論,和新聞組差不多,但是結(jié)構(gòu)性更強,好讓我能輕松地添加新的功能。
我一直希望這類工具中能有這些功能:
唯一的問題是如何做好多信息文本編輯。我的朋友 Jonathan Marsh 開發(fā)了一個棒極了的原型。一旦 IE 5.5 給我解決了多信息文本編輯的問題,我就能根據(jù)朋友的原型把下面這些放在一起:
圖 1:原型 XML 討論列表
每個頂級討論線索是一個可以展開和折疊的層次結(jié)構(gòu)。它使用 Cookie 來記憶您在哪里。這樣,您回到討論時,還會回到同樣的位置。
您也可以看到用戶分級功能;在上面的圖里,選定的張貼內(nèi)容也是最受歡迎的張貼。最多可以分 4 級。要對消息進(jìn)行分級,用戶只需要在標(biāo)題 RATE THIS MESSAGE 旁邊單擊鏈接,網(wǎng)頁會將分級信息發(fā)布到服務(wù)器,并顯示新的平均值。它還可以做很多事情。最棒的是:它非常容易使用,而且速度足夠快,這樣用戶才會真正去用。
單擊 REPLY 的時候,詳細(xì)信息框架將進(jìn)入 HTML 多信息文本編輯器,如下圖所示:
圖 2:多信息文本編輯器接口
實際上,IE 5.5 的內(nèi)置編輯器還有很多這里沒有提到的功能。使用工具欄、彈出式菜單和您擁有的其他控件,您可以隨心所欲地創(chuàng)建內(nèi)容更加豐富的用戶界面。其實,這段代碼是從另一篇 MSDN 文章上獲得的:定位和編輯(英文)。
和所有基于 XML 的 Web 服務(wù)一樣,首先要為包含消息線索索引的論壇設(shè)計一個簡單的架構(gòu)。在這里,我決定使用傳統(tǒng)的文檔類型定義 (DTD):
<!ELEMENT discussion (title, threads*)><!ELEMENT title (#PCDATA)><!ELEMENT threads (message*)><!ELEMENT message (subject, body, author, posted, rating, replies)><!ELEMENT replies (message*)><!ATTLIST message id CDATA #REQUIRED><!ELEMENT subject (#PCDATA)><!ELEMENT body EMPTY><!ATTLIST body src CDATA #REQUIRED><!ELEMENT subject (#PCDATA)><!ELEMENT author EMPTY><!ATTLIST author name CDATA #IMPLIED email CDATA #IMPLIED><!ELEMENT rating EMPTY><!ATTLIST rating users CDATA #IMPLIED average CDATA #IMPLIED>
這段代碼會捕獲線索化討論的層次結(jié)構(gòu),在這個結(jié)構(gòu)中,消息包含了答復(fù),答復(fù)又包含了更多的消息,等等。每個張貼內(nèi)容的主體都存儲在獨立的 XHTML 文件中,而 <body> 元素的 src 屬性確定了文件的位置。
這個索引存儲在論壇目錄里名為 index.xml 的文件中。您將此目錄作為一個稱作 root 的 URL 參數(shù)提供給 discuss.asp 網(wǎng)頁。例如,上面的網(wǎng)頁是使用以下的 URL 顯示的:
http://localhost/xdiscuss/discuss.asp?root=userdata
這樣,同一個論壇 Web 應(yīng)用程序可以用來維護站點上任意數(shù)量的獨立論壇。例如,我有一個論壇討論這個應(yīng)用程序本身(就是上面那個),另一個則用來討論我正在開發(fā)的產(chǎn)品的新功能。
在服務(wù)器的論壇目錄中,還有一個名為 admin.xml 的文件,其中包含了允許刪除張貼內(nèi)容的用戶名稱和電子郵件別名:
<admin><user><name>clovett</name><permission>all</permission></user><user><name>jmarsh</name><permission>all</permission></user></admin>
現(xiàn)在,唯一的一個權(quán)限是“All”。很顯然,可以用很多方法來擴展這個列表。如果能用一個用戶界面來維護這個管理消息,那也是個好辦法。
您下載源代碼時,將看到以下文件:
文件名 | 說明 |
---|---|
Common.asp | 用于管理共享資源的一些通用 ASP 函數(shù) |
Cookies.js | 標(biāo)準(zhǔn)客戶端 Cookie 管理代碼 |
Defaults.xsl | 顯示 XML 的缺省樣式表(僅用于調(diào)試) |
Delete.asp | ASP 腳本,先檢查管理員權(quán)限,然后刪除消息 |
Detail.css | 用于消息詳細(xì)資料框架的層疊樣式表 |
Detail.xsl | 用于建立詳細(xì)信息框架 UI 的 XSL 轉(zhuǎn)換器 |
Discuss.asp | 應(yīng)用程序的主要入口點;取得一個稱作“Root”的 URL 參數(shù),指向位于同一服務(wù)器的論壇目錄 |
Discuss.css | 共享 CSS,用于控制論壇的總體外觀和風(fēng)格 |
Error.xsl | 用于格式化錯誤信息的小樣式表 |
Expand.js | 客戶端 JScript 代碼,用于管理大綱視圖的展開和折疊 |
Global.asa | 管理存儲在 ASP 應(yīng)用程序范圍內(nèi)的共享對象 |
Left.html | 左框架,目前僅包含調(diào)試鏈接 |
Message.asp | 用于生成選定消息的詳細(xì)信息視圖 |
Outline.asp | ASP 腳本,用于生成大綱視圖 |
Outline.css | CSS,用于控制大綱視圖的外觀 |
Post.asp | ASP 腳本,用于管理新消息的張貼 |
Relevance-filter.xsl | XSL 轉(zhuǎn)換器,用于過濾論壇索引,僅返回按某種方式分級的消息 |
Reply.asp | ASP 腳本,建立選定消息的答復(fù)用戶界面 |
Reply.js | 用于管理答復(fù)的一些客戶端 Jscript? 代碼 |
Reply.xsl | 客戶端 XSL 轉(zhuǎn)換器,用于建立答復(fù)框架的用戶界面 |
Unload.asp | ASP 腳本,從服務(wù)器下載所有共享應(yīng)用程序范圍內(nèi)的對象 |
User-rating.asp | ASP 腳本,用于處理每個用戶的分級 |
View-data.asp | ASP 腳本,返回內(nèi)存中給定論壇的 XML |
Xmlupdates.asp | 共享 ASP 腳本,post.asp 用它來實現(xiàn)一些簡單 XML 更新程序合并 |
上面的 XSL 轉(zhuǎn)換器是 http://www.w3.org/1999/XSL/Transform(英文)轉(zhuǎn)換器,同時使用了由 MSXML 3.0 提供的 msxsl:script 擴展。
圖 3:總體消息流
上圖說明了本應(yīng)用程序的總體消息流:index.xml 文件高速緩存在 ASP 應(yīng)用程序范圍中,以獲得更好的性能,該文件還會不時保存到磁盤中,以免丟失所作的更改。這些由共享 ASP 腳本 common.asp 以及 global.asa 和 unload.asp 共同管理。
頂級大綱框架由 outline.asp 生成。outline.asp 運行一個服務(wù)器端 XSL 轉(zhuǎn)換器以過濾出用戶想看的消息(基于分級進(jìn)行)。然后,它將篩選后的索引內(nèi)容發(fā)送至客戶端,內(nèi)容中附加的 outline.xsl 轉(zhuǎn)換器將執(zhí)行客戶端 XSL 轉(zhuǎn)換,以生成 DHTML 用戶界面。
當(dāng)您從大綱中選擇消息時,底部的詳細(xì)消息框架將顯示 message.asp 的運行結(jié)果。message.asp 從指定的論壇中找到指定消息并返回消息的詳細(xì)信息,同時通過附加的 detail.xsl 轉(zhuǎn)換器建立詳細(xì)信息 DHTML 用戶接口。
在詳細(xì)信息視圖中,您可以刪除調(diào)用 delete.asp 的消息,并檢查您是否具有管理員權(quán)限,或者答復(fù)這個消息。Reply.asp 建立模板消息,并使用 reply.xsl 轉(zhuǎn)換器來顯示多信息文本編輯器。從編輯器視圖上,您可以將答復(fù)張貼到 post.asp 腳本,它將有關(guān)您消息的信息添加到共享索引,并將消息主體保存到服務(wù)器上的單獨文件中。
從包含的源代碼數(shù)目中,您可以看出這并不僅僅是一個小練習(xí)。它開始通過服務(wù)器上的 JScript ASP 代碼、十分復(fù)雜的 XML 轉(zhuǎn)換器和技巧性的 DHTML 客戶端 UI 代碼來拓寬維護能力方面的限制。其中技巧性最強的一些是:
縮進(jìn) - 使用稱作 padding-left 的 CSS 樣式生成大綱視圖的縮進(jìn)。根據(jù) <message> 元素的嵌套深度計算該樣式的值。此計算在 outline.xsl 轉(zhuǎn)換器中執(zhí)行,使用以下 XPath 表達(dá)式:
padding-left:<xsl:value-of select="count(ancestor::message)"/>em;
本地時間 - 服務(wù)器在 post.asp 中生成消息的時間戳記,并將其保存為通用協(xié)調(diào)時間,通用協(xié)調(diào)時間是指定日期與 1970 年 1 月 1 日午夜之間的差(按毫秒計算)。使用 JScript Date() 對象的 getUTC* 方法完成這一功能。在客戶端,多種 XSL 轉(zhuǎn)換器使用 Date 對象的 getTimezoneOffset 方法將時間調(diào)回本地時間,并使用 toLocaleString 顯示為本地化字符串。這些工作由 XSL/T 轉(zhuǎn)換器中的 msxsl:script 塊完成。
多論壇支持 - 一個論壇應(yīng)用程序,可用于參加同一服務(wù)器上的多個論壇。您可以使用“Root”URL 參數(shù)選擇論壇,每個論壇的 index.xml 文件被高速緩存在應(yīng)用程序范圍中。為了管理所有論壇,使用了另一個動態(tài)生成的、自由線索的 XML 文檔對象來維護所有載入論壇的主控列表。這樣,當(dāng)在 global.asa 中引發(fā) Application_OnEnd 事件時,commmon.asp 中的 Unload() 方法可以找到所有載入的論壇,并將其全部卸載。
展開/折疊 - 大綱視圖實際上是一個只有一行的表。要實現(xiàn)層次結(jié)構(gòu)的展開/折疊,HTML 中需要包含足夠的信息,以便 DHTML 腳本代碼指出各行之間的父子層次結(jié)構(gòu)。它的實現(xiàn)方式是:通過 outline.xsl 轉(zhuǎn)換器,在每個 <TR> 元素上生成 id、thread、parent 和 depth expando 屬性。這些值按 XPath 父子關(guān)系來生成,非常巧妙。在 expand.js 中將使用這一 HTML 信息實現(xiàn)展開/折疊功能。當(dāng)前的展開狀態(tài)也被維護并保存在 Cookie 中,以便您回來時它還能保持原來的展開狀態(tài)。通過維護當(dāng)前展開消息的消息 ID 列表可以實現(xiàn)這一功能。
這時,要添加下面的新功能將會相當(dāng)容易: