为 Lotus Connections Home page 实现和部署 Google 小部件

本文介绍由 IBM® 开发并可用于各种 IBM 产品(比如 IBM Lotus® Connections 2.0)的 iWidget 规范。本文通过一个实用的例子描述该规范的各个方面,展示如何实现一个能够用作 Google 小部件的 iWidget。

Vincent Burckhardt, 软件工程师, EMC

Vincent Burckhardt 是 IBM Dublin Software Laboratory 的软件工程师。Vincent 从 2007 年开始加入 IBM Lotus Connections development 团队。



2009 年 10 月 27 日

注意:本文讨论 Lotus Connections 2.0。您可以参考 developerWorks 文章 “Customizing Lotus Connections 2.5 with Lotus Widget Factory and Google Gadgets” 的第二部分,了解在 Lotus Connections 2.5 中部署 Google 小部件的步骤。本文的编程细节仍然是可用的,并且为希望了解 iWidget 规范的开发人员提供一个不错的起点。

Lotus Connections 2.0 包含一个新的、高度可定制和可扩展的 Home page,它使用户能够通过一个统一的视图查看来源不同的信息。这个 Home page 特性基于小部件,并允许您轻松地扩展 Lotus Connections 社交软件平台。

Lotus 软件试用下载

立即下载最新版本的 IBM Lotus 试用软件,轻松体验产品的最新特性!

Home page 特性允许您实现和添加自己的小部件。iWidget 是 IBM 为小部件定义的新定义。iWidget 规范 定义小部件的结构。iWidget 标准不局限于 Lotus Connections,它可用于其他产品(比如 IBM Mashup Center 的 Lotus Mashups),因此您只需要编写小部件一次就可以在不同的产品中运行它。

本文概述了创建和部署基础的 iWidget 并在 Home page 中运行它涉及到的步骤。本文展示如何将 Google 小部件包装到 iWidget 中。在阅读了本文之后,您应该能够创建可以向用户显示任何内容的基础小部件。

本文的前两个小节介绍与 iWidget 和 Google 小部件相关的必要理论知识。第 3 小节将逐步指导您实现一个能够用作基础的 Google 小部件包装器的 iWidget。最后,本文将深入讨论如何为 Google 小部件包装器添加改进。

创建和部署基础小部件的步骤非常简单。本文假设您熟悉最常见的 Web 开发技术,比如 JavaScript™、Java™ Platform, Enterprise Edition 和 XML。对以上技术有中等程度的了解即可,因为对于不常见的领域,比如 JavaScript Dojo Toolkit 的使用,本文将适时提供相关的介绍。

Home page 小部件和 iWidget 规范概述

本小节概述了 IBM iWidget 规范,并为理解后文的实现部分提供必要的理论知识。本文不会过于深入地研究该规范描述的某些特性。

Home page 小部件剖析

在讨论技术细节之前,我们先分析 Home page 小部件。Home page 小部件可以分为两部分:

  • 头部(Header)。包含小部件的标题和一些通过图标表示的操作按钮(移动、编辑、刷新、帮助和关闭)。
  • 主体(Body)。图 1 中红色矩形包围的部分,主体是向用户显示 iWidget 的地方。
图 1. Home page 小部件的结构
Home page 小部件的结构

小部件开发人员几乎能够完全控制在 Home page 小部件的主体部分显示的内容。小部件可以显示任何标准 Web 页面的内容。唯一的限制是必需遵循在 iWidget 规范中定义的组件模型。

Home page 运行时自动生成头部栏。您仅能对头部栏进行有限的定制。您可以定义哪个操作受 iWidget 的支持。Home page 自动隐藏嵌入的 iWidget 不支持的操作图标。管理员在部署时定义小部件的标题。

iWidget 描述器

描述器是 iWidget 的核心部分,必须从这里声明小部件支持的各种功能。可以用两种不同的风格编写 iWidget 描述器:microformat 或 XML 语法。因为 Lotus Connections Home page 仅支持 XML 定义风格,所以本文不介绍 microformat 语法。清单 1 显示了一个示例 Hello World iWidget XML 描述器。

清单 1. Hello World iWidget XML 描述器
<iw:iwidget name="helloWorld" xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget" 
iScope="HelloWorldWidgetClass">
   <iw:resource uri="helloworld.js" />			
   <iw:content mode="view">
      <![CDATA[
         <div id="root">
            Hello World! <br/>
               <button id="click" 
               onclick="iContext.iScope().onClickButton()">Click me!</button>
         </div>
      ]]> 
   </iw:content>     
</iw:iwidget>

这个小部件显示字符串 “Hello World” 和一个按钮,如图 2 所示。

图 2. Hello World 小部件
Hello World 小部件

例子的中的 XML 描述器的重要部分是:

  • iScope 属性。这个属性指定包含 iWidget 的逻辑的类的名称。它通常是在 XML 描述器中声明的资源之一中定义的 JavaScript 类。iWidget 框架为每个 iWidget 实例实例化一个 iScope 对象。
  • iw:resource 标记。这些标记指向 iWidget 需要的不同资源。Home page 支持 JavaScript 和层叠样式表(CSS)资源。将获取和计算在 XML 描述器中声明的每个资源。名为 “uri”(Uniform Resource Identifier)的属性与 XML 描述器的位置有关。在这个例子中,我们仅声明了一个资源,它是应该名为 helloworld.js 的 JavaScript 文件,所在的目录与 XML 描述器 file.iw:content 标记相同。这些标记定义特定模式的标记。标记片段是当 iWidget 显示特定模式时 Home page 为其呈现的 HTML 代码。这个例子中的小部件仅有一个模式 view(视图),它是默认的模式。

