你的下一个Web应用程序是Google Gadget吗?

来源:互联网 发布:freebsd下载源码好慢 编辑:程序博客网 时间:2024/06/05 09:46

你的下一个Web应用程序是Google Gadget吗?

by Aiessandro Lacava

翻 译:郭世龙

       学习怎样驾驭Google Gadget API使你的Web应用程序更可行。作为例子,我们来看看怎样打造一个实用的gadget,它能够取回并显示DevX的feeds。

       自从AJAX首次出现以来,对JavaScriot感兴趣的开发者数量快速增加——用JavaScript打造功用的工具集也迅速增长。Google Gadget 是JavaSctript开发相关的最新工具集之一。许多网站已经提供了用Google工具打造的gadget,你也可以。这篇文章就是想你展示怎样开发一个可以取回DevX RSS feed并显示给用户的Google Gadget。

 Google Gadget 剖析

      开发一个Google Gadget(简单的gadget从现在开始)确实是一个简单活。毕竟,一个gadget由XML、HTML、JavaScript,可选的有CSS。其作用如下:

            XML描述gadget的结构;

            HTML和CSS提供了表示层;

            JavaScript提供了gadget的逻辑层。

 下面的XML展示了基本的gadget结构:

<?xml version="1.0" encoding="UTF-8" ?>

  <Module>

  <ModulePrefs title="A title" />

  <Content type="html">

  <![CDATA[

  <!-- Here the CSS, JavaScript and HTML code -->

  ]]>

  </Content>

  </Module>

     这是XML元素的breakdown。根元素是ModuleModulePrefs元素持有关于gadget的信息(标题、高度等等)和作者的信息——稍后作更多介绍。Content元素一般包含“实际”的内容——

CSS、HTML和JavaScript代码。像你稍后看到的,有其他元素需要考虑,但是这些是你会在你开发的每个gadeget使用的基本元素。

 一个“Hello World” Gadget

    开始学习一个新的编程语言或技术最简单的方法是猛啃简单的实例。下面是一个在框框里打印出传统的“Hello,World”消息的gadget的代码。

<?xml version="1.0" encoding="UTF-8"?>
   <Module>
     <ModulePrefs title="Hello world example" />
     <Content type="html">
        <![CDATA[
          <div id="content" style="color: red;">
            hello, world!
          </div>
        ]]>
     </Content>
   </Module>

hello-world.xml作为保存前面的XML文件。现在你还不会用这文件——下一部分我将向你介绍怎样配置它——但是现在来看一下图1,它展示了运行的HelloWorld gadget的样子。

图1

看过了上面的例子,你可能注意到:

          你在XML文件中完整的定义了一个gadget.

          <Module>标签指示了这个XML文件包含了一个gadget.

          用ModulePrefs属性你指明了这个gadget的标题.

          <Content type="html">行指示gadget的内容类型是HTML(它可能也包含CSS和/或JavaScript代码)。也有其他的内容类型但是这一个最具柔性和通用性。你可以找到关于内容类型的更多信息 。

          CDATA部分包含HTML(可选的CSS和JavaScript)代码,这些代码用来提交和激活gadget。你不必使用CSS,你可以在你的HTML用简单的内联类型属性,像前面指明颜色(红色)的实例代码。

 用standard<style>标签包含CSS代码块,例如:

<style type="text/css">

  .your-class

  {

     color: red;

   }

</style>

 你可以像在标准HTML页中一样在<script>包括JavaScript代码:

    <script type="text/css">

  function init()

  {

  alert("hello, world");

  }

  </script>

稍后你将看到关于开发DevX RSS阅读器gadget中更多CSS和JavaScript的内容。

 Gadget部署

  当然,开发了gadget之后你要部署它。例如,为了运行“hello,world”gadget你需要一下步骤:

 1.上传gadget到你的web服务器。

2.去 http://www.google.com/ig。

