日志更新

Firefox 的 Jetpack 扩展案例分析:Gmail 邮件提醒

Gtalk 软件的最下方有个很好又很实用的功能,就是 Gmail 邮件提醒功能。会定时更新你 Gmail 中未读新邮件的数量。

Gtalk

试想如果我们将此功能移植到 Firefox 上一定有趣!

第一步,在状态栏中显示图标和数据。

通过 《如何创建 Firefox 的 Jetpack 扩展》 这篇文章,我们可以轻易的创建:

jetpack.statusBar.append({
    html: '<img src="http://mail.google.com/mail/images/favicon.ico"/><span id="count"></span>', //Gmail邮件图标和未读新邮件数
    width: 55, //状态栏上的宽度为55
    onReady: function(widget) {
        $("#count", widget).css({ //给未读新邮件数添加样式
            cursor: "pointer",
            paddingLeft:"4px",
            fontFamily: "Tahoma, Arial, sans-serif",
            verticalAlign: "top",
            fontSize: "10px",
            lineHeight:"18px",       
        });
    }
});

第二步,获取 Gmail 的数据,更新未读新邮件数。

可以通过 Gmail 邮件的 Feed 获得(需登录):https://mail.google.com/mail/feed/atom

Feed 源码中的 fullcount 标签是用来记录当前的未读新邮件数。

OK,首先数据源有了。接着,我们使用再熟悉不过的 Ajax 技术,获取到数据并赋给指定的元素。

function update(widget) {
    var widget = $(widget);

    $.get("https://mail.google.com/mail/feed/atom", function(xml) {
        var el = $(xml).find("fullcount"); // 记录未读新邮件数的节点	
        if(el){
            var newcount = parseInt(el.get(0).textContent); 
            widget.find("#count").text(newcount); //赋给指定的元素
        } else { //如果未登录,显示“Login”
            widget.find("#count").text( "Login" );
	}
    });
}

我们还可以通过进行一些优化:比如当未读新邮件数大于原来的邮件数时,增加提示信息等。
提示信息这里使用 jetpack.notifications.show(options) 方法,options 参数有三个属性:title (String):通知的标题;icon (URL):通知 icon 的 URL;body (String):通知的主题内容。

优化后的代码如下:

var count = 0;

function update(widget) {
    var widget = $(widget),
        notify = function(msg) { // 定义通知的公用方法
            jetpack.notifications.show({
                title: "Gmail",
                body: msg,
                icon: "http://mail.google.com/mail/images/favicon.ico"
            });
        };

    $.get("https://mail.google.com/mail/feed/atom", function(xml) {
        var el = $(xml).find("fullcount"); // 记录未读新邮件数的节点	
        if(el){
            var newcount = parseInt(el.get(0).textContent); 
            if(newcount > count) { // 如果未读新邮件数大于原来的邮件数,则提示来自哪里
                var sender = $(xml).find("name").get(0).textContent;
                notify("New message from "+sender);
            }
            count = newcount;
            widget.find("#count").text(count); //赋给指定的元素

        } else { //如果未登录,提示登录
            widget.find("#count").text( "Login" );
            notify("Please login to Gmail");
	}
    });
}

第三步:设置定时更新数据。

我们设置每 1 分钟更新一次数据:

setInterval( function() { update(widget) }, 60*1000 );

第四步:设置点击扩展后的链接窗口。

$(widget).click(function() { //设置点击扩展后的链接窗口
    jetpack.tabs.open("http://mail.google.com");
    jetpack.tabs[ jetpack.tabs.length-1 ].focus();
});

jetpack.tabs 为浏览器窗口的标签对象,.open(url) 为新打开浏览器窗口标签的方法,.focus()为选中此标签为当前标签的方法。

OK,Firefox 的 Jetpack 扩展——Gmail 邮件提醒,经过简单的四步轻松完成。

全部代码如下:

var count = 0;

