学习捕获和显示任何 Workplace Designer 组件的文档更改历史记录的技术。可以将这些数据捕获到 XML 中,并使用 IBM Workplace Designer 功能更强大的控件之一 —— Panel 控件来显示这些数据。
许多用户希望并且也需要跟踪他们数据的更改。审核跟踪是电子文档的基本部分。进行更改的人物、时间和内容是跟踪的重要项目。但是,许多开发人员都知道,捕获这些更改并不总是十分容易,而且进行这项工作也非常单调乏味。
在 Notes/Domino 开发环境中,我们尝试了捕获文档更改历史记录的各种方法。与 Lotus Notes 和 Domino 一起使用时,常规方法是在隐藏字段中存储以前的数据,然后将这些字段与实际字段比较,以确定更改了什么内容。当 Lotus Domino 与 Domino Enterprise Connection Services(DECS)和 IBM DB2 结合使用时,我们喜欢的捕获历史记录方法是使用 DB2 Before Update 触发器。该方法允许访问以前存储的记录和将要保存的记录,所以可以比较两个文档。我们发现,使用 IBM Workplace Designer 可以摸拟此方法,方法是检索保存的文档的第二个副本并在执行 document.save() 之前比较这两个文档。本文演示了此方法,向您介绍使用 Workplace Designer 捕获并显示更改历史记录的一般方法。
本文的目标读者是 Workplace Designer 应用程序开发人员。
存储更改历史记录
应将文档的更改历史记录存储在何处?有多种选择。在 Lotus Domino 中,常规方法是将数据保存文本字段中,使用特定的字符(如 ~)将数据隔开。在报告更改或添加其他元素时,该方法会带来许多问题。另一个方法是为每个条目创建响应文档。Workplace Designer 文档新的 XML 数据模型提供一个更好的方法:将当数据作为 XML 子元素添加到当前文档中。每个文档中可以有一到多个元素。此方法将所有内部数据保存到文档中,因为它是 XML 格式,所以很容易操作和报告。
让我们定义一下需要捕获的数据。至少需要:
- 时间戳。 进行更改的当前日期和时间。
- 用户名。 进行更改的用户。
- 描述。对更改内容的描述。
对于本文,您可以修改随 IBM Workplace Designer 一起提供的 Project Manager 示例组件。通过选择现有应用程序,您会明白如何将本文中的代码应用到当前应用程序中,而无需从头创建新的应用程序。


|
回页首 |
|
导入 Project Manager 示例组件
首先,请将 Project Manager 组件导入到 Workplace Designer。如果使用的是 Workplace Designer 2.6,请按照以下步骤操作,为组件创建新的项目:
- 打开 Workplace Designer,并选择 File - New - Component。
- 选择 “Start with a sample component” 选项。
- 从列表框选择 ProjectManager 组件。
- 键入组件的名称和标签,然后单击 OK。参见图 1。
图 1. New Workplace Component 对话框
如果使用的是 Workplace Designer 2.5,请按照以下步骤操作,以便为示例组件创建新的项目:
- 打开 Workplace Designer,并选择 File - Import - Component。
- 浏览至示例组件目录(位于:
\your WMC directory\applications\eclipse\plugins\com.ibm.workplace.designer.sampleApps_1.0.0\sampleApps)。
- 选择 Project Manager 组件。根据需要更改组件名称。然后点击 OK。参见图 2。
图 2. Import Workplace Component 对话框


|
回页首 |
|
更改项目和发布模式
导入示例组件后,首要的任务是更改项目和发布模式,以包括 changeHistory 子元素。对于 Workplace Designer 2.5 和 2.6,请按照以下步骤操作:
- 在 Workplace Designer 中,从 Component Navigator 中选择并展开组件中的 Schemas。
- 双击项目模式将其打开。
- 直接选择 Root Elements 标记下的项目元素。
- 选择 Element - Append Element - As Child。还可以右键单击该项目来选择这些菜单项。
- 将元素命名为 changeHistory,并接受默认的字符串作为类型。
- 选择 changeHistory,并选择 Element - Append Element - As Child。
- 为名称键入 timestamp,并为元素类型选择 dateTime。
- 为元素 username 和 description(二者都是字符串类型)重复上述步骤。模式如图 3 所示。
图 3. 新的模式
- 保存更改。
- 对于发布模式,请重复上面的步骤 2 至 7。