3.为了加入gadget你必须有一个个性化主页。如果你还没有,你必须通过点击“开始(get started)”链接来创建一个。然后用已存在的google帐户登录,或创建一个新的帐户。

4.在有了个性化首页之后,你可以通过点击在右上角的“增加内容(add stuff)”链接来增加gadget。这将转入到内容目录(content directory)。你可以用内容目录搜寻gadget并将它们加入到你的主页。

5.点击“通过URL增加(Add by URL)”链接(临近“搜索主页内容(Search Homepage Content)”按钮。

6.在“通过URL增加(Add by URL)”域中输入URL(你的服务器或我的)获得hello-world.xml gadget,并且点击"增加(Add)"按钮。

7.点击“返回主页(Back to homepage)”链接,在你的主页上会看到新的gadget。

 作者提示:我在我的web服务器上上传了这篇文章的实例,即使你没有自己的服务器你也可试试它们。你可以在http://www.alessandrolacava.com/google/gadgets/路径下找到所有的实例。例如,与“hello,world”相关的URL是http://www.alessandrolacava.com/google/gadgets/hello-world.xml。

   你也可以在Google 内容目录发布你的gadget(publish your gadgets to the Google Content Directory)。那个链接也讨论了怎样发布你的gadget到另一个目标,像你自己的web网站通过聚合。

   既然你已经看到了怎样写和部署一个简单的gadget,你准备要继续更有趣的内容了。

 用户偏好

   一些gadget需要给用户一个提供用户指定信息的方式。例如,一个RSS—feed 阅读器gadget可能要求用户提供提取的条目数或用户感兴趣的feed的URL。XML文件中的用户偏好部分描述用户输入域,但gadget运行时,这个域变成了用户接口控制。为了在你的gadget中包含用户偏好,你需要包含<UserPref></UserPref>部分到你的XML文件中。返回到HelloWorld例子,你可能让用户通过UserPref元素指定这个gadget的标题:

<?xml version="1.0" encoding="UTF-8"?>

   <Module>

  <ModulePrefs title="__UP_title__" />

   <UserPref name="title" display_name="Gadget Title"

        default_value="Hello world example"

               datatype="string" />

          <Content type="html">

         <![CDATA[

            <div id="content" style="color: red;">

            hello, world!

            </div>

                   ]]>

        </Content>

   </Module>

图2显示了前面的用户偏好怎样呈现(rendered)——作位一个简单的文本框。

前面的实例中UserPref元素属性有如下意义:

 name是偏好(preference)的名字。就是通过名字你能在你的代码中引用这个偏好。这是唯一的必须属性。

 display_name是除了呈现(rendered)对象——文本框、选择框等等之外,被显示色标签。

 default_value是默认情况下选择的值。

               datatype是这个用户偏好的数据类型。选项是string、bool、enum、hidden、list或location。如果你没有指定datatype值,默认的是string。偏好的提交依赖这个属性。例如,一个dedataype定义为bool的偏好会呈现为一个选择框。稍后你会看到更多关于datatype的内容。

 

这些属性是最常用的的一些,除此之外还有还有其他的属性你可能在你的gadget需要的。参考 官方文档(official documentation)查找更多关于这个和其他的关于gadget API话题。

 

注意前面的代码是怎样指向用户偏好的。它使用哪个了双下划线,其后是“UP”,它指明的“用户偏好(User Prefenrence)”,另一个下划线,偏好名,用另一个双下划线结束:

                          __UP_prefName__

 要更改的唯一的事情是prefName,它必须与你在定义偏好的时候提供给name属性的值匹配。这一个变量被称作“替换变量(substitution variable)”。例如,你可以使用__UP_title__引用title偏好。接下来你会看到怎样在JavaScript段中程序性的应用用户偏好。

 

核心JavaScript库

 

 使用JavaScript管理gadget逻辑。使用下面的模板在你的gadget中包含JavaScript代码:

  <?xml version="1.0" encoding="UTF-8"?>

  <Module>

  <ModulePrefs title="Hello world example" />

  <UserPref name="title" display_name="Gadget Title"

        default_value=" Hello world example"

   datatype="string" />

  <Content type="html">

  <![CDATA[

   <script type="text/javascript">

    // Your JavaScript code here...

     </script>

  ]]>

   </Content>

  </Module>

 

   你将会经常使用哪个Google Gadget API 核心JavaScript库(Google Gadget API core JavaScript library)。在这个库中最重要的功能可能是_IG_RegisterOnloadHandler,它是事件句柄函数,当gadget加载时会被调用调用。它只有一个参数——函数,页面加载时它会被调用。下面是一个实例:

       <Content type="html">

  <![CDATA[

          <script type="text/javascript">

  function init()

  {

  alert("hello, world!");

  }            

          // Call the init function on page load

  _IG_RegisterOnloadHandler(init);

  </script>

  ]]>    

       </Content>

页面一加载时,这个gadget用 _IG_RegisterOnloadHandler调用init函数显示“hello,world”。

其他有用的Google Gadget API是_IG_Prefs类,你可以用它程序性的提取用户偏好:

     var prefs = new _IG_Prefs();

  var title = prefs.getString("title");

  alert(title);

前面的代码提取用户偏好的“title”并用JavaScript alert方法显示。另外getstring,你可以分别用getIntgetBool提取整型和布尔型用户偏好。你也可以像提取一样设置偏好,例如:

     var prefs = new _IG_Prefs();

  prefs.set("title", "The New Title Here");

使用设置器方法,你需要在你的gadget中包含setprefs库。使用Require XML元素——ModulePrefs的子元素来实现,例如:

     <ModulePrefs title="The title">

  <Require feature="setprefs"/>

  </ModulePrefs>

     你可以发现还有许多其他有用的JavaScript库。他们都在名为“Feature-Specific JavaScript Libraries”的库里。我不再在这篇文章中更多的涉及这个话题和其他具体特性的JavaScript库了,因为那需要专门的文章来讨论。

  但是,我将简单的讨论核心JavaScript库中一些有用的特性。例如,如果你想要在URL中提取内容作为文本,HTML或JSON(关于JSON更多的内容),你可以用如下使用_IG_FetchContent函数:

      <Content type="html">

  <![CDATA[

  <script type="text/javascript">

          function init()

       {

         _IG_FetchContent(

                              "http://www.some-content.to-display.com",

                                callbackFunc);

          }      

                 function callbackFunc(responseText)

           {

           _gel("mainContainer").innerHTML = responseText;

           }

  // Call the init function on page load

       _IG_RegisterOnloadHandler(init);

    </script>

       <div id="mainContainer"></div>

  ]]>

  </Content>

       你可能注意到了 _IG_FetchContent需要两个参数。第一个是去取回内容的URL。第二个是当内容取回时调用的回调函数。这是必要的,因为_IG_FetchContent是异步的,因此调用之后立即返回。在前面的实例中,回调函数在mainContainer div标签内显示HTML代码,这些HTML代码提取自那个假想的URL.

       当然,你可以随意地按照你喜欢的方式处理提取的内容。例如,无论gadget在何时候加载,你可以使用中方式显示一个随机的有趣的引语。注意,另一个核函数 _gel的使用,它只是一个"get-element"的快捷方式,它封装了关于冗长的 document.getElementById JavaScript 函数。还有其他的有用的封装函数。稍后你将会看到。其他的你可以点击查看Official API Reference.

  另外, _IG_FetchContent,这个核API提供了两个其他用作同样目的的函数:

          _IG_FetchXmlContent(URL, func):取回指定的URL中的XML内容。参数指定的函数。像 _IG_FetchContent(),它是异步的

          _IG_FetchFeedAsJSON(URL, func, num_entries, get_summaries): 异步方式取回指定的URL中的RSS/Atom feed并且将它作为一个JSON对象返回。当它准备好时,调用func。通

num_entries取回指定的feed实体的数目(默认是3,可能值是1-100),可选的是为每个实体取回概括(summaries),这取决于get_summaries的值——默认的是false。

 我使用了 _IG_FetchFeedAsJSON方法开发了DevX RSS Feed阅读器gadget。

 打造一个DevX RSS Feed阅读器Gadget

       列表1包括了打造DevX feed阅读器的完整代码。尽管乍看,可能看起来像是一堆代码,但是当你考虑到表示和业务逻辑时那就不是只是这样了。

     如果你没有服务器,你可以用URLhttp://www.alessandrolacava.com/google/gadgets/devx-feeds.xml来测试这个gadget。

尽管列表1是你迄今为止所见到的相当大的一个实例,但是它由你已经看到过那些元素构成,从Module根元素开始,它包含了下面的子元素:

      ModulePrefs

     UserPref 元素集

     Content元素

但是一些你尚未见过的方面值得解释一下。下面是ModulePrefs元素:

   <ModulePrefs title="__UP_title__"

     directory_title="DevX Feeds"

     description="Aggregate 1-10 entries of DevX Feeds.

  You can choose the feed to read by editing settings"

    author="Alessandro Lacava"

    author_email=alessandrolacava+devxgadget@gmail.com

    author_affiliation="DevX"

    author_location="Milan, ITALY"

    height="250"

    scrolling="true"

    singleton="false"

    author_link="http://www.alessandrolacava.com">

  </ModulePrefs>

     像你看到的,ModulePrefs元素包含一般关于gadget信息——作者信息、gadget的高度等等。因为内容可能超出高度,gadget通过scrolling="true"属性支持卷屏。注意我怎样写我的e-mail地址:alessandrolacava+devxgadget@gmail.com

我这样做是因为垃圾邮件,Gmail丢弃+号后面的内容。

     我前面告诉过你你可以为UserPref部分指定其他的数据类型。控件对偏好的呈现强烈的取决与你选择的数据类型。如果你没有指定数据类型,默认的是string,它呈现位一个简单的文本框。title偏好使用了默认呈现:

   <UserPref name="title"

  display_name="Gadget Title"

         default_value="DevX Feeds"/>

图3展现了这个样例gadget的title偏好和其他偏好项。

图3

     DevX gadget使用了bool、enum和默认的string偏好类型。像你从图3中看到的一样,gadget呈现bool型为选择框,而enum则呈现位复选框(下拉列表)。例如,在这feedUrl枚举偏好定义了让用户选择哪几个DevX feeds被取回。

    <UserPref name="feedUrl"

  display_name="Feed" datatype="enum"

   default_value="http://services.devx.com/outgoing/devxfeed.xml">

  <EnumValue value=http://services.devx.com/outgoing/devxfeed.xml

   display_value="Latest Articles"/>

   <EnumValue value=http://services.devx.com/outgoing/javafeed.xml

  display_value="Java"/>

  ...

  </UserPref>

     注意你可通过UserPref元素的display_value属性指示默认值,显示值可以不同于这个条目的值(value)。你可以使用display_value属性指明一个不同的显示值。如果你没有指明具体的显示值,控件则显示value属性——这种情况下,对于终端用户来说不方便。为了完整性,下面是更详细的在DevX gadget中使用的bool偏好中的一个的考察:

     <UserPref name="newPageTarget"

  display_name="Open Link In New Page"

  datatype="bool"

  default_value="true"/>

     前面的偏好定义让用户选择是否在同一个页面——这里是在Google 主页——或是不同的页面打开feed链接。我选择true作为这个偏好的默认值,意思时说选择框默认情况下是被勾选的并且所有

的feed链结将在新的浏览器实例中加载。

     像你可能猜到的那样,一个gadget最重要的部分放在内容元素中,这就是你为gadget应用程序定义表示层(CSS和HTML)和业务逻辑(JavaScript)的地方。

我没有深入的探究CSS部分,因为像其他CSS一样它只是样式。HTML部分限制在下面的代码行中:

    <div id="feedContainer"></div>

  这个div元素的内容将包含完整的gadget体——即,DevX RSS feeds。

    剩下的JavaScript部分由三个函数组成:fillGlobals, initparseFeed加上一个前面讨论的_IG_RegisterOnloadHandler,它注册init函数作为页面加载句柄。下面是init函数的代码:

  function init()

  {

  fillGlobals();

  // Display loading message before fetching feed.

  container.innerHTML =

                 '<div class="loadingLabel">Loading...</div>';

  // Fetch feed and return it as a JSON object.

  // parseFeed is the callback function.

  _IG_FetchFeedAsJSON(feedUrl, parseFeed, numOfEntries); 

     }

 函数init调用fillGlobals,它只是赋值给一些整个应用程序中使用的变量。通过提取用户偏好和获得一个指向包含feeds的feedContainer div标签的句柄来实现。下面是fillGlobals函数的代码:

  function fillGlobals()

  {

  var prefs = new _IG_Prefs(__MODULE_ID__);

  feedUrl = prefs.getString("feedUrl");

  numOfEntries = prefs.getInt("numOfEntries");

  container = _gel("feedContainer");

  showFeedDate = prefs.getBool("showFeedDate");

  openInNewPage = prefs.getBool("newPageTarget");

    }

 调用fillGlobals之后,init在主容器中显示“Loading...”消息,然后调用内嵌函数 _IG_FetchFeedAsJSON,它用来提取RSS作为一个JSON对象(关于JSON参看文章)。有三个参数传递

_IG_FetchFeedAsJSON,它们是:

          feedUrl:取回RSS feed的URL。fillGlobals方法从用户偏好提取指定偏好的feed值。

          parseFeed:这是一个回调函数,当feed被提取之后这个函数被出发。记住, _IG_FetchFeedAsJSON异步取回feed,完成之后,传递JSON对象——代表feed————给指定的回调函数,即parseFeed

          numOfEntries:提取实体的最大数。这个变量也被在用户偏好中的fillGlobals中初始化的。

这就是你需要知道的打造聪明的Google gadget的全部基本信息。图4显示了在我的Google主页上的完整gadget截屏。

      我不会深入探究parseFeed函数的细节,因为它只是基本的JavaScript代码,用来循环提取feed实体并把它们加入到gadget的主容器中(feedContainer div)。唯一你需要更多了解的是传递

parseFeed的JSON对象的结构。更多的信息请浏览官方文档(official documentation)。

 关于安全

        最后,我希望多几句话他一下安全性。事实上,你可能想知道:“是什么阻止我的gadget访问属于页面上别的gadget的数据?”

从gadget,它的类型是HTML——通过<Content type="html">行声明——你不能访问其他gadget的数据。原因是每一个HTML类型的gadget被提交给iframe。下面是来自Google Gadget开发守

则(Development Fundamentals)的一段话:

     “Gadget内容被包装在一个iframe中。一个iframe不尽准确的说是一个运行在父业面之上的分离页面。iframe不知道并且没有能力与父页面交互。这样的独立性帮助保护用户免于遭受尝试的恶意gadget的

伤害,例如,盗取或修改cookies。但是,iframe确实是通过拒绝gadget之间或去其他页面组件的交互施加了一定的限制。”

       你可以通过声明你的gadget位一个HTML内联(HTML-inline)gadget来逾越这些限制,通过改变它的content type设置成<Content type="html-inline">。当然,这各gadget的类型有其他的限制;例如,你不能用有其他的Google属性的HTML内联的gadget,并且内联的HTMLgadget不能被在内容目录中。内联的也也有其他主要的缺点,但它们超出了本文讨论的范围。关于gadget更多的信息,我强烈的建议你下载学习相关的文档(related documentation)。

源码

 Original Text