function update(widget) {
    var widget = $(widget),
        notify = function(msg) { // 定义通知的公用方法
            jetpack.notifications.show({
                title: "Gmail",
                body: msg,
                icon: "http://mail.google.com/mail/images/favicon.ico"
            });
        };

    $.get("https://mail.google.com/mail/feed/atom", function(xml) {
        var el = $(xml).find("fullcount"); // 记录未读新邮件数的节点	
        if(el){
            var newcount = parseInt(el.get(0).textContent); 
            if(newcount > count) { // 如果未读新邮件数大于原来的邮件数,则提示来自哪里
                var sender = $(xml).find("name").get(0).textContent;
                notify("New message from "+sender);
            }
            count = newcount;
            widget.find("#count").text(count); //赋给指定的元素

        } else { //如果未登录,提示登录
            widget.find("#count").text( "Login" );
            notify("Please login to Gmail");
	}
    });
}

jetpack.statusBar.append({
    html: '<img src="http://mail.google.com/mail/images/favicon.ico"/><span id="count"></span>', //Gmail邮件图标和未读新邮件数
    width: 40, //状态栏上的宽度为40,预留3位数的宽度
    onReady: function(widget) {
        $("#count", widget).css({ //给未读新邮件数添加样式
            cursor: "pointer",
            paddingLeft:"4px",
            fontFamily: "Tahoma, Arial, sans-serif",
            verticalAlign: "top",
            fontSize: "10px",
            lineHeight:"18px",       
        });

        $(widget).click(function() { //设置点击扩展后的链接窗口
            jetpack.tabs.open("http://mail.google.com");
            jetpack.tabs[ jetpack.tabs.length-1 ].focus();
        });

        update(widget);
	setInterval( function() {update(widget) }, 60*1000 );
    }
});

测试Demo:http://www.planabc.net/lab/jetpack/gmail/

对于 Jetpack 详细的 API,可以阅读 about:jetpack 页面的 API Reference 标签部分。

案例源码来自:https://jetpack.mozillalabs.com/demos/gmail-checker.js

如何创建 Firefox 的 Jetpack 扩展

Firefox 的 Jetpack 可以让我们很轻松地创建 Firefox 插件,仅通过已掌握的前端技能(HTML/CSS/JS),估计让人更兴奋的一点—— Jetpack 还集成了 jQuery 框架。

Adobe Air 也好,Web OS 也好, Jetpack 也好,至少让我们肯定一点,前端的价值将会在机遇中越来越大的被展现。

下面让我们一起来看看如何一步步创建你的第一个 Firefox 的 Jetpack 扩展

第一步:安装 Jetpack 插件

Jetpack 插件地址:https://jetpack.mozillalabs.com/install.html

安装完成 Jetpack 插件后,你就可以通过在地址栏中输入 about:jetpack 来访问 Jetpack 本地界面了。

about:jetpack

第二步:创建 planabc.js 文件。

planabc.js 的详细代码为:

jetpack.statusBar.append({
    html: '<img src="http://www.planabc.net/favicon.ico"/>',
    width: 16,
    onReady: function(widget){
        $(widget).click(function(){
            jetpack.tabs.focused.contentWindow.location = "http://www.planabc.net/";
        });
    }
});

jetpack.statusBar.append 将执行 JavaScript 对象(该JavaScript 对象有四个属性:html、url、width 和 onReady)。

  • html 属性:定义初始的 HTML,将显示在状态栏。此样例中,将显示一个简单的 IMG 元素。
  • url 属性:定义将在状态栏上显示的外部 HTML 内容的 URL。此样例中,未使用该属性。
  • width 属性:定义内容在状态栏上的宽度(单位:像素)。此样例中,定义为 16 像素,也就是 IMG 元素本身的宽度。
  • onReady 属性:定义被调用的函数(一旦状态栏被创建,此函数将会被调用)。由于 Jetpack 集成了 jQuery 框架,所以可以直接使用 jQuery 的属性和方法。在此样例中定义了这样一个函数,当点击该 Jetpack 扩展时,我们将修改 jetpack.tabs.focused.contentWindow.location 属性为 http://www.planabc.net/jetpack.tabs.focused.contentWindow 对象相当于 window 对象,你可以访问通过 JavaScript 访问网页。

第三步:测试 planabc.js 代码。

通过在地址栏中输入 about:jetpack 访问到 Jetpack 本地界面,点击 Develop 标签,然后将 planabc.js 文件中的代码拷贝到页面上的输入框中。点击 “try out this code” 按钮,你将会看到一个新的 icon 出现在 Firefox 窗口的右下角。

Develop 非常方便在代码部署前,在 Firefox 中测试你的代码。

Develop