清单 2 显示了来自 helloworld.js 文件的代码,这些代码定义 iScope 类 HelloWorldWidgetClass。这个类仅定义一个方法 onClickButton,该方法是与在清单 1 中定义的按钮的 onclick 事件相关联的处理函数。当用户单击按钮时,一个窗口将显示字符串 “Button clicked”。

Dojo 语法

JavaScript 是基于原型的语言。为了给习惯面向对象编程的开发人员提供便利,Dojo Toolkit 提供了一些面向对象的类帮助程序(helper)。这个例子在声明没有继承任何父类(null)并有一个方法(onClickButton)的 HelloWorldWidgetClass 时使用了 dojo.declare 方法。

清单 2. helloworld.js 的内容
dojo.provide("HelloWorldWidgetClass");

dojo.declare(
   /* class name */                                            
   "HelloWorldWidgetClass",  
   /* parent class */ 
    null,
   /* methods and variables */ 
   {	
      onClickButton: function(){
         alert("Button clicked");
      }
   }
}

使用 iWidget 框架提供的服务

iContext 对象是用于与 iWidget 框架提供的服务交互的中心点。iWidget 框架自动将一个名为 iContext 的对象插入到您的小部件的 iScope 类,并将其作为一个成员 (this.iContext)。您可以通过 iContext 对象利用 iWidget 框架的功能。

另外,可以在小部件的 HTML 标记中使用 iContext 对象来以封装的方式调用 iScope 类的相关实例的方法。清单 1 的例子使用这种技术调用 onClickButton 方法。

封装和 iContext

封装是 iWidget 规范的重要部分。每个 iWidget 都需要进行封装,以避免同时在相同的页面上打开的几个小部件声明的资源之间发生冲突。iWidget 框架帮助您封装小部件,但您也需要完成一些工作。iWidget 开发人员尤其需要:

  • 正确声明 iWidget 类 (iScope) 的作用域,如本文的 “iWidget 描述器” 小节所述。iWidget 要使用的任何方法或变量都必须在 iScope 中声明。
  • 要避免在 iWidget 资源中使用全局 JavaScript 函数和变量,因为您不能保证该页面上的其他小部件没有声明同名的对象,如果存在同名对象将导致冲突。
  • 通过 iContext 对象与 iWidget 框架交互以获取作用域合适的对象。在 Hello World 例子中,您通过 iContext.iScope() 语句来实现该目的。

ItemSets

ItemSet 是一组由 iWidget 框架管理的名-值对。它们通常用于储存 iWidget 的属性。ItemSet 通过 iScope 类中的方法进行操作,比如 getItemValue 和 getAllNames(要了解更多信息,请参考 iWidget 规范)。ItemSet 可以在 XML 描述器中声明,如清单 3 所示。

清单 3. ItemSet 声明
<iw:itemSet id="itemSetId">
   <iw:item id="item1" value="value1" />
   <iw:item id="item2" value="value2" />
</iw:itemSet>

本文的最后一个小节 “进一步改进小部件包装器” 提供了一个具体的例子,阐述如何使用 ItemSet 储存您在本文中实现的 Google 小部件包装器的首选项。

iWidget 框架提供的其他服务