|
回页首 |
|
创建 changeHistory 脚本库
将所有代码存储到脚本库中,这样可以方便地在表单间维护和共享代码。在开始编码之前,让我们讨论一下捕获文档更改历史记录所采取的步骤:
- 在文档的任何验证后,但在实际 document.save() 事件之前,调用 updateChangeHistory() 函数。
- 此函数首先检查这是否为一个新文档。如果是,则记录创建日期/时间和作者姓名。
- 如果是现有文档,则通过使用当前文档的 ID 获取原始文档的一个副本。
- 其次,比较关键字段,以确定它们是否已更改。
- 如果已更改,或者文档是新的,则使用 DOMDocument addContent() 方法插入新的 changeHistory 元素。
不必比较表格的所有字段来确定是否进行了更改。通常,用户有兴趣跟踪某些关键字段的更改历史记录。一些字段可能会定期进行更改,但是不想不必要地增加历史记录集的大小。对于项目表单,我们选择用户对了解更改历史记录感兴趣的以下字段:Project Name、Status、Manager、Budget 和 Status Update。对于发布表单,我们跟踪以下字段的更改:Type、Owner 和 Priority。
让我们从代码开始。
- 在 Workplace Designer 中,从 Component Navigator 选择并展开组件中的 Scripts 。
- 双击 Script Libraries,打开它们。
- 单击 New Script Library 按钮。
- 将库命名为 changeHistory 。
- 键入 “changeHistory 脚本” 中列出的代码。
- 保存更改。
在代码中,我们为需要比较的两个不同的数据类型创建了两个 helper 函数。一个函数用于字符串值比较,另一个用于 double 值比较。如果要比较其他类型,如日期值,则需要创建其他函数。
要注意的另一点是,在 compareDoubleValues() 函数中使用 I18n 类将 double 值转换为字符串。这个类提供各种国际化方法,包括许多对值进行格式化和转换的方法。虽然本文中不使用日期格式化函数,但是它们也是非常有用的。模式中的日期/时间值以国际化格式存储。当显示表单字段中 XML 模式的日期时,Workplace Designer 会为您处理日期格式。当在 JavaScript 中使用 XML 日期时,可以使用 I18n 类对这些日期进行格式化。
function compareStringValues(theField,theFieldDesc,currentDoc,
theOrigDoc,theUser,theTimeStamp,buildDescFlag){
//initialize theDescription string variable to hold our change description
var theDescription="";
if (currentDoc.getStringValue(theField)!=theOrigDoc.getStringValue(theField)){
//build the description
if (buildDescFlag){
theDescription=theFieldDesc + " changed from "
_+ theOrigDoc.getStringValue(theField)
_+ " to " + currentDoc.getStringValue(theField);
//use the passed in description. pass false in when data is too long to track.
}else{
theDescription=theFieldDesc;
}
insertHistory(theUser,theTimeStamp,theDescription,currentDoc);
}
}
function compareDoubleValues(theField,theFieldDesc,currentDoc,
theOrigDoc,theUser,theTimeStamp){
//initialize theDescription string variable to hold our change description
var theDescription="";
if (currentDoc.getDoubleValue(theField)!=theOrigDoc.getDoubleValue(theField)){
theDescription=theFieldDesc + " changed from "
_+ I18n.toString(theOrigDoc.getDoubleValue(theField))
_+ " to " + I18n.toString(currentDoc.getDoubleValue(theField));
insertHistory(theUser,theTimeStamp,theDescription,currentDoc);
}
}
|
在 insertHistory() 函数中需要指出一个项。在 Workplace Designer 产品文档中,可以查看 addContent() 方法的以下语法:
addContent(content:DOMContent) : DOMDocument
addContent(n:int, content:DOMContent) : DOMDocument
此方法的第二个版本指定一个整数值作为第一个参数。此值与 DOM 树中此元素的位置相关。通过包含整数值 1,如:
currentDoc.getRootElement().addContent(1,history);
可以将这个 history 元素放置在第一个位置,从而将前面的每一项下推一个位置。这可以确保历史记录更改按降存储,最近的更改位于顶部。由于不需要对数据排序,这样还易于稍后进行显示。
function insertHistory(theUser,theTimeStamp,theDescription,currentDoc){
//create a new DOMElement object for our history
var history = new DOMElement("changeHistory");
//set the user element
history.setStringValue("userName",theUser);
//set the timeStamp
history.setDateValue("timeStamp",theTimeStamp);
//set the description of the change
history.setStringValue("description",theDescription);
//Here is where we add the history object to our current document.
currentDoc.getRootElement().addContent(1,history);
print("<<<<adding content history");
}
|
注: 有关全部的 changeHistory 代码,请参见 “changeHistory 脚本”。