第四步:部署 Jetpack 扩展。

创建一个简单的页面,在页面的 HEAD 元素内添加如下的 LINK 元素:

<link rel="jetpack" href="planabc.js" name="怿飞的博客"/>

HTML 文件源码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Mozilla Jetpack 案例</title>
        <link rel="jetpack" href="planabc.js" name="怿飞的博客"/>
    </head>
    <body>
        <a href="http://www.planabc.net/2009/10/13/build_firefox_extensions_with_jetpack/">《如何创建 Firefox 的 Jetpack 扩展》 </a>
    </body>
</html>

最后,将 HTML 文件和 planabc.js 文件都上传到服务器。

第五步:安装 Jetpack 扩展。

在 Firefox 中浏览该 HTML 页面时,Jetpack 插件将会在屏幕的最上方显示一个安装条,点击 “install” 按钮。将会提示安装不受信任的特性,点击 “I know what I’m doing. Install It!” 按钮。

安装完成和第三步测试一样,将会看到一个新的 icon 出现在 Firefox 窗口的右下角。如果此时你发现状态栏有2个相同的新 icon,那意味着原先的测试代码依然还在 about:jetpack 页面的 Develop 标签页中,清空输入框的代码即可消除。

返回到 about:jetpack 页面,点击 Installed Features 标签,将在列表中显示有新安装的 Jetpack 扩展。

测试Demo:http://www.planabc.net/lab/jetpack/planabc/

判断 iframe 是否加载完成的完美方法

一般来说,我们判断 iframe 是否加载完成其实与 判断 JavaScript 文件是否加载完成 采用的方法很类似:

var iframe = document.createElement("iframe");
iframe.src = "http://www.planabc.net";

if (!/*@cc_on!@*/0) { //if not IE
    iframe.onload = function(){
        alert("Local iframe is now loaded.");
    };
} else {
    iframe.onreadystatechange = function(){
        if (iframe.readyState == "complete"){
            alert("Local iframe is now loaded.");
        }
    };
}

document.body.appendChild(iframe);

最近, Nicholas C. Zakas 文章《Iframes, onload, and document.domain》的评论中 Christopher 提供了一个新的判断方法(很完美):

var iframe = document.createElement("iframe");
iframe.src = "http://www.planabc.net";

if (iframe.attachEvent){
    iframe.attachEvent("onload", function(){
        alert("Local iframe is now loaded.");
    });
} else {
    iframe.onload = function(){
        alert("Local iframe is now loaded.");
    };
}

document.body.appendChild(iframe);

几点补充说明:

  1. IE 支持 iframe 的 onload 事件,不过是隐形的,需要通过 attachEvent 来注册。
  2. 第二种方法比第一种方法更完美,因为 readystatechange 事件相对于 load 事件有一些潜在的问题。

CSS Expression 的优化

IE 浏览器中 CSS Expression 特性的最大的问题:会反复执行,每秒钟可能执行了成百上千次,有严重的性能问题。

如何对 CSS Expression 进行优化呢?

至少:如果我们将 CSS Expression 在匹配的元素中仅执行一次,性能将会提升很大。

old9《CSS Expression Reloaded》一文中提供了一个解决方案:

在 CSS Expression 语句体里,将触发该 Expression 的 CSS 属性重置。

例如:

div { 
    zoom: expression(function(el){el.style.zoom = "1"; alert(el.tagName);}(this));
}

补充几点:

  1. CSS Expression 执行在任意一个匹配的元素上。
  2. 在 CSS expression 内, “this”关键字指向当前匹配的 HTML 元素。
  3. CSS 属性选用一些不常用的属性来触发,触发完重置回默认值。

最近在 Ajaxian 的文章《Creating a querySelector for IE that runs at “native speed”》 中看到作者 Dion Almaer 也提供了一个类似的解决方式:

div { 
    -singlex: expression(this.singlex ? 0 : (function(t) { alert(t.tagName); t.singlex = 0; } )(this)); 
}

但此代码并没有完全解决 CSS Expression 最大的性能问题,因为每次触发还是要去执行 Expression 脚本。甚至你可以滚动下你鼠标的中间滚轮,意向不到的问题将会发生。

最后强调:仅是对 CSS Expression 做了优化,但并未说 CSS Expression 就不存在其他方面的问题。