这个小节描述 iWidget 规范定义的其他服务。我们的 Google 小部件包装器仅使用了这些服务的一部分。iWidget 规范提供的功能包括:

  • 事件系统。这个系统允许 iWidget 触发和捕捉事件。在 Home page 中,这个机制用于在用户选择头部栏的操作(比如编辑和刷新)时对 iWidget 触发事件。
  • IO 模块。由于 JavaScript 实施同源安全策略(要了解细节,请访问 http://www.mozilla.org/projects/security/components/same-origin.html),所以不能对默认的 Home page 之外的其他域触发 Ajax 请求。为了提供将请求发送到其他域的能力,Home page 附带了一个 Ajax 代理。可以使用指定的 IO 模块重写任何 URL,从而通过内置的 Home page Ajax 代理重新路由 Ajax 请求。此外,还可以用它查找与 XML 描述器的位置相关的资源。
  • 连接系统。用户可以配置两个以上的小部件,并使用刚才提到的事件系统在它们之间交换数据。注意,这个特性在 Lotus Connections Home page 中不可用,但在 Lotus Mashups 中可用。

Google 小部件概述

Google 小部件是由 XML、HTML 和 JavaScript 组成的轻量级应用程序。可以将 Google 小部件添加到 Gadget 容器,比如 iGoogle(Google 的可定制主页)、Orkut/Google Maps 或 Google Desktop。任何人都可以开发小部件。Google 提供一个 公共目录,您可以通过它发布您的小部件。

就像 iWidget 一样,Google 小部件的核心部分包含在它的 XML 定义文件中。您可以在 开发人员的官方指南 的 “编写自己的小部件” 小节找到关于小部件 XML 描述器的细节。总而言之,小部件的 XML 定义指定两个主要方面:小部件的标记(HTML 代码)和一组首选项。

注意,目前有两个不同的 Google 小部件 API。本文使用 Google 支持联合小部件的遗留 API。

向任意 Web 站点添加 Google 小部件

Google 提供在任意 Web 站点上运行小部件的功能,这种功能称为联合(syndication)。您可以利用该功能创建允许您在 Lotus Connections Home page 中显示 Google 小部件的包装器。

  • 为了让您能够在小部件容器之外运行小部件,Google 提供这样一个 Web 服务:它返回由 JavaScript 和 HTML(负责发起并呈现小部件的依赖项)组成的格式化输出。该服务包含几个请求属性,尤其是:指向 Google 小部件 XML 定义文件的 URL。
  • 在小部件的 XML 描述器中定义的用户首选项(可以通过传递首选项的名称分配一个值)前面有一个 _up,作为服务的请求参数。传递的用户首选项值覆盖在 Google 小部件的 XML 定义中指定的默认值。
  • 显示首选项,比如标题、宽度、高度和边框样式。

Google 服务的基 URL 为字符串 http://www.gmodule.com/ig/ifr。现在提供一个完整的 URL 例子,它包含为 Date Time Google 小部件返回 JavaScript 代码的 Google 服务的请求属性:

http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/
datetime.xml&up_color=blue&up_firstDay=0&w=320&h=136&output=js

在该例子中,注意以下参数:

  • 提供咨询 Date Time 小部件的 XML 描述器的 URL:字符串 http://www.google.com/ig/modules/datetime.xml。
  • Color 和 firstDay 用户首选项(特定于该小部件)被设置为 blue 和 0(Sunday)。
  • Width (w) 和 height (h) 显示参数被设置为 320 px 和 136 px。

尽管您可以为 Web 服务手动创建 URL 以包含所需的请求参数,但使用 Google 提供的 Page Creator 工具是一项最佳实践。这个工具能以可视的方式快速构造 URL。该工具允许您为小部件的首选项指定值以及为服务生成 URL,包括在小部件的 XML 定义中定义的不同首选项的正确请求参数。要使用 Page Creator 工具,请遵循以下步骤:

  1. 访问 Google 小部件库
  2. 选择一个小部件,然后选择 Add to your webpage 选项。定制该小部件的设置和用户首选项的值。页面显示使用新值的小部件的预览图。
  3. 完成这些设置之后,选择 Get the code 选项。
  4. 该页面显示需要包含的代码。指向 Web 服务的 URL 为脚本标记的 src 属性中的字符串。

注意:您可能已经发现,Page Creator 返回的 URL 对一些特殊字符进行了强制类型转义。例如和号 (&) 字符被转义成 &。因为 URL 将保存在 HTML 或 XML 文档中,必须对特殊字符进行转义以确保文档有效。


在 iWidget 描述器中包装 Google 小部件

现在,您已经准备好为 Date Time Google 小部件编写包装器。图 3 显示了在 Home page 部署该小部件之后的结果。

图 3. 在 Home page 中部署的 Google Date Time 小部件
在 Home page 中部署的 Google Date Time 小部件

在这个小节中公开的方法适用于任何其他 Google 小部件,仅需一行帮助指向适当小部件的代码。

作为第一种方法,您的包装器非常基础:它的唯一目的是在 Home page 中呈现小部件。本文的最后小节主要关注向该包装器添加功能,比如用户可以通过它修改小部件首选项值的编辑视图。

呈现小部件和 XML 描述器的方法

IFRAME

IFRAME 是一个包含另一个文档的内联框架。它是一个标准的 HTML 元素,并且与 iWidget 规范没有特定的关系。IFRAME 的 src 属性指向将加载的文档的 URL。

要在 Home page 中呈现 Google 小部件,使用适当的请求参数调用在 “向任意 Web 站点添加 Google 小部件” 小节讨论的 Google Web 服务。调用的响应(包含 HTML 和 JavaScript)插入在一个脚本元素中。Script 元素位于 iWidget 的 IFRAME 部分的 HTML 文档中。

清单 4 显示了 iWidget 的 XML 描述器的代码骨架。清单 5 包含 JSP 文档 (gadgetWrapper.jsp) 的一部分,其中的脚本元素指向 Google 服务。

清单 4. 针对 Google 小部件的 iWidget 包装器定义
<iw:iwidget name="googleDateTime" 
xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget">
   <iw:content mode=”view”>
   <![CDATA[
      <iframe scrolling="auto" width="100%" height="300px" frameborder="0" 
      src="/gadgetWrapper/gadgetWrapper.jsp?url=<google gadget xml url>">
      </iframe>
   ]]> 
   </iw:content>     
</iw:iwidget>
清单 5. gadgetWrapper.jsp
<%
   StringBuffer url = new StringBuffer();
   url.append("http://www.gmodules.com/ig/ifr?");
   url.append(request.getQueryString());	
 %>

<script src="<%= url.toString() %>"></script>

如您所见,iWidget 呈现指向 gadgetWrapper JSP 页面的 IFRAME HTML 元素。JSP 页面负责以下任务:

  • 获取 URL 的查询字符串部分。即 URL 中字符 ? 之后的子字符串。在这个例子中,/gadgetWrapper/gadgetWrapper.jsp?url=<google gadget xml url> 的查询字符串部分为 url=<google gadget xml url>。
  • 通过将查询字符串附加到 gmodule.com 上的服务的上下文根构建指向 Google 服务的 URL。
  • 将脚本元素的 src 属性设置为指向包含来自查询字符串的适当小部件参数的 Google 服务。

如果您不使用 Java,那么可以根据您选择的语言(比如 PHP 或 .NET)调整 JSP 页面的行为。最重要的部分就是使用指向 Google 服务的 URL 设置脚本元素。

在这点上,要注意 3 个方面:

  • 我们本来可以将脚本元素直接插入到 iWidget 代码的 XML 定义中。但是,Google 服务返回的 JavaScript 代码之间的冲突迫使我们选择将脚本标记隔离在 IFRAME 元素中。
  • Google 服务的输出请求参数接受 html 值(而不是 js)。这导致可以将生成的 HTML 代码直接插入到 IFRAME 中(见清单 4),而不需要使用 JSP 解决方案。但是,这个解决方案没有在 Google 小部件下方包含 “gadget powered by Google” 和 “+Google” 按钮,这违反了 Google 小部件服务条款
  • 这个 iWidget 没有任何支持逻辑。因此,XML 定义不包含任何到 iScope 或 JavaScript 资源的引用。在本文的最后小节,您将为 iWidget 添加一些逻辑。

Google Date Time 小部件

清单 6 显示了针对包装了如图 3 所示的 Date Time Google 小部件的 iWidget 的 XML 描述器代码。IFRAME 元素的 src 属性指向这个位于 http://www.google.com/ig/modules/datetime.xml 的小部件的 XML 描述器的 URL。它还设置了特定于该小部件的用户参数,比如背景颜色(橙色)和每周的第一天(0 表示 Sunday)。如前所述,您可以通过检查小部件的 XML 定义找到哪些用户参数可用于特定的小部件,或者使用 Google Page Creator 工具完成该任务。

清单 6. 针对 Google Date Time 小部件的 iWidget 包装器定义
<iw:iwidget name="googleDateTime" 
xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget">
   <iw:content mode="view">
   <![CDATA[
      <iframe scrolling="auto" width="100%" frameborder="0"
	   src="/gadgetWrapper/gadgetWrapper.jsp?url=
http://www.google.com/ig/modules/datetime.xml&amp;up_color=
orange&amp;up_firstDay=0&amp;title=&amp;border=
&amp;output=js"></iframe>
        ]]> 
     </iw:content>
</iw:iwidget>

要将您选择的 Google 小部件的 URL 插入到 IFRAME 的 src 属性(source),请遵循 “向任意 Web 站点添加 Google 小部件” 小节描述的步骤。在这点上,您将用户首选项硬编码为 URL 请求字符串的一部分。在本文最后一个小节中,您将修改该代码以让用户能够更改首选项。

注意:在清单 6 中,我们还将两个显示参数(title 和 border)设置为空值。该设置允许您呈现没有标题和任何边框样式的 Google 小部件。


在 Home page 中部署 Google 小部件

将 iWidget 部署到 Home page 有两个主要步骤:

  1. 将 XML 描述器和 iWidget 的所有资源部署到 Web 服务器。
  2. 在 Home page 目录中注册小部件,具体操作是指向已部署的 iWidget XML 描述器的 URL。

部署 iWidget

将 iWidget 部署到 Web 服务器的方式非常灵活,因为您不局限于特定的服务器技术。例如,您的 iWidget 可以是一个部署到 PHP 服务器的 PHP 项目。您还可以将小部件实现为 Java Platform, Enterprise Edition 项目,并将其部署到 servlet/Java Platform, Enterprise Edition 容器中,比如 WebSphere® Application Server 或 Tomcat。您可以自行选择。注意,如果您没有使用 Java Platform, Enterprise Edition 容器,那么必须调整在 “呈现小部件和 XML 描述器” 小节中描述的 JSP 页面。

下面的步骤详细阐述了在 Eclipse 中将 iWidget 创建为一个 Web 项目并将其作为 EAR 文件导出的流程。然后可以将 EAR 文件部署到 Java Platform, Enterprise Edition 容器。

注意:您必须安装 Web 工具插件才能在 Eclipse 中创建 Web 项目。您可以从 http://download.eclipse.org/webtools/downloads/ 下载该插件。Java Platform, Enterprise Edition 版本的 Eclipse 包含该插件。

让我们创建项目并准备部署 EAR 文件。在 Eclipse 中,首先创建一个项目:

  1. 转到 File - New - Project。
  2. 在窗口中选择 Web - Dynamic Web Project,然后单击 Next。
  3. 输入任意的项目名,比如 gadgetWrapper。如果您想要直接从 Eclipse 部署项目,那么选择一个目标运行时;否则,选择 None。
  4. 选择 Add Project to an EAR 选项告诉 Eclipse 为这个 Web Project 创建一个 EAR 项目,并将它们关联起来。
  5. 选择 Next 获得最新的窗口。不要修改任何默认设置。单击 Finish 创建 Web 项目。

至此,您已经准备好处理该项目。

接下来,将 iWidget XML 描述器添加到项目中:

  1. 在 WebContent 下,通过右键单击目录名并选择 New - File 创建一个新的 XML 文件。输入 gadgetWrapper.xml 作为文件名。
  2. 在 Eclipse 中双击该文件打开它,然后将清单 6 中的代码复制粘贴到其中。如果您不能编辑该文件,那么检查是否选择了 source 选项卡。见图 4。
  3. 保存文件。
图 4. 在 Eclipse 中编辑的 gadgetWrapper.xml 文件
在 Eclipse 中编辑的 gadgetWrapper.xml 文件

要将在清单 5 中定义的 JSP 添加到项目,重复添加 XML 描述器的步骤。您可以在本文的下载小节中的 gadgetWrapper.ear 中找到该文件的完整本版。

接下来,生成部署到 Java Platform, Enterprise Edition 容器(比如 WebSphere Application Server)的 EAR 文件:

  1. 选择与先前创建的 Web 项目相关联的 EAR 项目。
  2. 右键单击并选择 Export - EAR file。
  3. 在磁盘上选择一个目标位置。

就这么简单!包含 iWidget 资源和 XML 文件的 EAR 文件已经就绪,可以将其部署到任何 Java Platform, Enterprise Edition 容器中了。

至此,您可以将 EAR 文件部署到 Java Platform, Enterprise Edition 容器中,就像部署其他 EAR 文件一样。

注意:清单 6 中显示的 IFRAME 有一个对上下文根设置为 /gadgetWrapper 的 JSP 页面(见清单 5)的引用。您必须根据 EAR 文件部署到的实际上下文根调整该设置。在本文的最后一个小节中,我们将展示如何使用 iWidget IO 模块解决该限制。

在 Home page 目录中注册小部件

Home page 提供一个管理用户界面,用于向目录数据库添加新的小部件。注意,只有具有管理员特权的用户能够向 Home page 目录添加小部件。

遵循以下步骤,使用 Home page Web 管理用户界面添加我们的 iWidget:

  1. 使用管理员帐户登录 Home page。
  2. 在 Home page 中选择 Administration 选项卡,如图 5 所示。
    图 5. Administration 选项卡
    Administration 选项卡
  3. 在页面的右下角选择 Add another widget 选项。
  4. 将显示如图 6 所示的表单。输入标题名和 iWidget 的 XML 描述器的位置。
    图 6. Administrators Home page
    Administrators Home page
  5. 输入小部件的标题。您输入的标题将显示在小部件的标题栏中;例如,标题可以是 Google Date Time。
  6. 输入 XML 描述器的位置。这个字段取决于您在 “部署 iWidget” 小节中部署小部件的位置。
  7. 其他文本字段是可选的,可以留空。例如,您可以指向一个图标。当小部件关闭之后,该图标将显示在侧栏中。
  8. 不要勾选任何复选框。仅当小部件与其他 Lotus Connections 特性交互时才使用它们。包装 Google 小部件的 iWidget 不需要使用这些选项。
  9. 单击 Save。

您可以在 Lotus Connections v2 Information Center 中更多地了解管理小部件的管理选项。


进一步改进小部件包装器

这个小节描述如何为基础的 iWidget 添加更多功能。尤其是,您可以添加这样一个功能,让用户可以修改在 Google 小部件定义中声明的一部分首选项。注意,用户首选项由 Google 小部件本身处理,因为它们在 Google 小部件的 XML 定义中被声明为 <UserPrefs> 元素。我们的目标是让用户为这些首选项选择值,并将它们传递到 Google 服务。

要让用户能够定制已包装的 Google 小部件,需要:

  1. 为小部件实现一个编辑视图,用户可以通过该视图定制在 Google 小部件定义中声明的首选项值。
  2. 将输入的值传递到 Google 服务,该服务是在前面的 “向任意 Web 站点添加 Google 小部件” 小节中引入的。为此,将新的首选项值作为 URL 的一部分传递给 Google 服务。

通过这些步骤,您还可以看到使用本文介绍的几个概念的实用例子,比如 ItemSet、iWidget 框架提供的封装机制和事件系统。

Date Time 小部件首选项

在这个小节,我们将通过修改现有的 iWidget 以让用户为 Google Date Time 小部件设置首选项。注意,以下的步骤对所有 Google 小部件都是一样的;所以,很容易调整这里的概念并应用到 Home page 的其他小部件的定制过程中。

通常,可以通过两种方式获取 Google 小部件的用户首选项列表:

  • 可以查看小部件的 XML 描述器,并找到 <UserPrefs> 元素。
  • 可以使用 Page Creator 工具。首选项列出在 Gadget 设置部分下面。

通过查看 Date Time 小部件的 XML 定义,您可以看到有两个用户首选项:

  • 背景颜色
  • 日历中的每周的第一天

这两个参数有一个以枚举方式定义的允许值列表。清单 7 显示了来自用户颜色首选项的小部件 XML 定义的枚举代码片段。用于每周的第一天的首选项也使用相同类型的枚举。在本小节的剩余部分,我们将实现让用户为这两个首选项之一挑选枚举列出的值。

清单 7. 来自 Date Time 小部件显示颜色首选项枚举的 XML 定义
<UserPref name="color" datatype="enum" default_value="blue" 
display_name="__MSG_color__">
   <EnumValue value="blue" display_value="__MSG_blue__"/>
   <EnumValue value="green" display_value="__MSG_green__"/>
   <EnumValue value="orange" display_value="__MSG_orange__"/>
   <EnumValue value="pink" display_value="__MSG_pink__"/>
   <EnumValue value="purple" display_value="__MSG_purple__"/>
   <EnumValue value="red" display_value="__MSG_red__"/>
   <EnumValue value="yellow" display_value="__MSG_yellow__"/>
</UserPref>

为 iWidget 添加逻辑

先前展示的 iWidget 是一个基础的小部件,它仅包含一些标记,而没有包含任何 JavaScript 逻辑。在这个基础的小部件中,指向 Google 服务的 URL 直接硬编码到 iWidget 的标记 (iw:content) 部分。现在,您想要根据用户输入的值动态地构建 URL。为了完成该步骤,您需要编写一些为生成的 URL 字符串实现逻辑的支持代码。现在的第一个目标是将 Google 服务 URL 的位置从 iWidget 的 HTML 标记移动到支持代码,涉及的步骤为:

  1. 通过在 iWidget XML 定义中将 src 属性从 IFRAME 删除来从标记中删除 URL。现在,内容部分如清单 8 所示。

    清单 8. iWidget 包装器视图的标记
    <iw:content mode="view">
       <![CDATA[
          <iframe id="frame" scrolling="auto" width="100%" 
          frameborder="0"></iframe>
       ]]> 
    </iw:content>
  2. 创建包含支持逻辑的 JavaScript 文件。如前所述,在称为 iScope 的 JavaScript 类中实现逻辑。在 Eclipse 中,创建和添加 JavaScript 文件的步骤与向项目添加 XML 文件的步骤一样,见前面的 “部署 iWidget” 小节。将该 JavaScript 文件命名为 googleGadgetWrapper.js。清单 9 显示了添加到该文件的代码。

    清单 9. 初步的 googleGadgetWrapper.js
    dojo.provide("GoogleGadgetWrapper");
    
    dojo.declare("GoogleGadgetWrapper", null, {	
    
       onLoad: function(){
       },
    	
       onview: function(){
       // get the frame DOM object declared in the widget markup
       var frame = this.iContext.getElementById("frame");	
    
       // get the URL to the JSP page location without having to hard-code
       // the context root in the code. For instance, if the context root  
       // after deployment is /gadgetWrapper/, jspLocation is set to
       // /gadgetWrapper/gadgetWrapper.jsp
       var jspLocation = this.iContext.io.rewriteURI("gadgetWrapper.jsp");
    	
       // set the src attribute of the iframe		
       frame.src = jspLocation + "?url=http://www.google.com/ig/modules/datetime.xml&
       title=&border=&output=js&w=400";
       }
    }

我们仔细研究一下清单 9 中的代码:

  1. iWidget 框架向小部件发送一个名为 Load 的 iEvent。我们不打算详细了解事件处理机制,但您需要知道它将导致在 iWidget 的 iScope 上调用一个名为 on + <事件名> 的方法。在这个例子中,这个机制导致调用 onLoad 方法。
  2. iWidget 框架加载小部件的默认模式 (view)。通过两个步骤加载模式:
    • 向用户显示与模式对应的标记(XML 描述器中的内容元素)。注意,在清单 7 中,您在该模式的内部声明了小部件的标记(mode="view" 属性)。
    • 带有模式的名称的 iEvent 被发送给小部件。在这个例子中,将导致调用方法 onview。

结果是当把小部件放到页面上之后,框架将自动调用 onLoad 和 onview 方法。

另外还要注意,我们使用来自 iWidget 框架(通过 iContext 对象)提供的 IO 模块的 rewriteURI 方法。这种方式允许您获得 JSP 文件的真实位置,而且不需要在代码中包含项目的上下文根。您不能确定在开发期间 iWidget 在其下部署的上下文根是什么,因为管理员可以在部署期间更改该值。

后台逻辑必须连接到 iWidget 的 XML 定义。通过两个步骤完成该连接:

  1. 添加一个资源元素标记,以指向刚才添加到项目的 JavaScript 文件:
    <iw:resource uri="googleGadgetWrapper.js" />
  2. 在 iWidget XML 描述器的 iw:widget 标记元素中设置 iScope 属性,使其指向在 googleGadgetWrapper.js 中定义的 JavaScript 类。因为您的 JavaScript 类的名称为 GoogleGadgetWrapper,所以 iw:widget 标记应该类似于:
    <iw:iwidget name="googleDateTime"
    xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget" iScope="GoogleGadgetWrapper">

就这么简单!现在,将在小部件初始化时动态地设置 IFRAME 的 src 属性。至此,小部件出现给用户的行为已经没有区别。您现在可以为指向 Google 服务的 URL 生成查询部分了。

储存参数并生成指向 Google 服务的 URL

在设置指向 IFRAME 的 URL 之前,您已经看到了一种生成和修改指向 Google 服务的 URL 的简便方法。在这个小节中,您将通过修改 URL 以加入用户首选项的值,这包括 3 个步骤:

  1. 将 Google 小部件的用户首选项值储存在您的 iWidget 的 ItemSet 中。使用 ItemSet 储存首选项的理由是:
    • 它提供一致的数据储存,您可以在代码的不同部分使用它来设置和获取用户选择的值。
    • 它允许您在 Home page 服务器的各个会话中保留首选项。这点在本文后面的 “持久化用户首选项” 小节实现。

    为此,让我们修改 iWidget 的 XML 定义以声明 ItemSet,并将其命名为 userPrefs。清单 10 显示了您随后要在编辑视图中使用的两个用户首选项的代码片段。

    清单 10. 为 Date Time 小部件储存用户首选项的 ItemSet
    <iw:itemSet id="userPrefs">
       <iw:item id="color" value="green" />
       <iw:item id="firstDay" value="0" />
    </iw:itemSet>

    注意,您还为每个用户首选项指定了默认值(green 和表示 Sunday 的 0)。

  2. 您需要实现一个从储存在 ItemSet 中的值动态地生成指向 Google 服务的 URL 的机制。为此,在 iWidget 的 iScope 类中添加另一个名为 getQueryString 的方法。清单 11 显示了该方法的代码。
    清单 11. 从首选项 ItemSet 返回查询字符串的方法
    getQueryString: function(){
       // get the ItemSet object
       var userPrefs = this.iContext.getItemSet("userPrefs");
    		
       // get the names ("id") of the items as an array		
       var prefNames = userPrefs.getAllNames();
    		
       // initialize an empty JavaScript object used as a map		
       var params = {};
    		
       // populate the params map with the user parameters
       dojo.forEach(prefNames, function(name) { 
          // we need to prefix the name with "up_" to pass it to the Google Service 
          as discussed in “Google gadget overview” part
          var upName = "up_" + name;
    	params[upName] = userPrefs.getItemValue(name);		
       });
    		
      // generate the string from the params map
      return dojo.objectToQuery(params);		
    }

    这个方法返回包含用户首选项的值的方法。例如,对于 Date Time 小部件,它返回字符串 up_color=green&up_firstDay=0。这个字符串可直接用于构建指向 Google 服务的 URL,Google 服务将为 Google 小部件返回对应的标记。

  3. 您必须修改清单 8 中的 onview 方法,以在将指向 Google 服务的 URL 设置为 IFRAME 的 src 属性之前调用 getQueryString 来构建它。清单 12 显示了修改后的 onview。
    清单 12. 修改后的 onview,包含用户首选项值的 URL 字符串是动态生成的
    onview: function(){   
       var frame = this.iContext.getElementById("frame");	
    	
       var query = this.getQueryString();
    
       var jspLocation = this.iContext.io.rewriteURI("gadgetWrapper.jsp");
    			
       frame.src = jspLocation + "?url=http://www.google.com/ig/modules/datetime.xml&
       title=&border=&output=js&w=400&" + query;
    }

实现编辑视图

至此,您已经实现了储存用户首选项并生成包含首选项值的 Google 服务 URL 的机制。在这个小节中,您将使用用户输入的值填充 ItemSet。完成该任务需要 3 个步骤:

  1. 实现一个允许用户为首选项选择值的图形界面。为此,您必须实现编辑(edit)视图的标记。在启用编辑视图的情况下,该实现将是用户与之交互的视图。在 Date Time Google 小部件中,您希望允许用户定制背景颜色和每周的第一天。因此,您仅需将编辑视图实现为包含两个下拉列表的表单,下拉列表包含两个用户首选项可以选择的值。

    图 7 显示了包装 Date Time 小部件的 iWidget 编辑视图。

    图 7. iWidget 包装器的编辑视图
    iWidget 包装器的编辑视图

    清单 13 显示的标记代码是 iWidget 的 XML 描述器的一部分。

    清单 13. 小部件 <iw:content mode="edit"> 的编辑视图代码
       <![CDATA[
       <table>
       <tr>
          <td>Color: </td>
    	<td>
          <select id="color">
    	   <option value="blue">Blue</option>
    	   <option value="green">Green</option>
    	   <!—other options here 
    	</select>
    	</td>
       </tr>
       <tr>
      —-- same principle as for the color drop-down list here -->
       </tr>
       </table>
       <br/>
       <input id="saveButton" type="button" value="Save" 
       onclick="iContext.iScope().onSave()" />
       <input id="cancelButton" type="button" value="Cancel" 
       onclick="iContext.iScope().onCancel()" />
       ]]> 
    </iw:content>

    在清单中,需要注意以下方面:

    • 标记放置在 mode 属性设置为 edit 的 iw:content 元素中。
    • 使用 iContext.iScope() 方法确保封装正确。
    • 该标记是一个 HTML 表,它包含两个带有两个按钮(Save 和 Cancel)的下拉列表。
  2. 向 iWidget 的支持逻辑添加方法,以通过用户输入填充 ItemSet。为此,您必须为按钮(onSave() 和 onCancel() 方法)实现支持逻辑。清单 14 显示了单击 Save 按钮时调用的 onSave() 方法的代码。
    清单 14. onSave() 方法的代码
    onSave: function(){
       // get ItemSet object
       var userPrefs = this.iContext.getItemSet("userPrefs"); 
    
       // set the item values from the drop-down list selections
       userPrefs.setItemValue("color", 
       this.iContext.getElementById("color").value);
       userPrefs.setItemValue("firstDay", 
       this.iContext.getElementById("firstDay").value);
    		
       // switch back to the view mode (widget normal view with the gadget)		
       this.iContext.iEvents.fireEvent("onModeChanged", 
       null, "{newMode: 'view'}");		
    }

    onSave() 方法通过用户输入为 ItemSet 的两个首选项设置新值。onSave() 方法的最后一行用于返回到小部件的视图模式。为此,您需要对小部件发出一个 onModeChanged 事件。iWidget 框架将该事件解释为将小部件的当前模式从编辑(edit)切换到视图(view)的请求。在该步骤中,将调用在 “为 iWidget 添加逻辑” 中描述的模式处理机制。

    Cancel 按钮的目标是返回到视图模式,并且不保存 ItemSet 中的首选项。因此,onCancel() 只是触发 onModeChanged 事件的 onSave() 的最后一行。

  3. 在 iWidget 的 XML 描述器中注册编辑模式。为此,向 XML 描述器的 iw:iwidget 元素添加 supportedMode 属性,如下所示:
    <iw:iwidget name="googleDateTime"
    xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget"
    iScope="GoogleGadgetWrapper" supportedModes="edit view">

    完成更改并重新部署小部件之后,用户将在 Home page 的小部件的头部栏上看到编辑图标,如图 8 所示。

图 8. iWidget 的头部栏的编辑图标
iWidget 的头部栏的编辑图标

当用户单击 Edit 时,Home page 运行时将对嵌入的 iWidget 触发 onModeChanged 事件。该事件导致框架呈现编辑视图并在 iWidget 的 iScope 中调用一个称为 onedit 的方法。为了完成该任务,清单 15 显示了如何在 onedit 方法中添加一些逻辑,以使用储存在 ItemSet 中的值设置编辑视图中的两个下拉列表。

清单 15. 使用存储值在编辑视图中设置下拉列表的 onedit 方法
onedit: function(){
   var userPrefs = this.iContext.getItemSet("userPrefs"); 
   this.iContext.getElementById("color").value = userPrefs.getItemValue("color");
   this.iContext.getElementById("firstDay").value = userPrefs.getItemValue("firstDay");
}

持久化用户首选项

更新:根据 iWidget 规范,现在的 Lotus Connections 2.5 支持用户首选项持久化。尽管 Lotus Connections 2.5 的向后兼容性使得本小节中的代码仍然有效,但我们建议您使用标准 iWidget。参考文章 “Customizing Lotus Connections 2.5 with Lotus Widget Factory and Google Gadgets” 的 “Lotus Connections 2.5 中的 iWidget 规范 v1.0” 了解更多细节。

对 iWidget 包装器的最后一个改进是持久化储存在 ItemSet 中的用户首选项。当您执行该任务时,用户所做的定制不会丢失。Home page 运行时为持久化 ItemSet 服务器提供两个方法(_save 和 _load)。

注意:这个实现是针对特定于 Home page 的 iWidget 框架的扩展;它不能用于其它 iWidget 容器,比如 Lotus Mashups。

_save 和 _load 方法接受 URI 作为参数,URI 是持久化 ItemSet 的位置。本文不讨论这些方法用于编码和解码 ItemSet 的系列化。您仅需要知道 Home page 提供一个接受并返回位于 handleUP?Act=XXX&FId=XXX 的系列化字符串的服务 (Servlet),其中 Act 以 SaveCustomization 和 LoadCustomization 作为值,FId 是 iWidget ID。

注意:在 Home page 中,您可以从 iContext (iContext.widgetId) 获得小部件 ID。这个变量专属于 Home page,不是 iWidget 规范的一部分。

清单 16 显示了 onLoad 方法的代码(在小部件放到页面上之后才调用),该方法负责使用来自持久化层的值填充 userPrefs ItemSet。注意,如果没有持久化任何值(即用户没有为该小部件编辑和保存首选项),那么默认值就是在 iWidget 的 XML 描述器中定义的值(见清单 9)。

清单 16. 从 Home page 持久化层加载用户首选项
onLoad: function(){
   var userPrefs = this.iContext.getItemSet("userPrefs");
   userPrefs._load("handleUP?Act=LoadCustomization&FId=" + this.iContext.widgetId);
}

最后,您需要保存 ItemSet 的值。当用户在编辑视图中单击 Save 按钮时,您必须完成该步骤。因此,您必须在触发 onModeChanged 事件之前调用 onSave 方法的 userPrefs 对象上的 _save 方法。您可以在本文下载小节的 EAR 文件中找到源代码。


结束语

本文讨论了实现一个包装 Google 小部件的基础 iWidget 并将其部署到 Lotus Connections Home page 所需的各个步骤。除了包装器本身的实现之外,本文还通过具体的例子展示 iWidget 框架提供的一部分特性。在阅读完本文之后,您应该了解了为 Home page 编写基础小部件所需掌握的概念,比如 XML 描述器、ItemSet、模式和事件。另外,您还可以继续改进 Google 包装器,例如允许用户在 iWidget 的编辑视图中输入小部件描述器的位置。


致谢

本文作者感谢 Luis Benitez 为撰写这篇 developerWorks 文章提供全程指导,并感谢 Adrian Spender 为本文的主题提供建议。

此外,本文作者还要感谢 Luis、Adrian 和 Li Xu 审阅了本文并提供修改建议。


下载

描述名字大小
gadgetWrapper.ear4KB

参考资料

学习

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Lotus
ArticleID=439595
ArticleTitle=为 Lotus Connections Home page 实现和部署 Google 小部件
publish-date=10272009