|
回页首 |
|
调用 updateChangeHistory() 函数
接下来,可以修改 ProjectEdit 和 IssueEdit 表单,以调用新的函数。调用 updateChangeHistory() 函数仅需要较短的代码。Workplace Designer 2.5 Project Manager 示例组件与 2.6 中的示例组件稍微不同。版本 2.6 包括执行检验的其他代码。
在 Workplace Designer 中,通过展开组件中的 Forms 打开 ProjectEdit 表单并双击 ProjectEdit 表单。如果是 Workplace Designer 2.5,请执行以下步骤:
- 向下滚动屏幕,单击 OK。
- 在 Properties 窗格中,选择 Basics 选项卡。
- 将 Button type 从 Submit 改为 Simple。这是非常必要的,因为单击按钮时要执行附加功能。
- 接下来,选择 Events 选项卡。
- 选择 onClick 事件。
- 输入以下代码。
import ChangeHistory;
import NavigationScripts;
updateChangeHistory(document);
saveCurrentDocument(document, context, "DepartmentProjectStatus.xsp");
|
- 保存更改,参见图 4。
图 4. ProjectEdit 表单上的 Events 选项卡
如果使用的是 Workplace Designer 2.6,请执行以下步骤:
- 向下滚动屏幕,并单击 OK。
- 选择 Events 选项卡。
- 选择 onClick 事件。
- 在现有脚本的顶部,输入:
import ChangeHistory;
- 在行
saveCurrentDocument(document, context, "DepartmentProjectStatus.xsp"); 的上方插入:
updateChangeHistory(document);
- 保存更改。
更改 ProjectEdit 表单之后,打开 IssueEdit 表单。如果使用的是 Workplace Designer 2.5,请执行以下步骤:
- 向下滚动屏幕,并单击 OK。
- 选择 Events 选项卡。
- 选择 onClick 事件。
- 在
import NavigationScripts; 下插入以下代码:
import ChangeHistory;
updateChangeHistory(document);
- 保存更改。参见图 5。
图 5.IssueEdit 表单上的 Events 选项卡
如果使用的是 Workplace Designer 2.6,执行以下步骤:
- 向下滚动屏幕,并单击 OK。
- 选择 Events 选项卡。
- 选择 onClick 事件。
- 在现有脚本的顶部,输入:
import ChangeHistory;
- 在行
saveCurrentDocument(document, context, "ProjectEdit.xsp"); 上方插入:
updateChangeHistory(document);
- 保存更改。
此时,应用程序已可以开始记录对识别字段的任何更改。


|
回页首 |
|
显示更改历史记录
记录文档更改历史记录之后,需要在表单中显示历史记录数据。Panel 控件是 Workplace Designer 中一个功能比较强大的 UI 控件。它可以包含其他 UI 控件,并根据某些条件重复其内容。可以使用 Panel 控件重复包含字段的表,以显示当前文档的所有更改历史记录元素。
使用表和面板
在表单中创建表以匹配其他表的最简便方法是复制现有表。复制项目表(第一个表)并将它粘贴在表单的底部。删除第二行中包含标签和字段的嵌入表。新表如图 6 所示。
图 6. 新表
如果是新文档,则需要隐藏历史记录表。选择表的 Basic 选项卡。对于 Visibility 属性,请选择 computed,并输入以下公式:
!@IsNewDoc();
接下来,为表设置一个标题。单击表的第一行中的计算字段,然后单击 Value 选择卡。将当前脚本替换为 Document History。在这里,可插入一个 Panel 控件,以重复历史记录数据。将光标放置在第二行上,从 UI Controls/Container Controls 面板拖放一个 Panel 控件。将面板的宽度设置为 100%。单击 Data 选项卡,并选择 “Specify a data source for this panel” 选项。将 Data source 设置 document。从下拉列表中选择 Project schema。对于 Data context 字段,输入 changeHistory(参见图 7)。
图 7. 面板属性
单击 Repeating 选项卡。选择 By XPath 选项,并在文本框中输入 /project/changeHistory。接下来,将一个三列的表插入该面板。该表包括要为每个历史记录元素显示的三个字段:timestamp、description 和 username。
将一个表控件拖放到面板。移除一行,使表成为具有三列的一行。然后需要重新调整面板的大小,因为该表可能已改变了面板的大小。将表单元格的宽度分别设置为 115、145 和 320。
现在,添加三个数据字段。将一个 Edit Box 控件拖放到第一个单元格。选择 Edit Box 控件,并单击 Basics 选项卡。删除 Label text。将 Read Only 属性设置为 true。将宽度设置为 100%。选择 Data 选项卡。从 Data binding 下拉列表中选择 timeStamp。如果在下拉列表中不能看到 timeStamp 元素,那么面板的数据和/或重复项存在问题(根据经验)。从 Date/time Format 下拉列表选择 <date and time>(参见图 8)。
图 8. 编辑框属性
为节省操作步骤,可以复制第一个字段,并将其粘贴到第二个单元格。单击 Data 选项卡。从 Data binding 下拉列表中选择 description。将 Display type 设置为字符串。将字段的另一个副本粘贴到第三列。单击 Data 选项卡,并从 Data binding 下拉列表中选择 userName 。将 Display type 设置为字符串。
快大功告成了!但还有一个问题需要纠正。我们发现在使用重复面板中的表时会显示额外的行。解决方案是隐藏表前和表后的段落。不执行上述步骤仍可继续,等到表包括额外行时再执行。请参见侧栏 “隐藏额外行”,获取详细信息。
 |
隐藏额外行
要隐藏额外行,单击面板中表上方的行。从下拉列表中选择 Paragraph,并将 Visibility 属性设置为 false。对面板中表下方的行执行同样的操作。
|
|
现在完成了项目表单,可以显示更改历史记录数据了。可以对 IssueEdit 表单重复相同的步骤,或将文档历史记录表复制到 IssueEdit 表单。需要在面板上的模式选择和 XPath 公式中用发布模式替代项目模式。
有关使用重复面板的其他示例,请参阅 IBM 红皮书 “IBM Workplace 2.5 Development with Workplace Designer”。


|
回页首 |
|
部署和测试更新的组件
现在已经为部署和测试更新的组件做好了准备。要将组件部署到服务器,请创建一个新项目并保存它。接下来,编辑该项目,并修改某些字段。其结果如图 9 所示。
图 9. 部署新组件


|
回页首 |
|
添加更多功能
捕获并显示文档更改历史记录之后,您会发现历史记录增加得很快。可能需要让用户确定是否显示文档历史记录表。向用户提供一个标签,单击它时,将变量设置为 sessionData,从而添加此功能。然后使用此变量隐藏或显示整个历史记录表。
在文档历史记录表上方拖放一个标签控件。选择标签和 Basics 选项卡。将 label 属性更改为 “+ Show Document History”。对于可视性,请选择 computed 并输入以下公式:
sessionData.showHistory!=true & !@IsNewDoc();
在 Events 选项卡上,选择 onClick() 事件。从下拉列表中选择 JavaScript,并选择 Run On Server 选项。输入以下脚本:
sessionData.showHistory = true;
在 Format 选项卡上,将颜色设置为 RGB {80,121,183}。此颜色与 ProjectEdit 表单上的其他标题匹配。必须为此标题定义一个自定义颜色。将 Style 设置为 bold。
接下来,创建另一个标签,以隐藏表。将另一个标签控件拖放到前一个标签控件下面。选择标签和 Basics 选项卡。将标签更改为 “- Hide Document History”。对于可视性,请选择 computed 并输入以下公式:
sessionData.showHistory==true & !@IsNewDoc();
在 Events 选项卡上,选择 onClick() 事件。从下拉列表中选择 JavaScript,并选择 Run On Server 选项。输入以下脚本:
sessionData.showHistory = false;
在 Format 选项卡上,将颜色设置为 RGB {80,121,183}。将 Style 设置为 bold。
接下来,更改文档历史记录表的 Visibility 公式。选择表,然后选择 Basics 选项卡。选择 Visibility 属性的计算公式,将其更改为:
!@IsNewDoc() & sessionData.showHistory;
要在打开文档时将历史记录表默认设置为隐藏的,请在 PostOpenDocument() 事件上将 showHistory 会话变量重新设置为 false。为此,请选择 Form 属性。选择 Events 选项卡,然后选择 onPostOpenDocument() 事件。从下拉列表中选择 JavaScript,并选择 Run On Server 选项。输入以下公式:
sessionData.showHistory=false;
图 10 显示了一个表单,它附带 “+ Show Document History” 和 “- Hide Document History” 标签以及具有新公式的 Events 选项卡。
图 10. 设置默认的表可视性
另一个注意事项是限制重复面板显示的数据量。在面板的 Repeating 选项卡上可以设置最大重复数。如果必要,可以在这里输入一个整数值。
现在,将上边的更改复制到 IssueEdit 表单,将新功能部署到服务器。试运行一下!


|
回页首 |
|
结束语
本文向您展示了一个简便方法,使用该方法可以捕获表单数据的更改,并将这些更改存储在 XML 子元素中。Workplace Designer 提供了一种 Panel 控件,它允许方便地重复这些数据,并将其显示在表单中。阅读并实现本文介绍的方法后,您会发现 Panel 控件和 XML 子元素有许多其他用途。 |