hbaaron
小狐狸
小狐狸
  • UID37668
  • 注册日期2011-11-02
  • 最后登录2012-08-09
  • 发帖数66
  • 经验10枚
  • 威望0点
  • 贡献值0点
  • 好评度0点
阅读:3714回复:0

Firefox扩展SDK开发指南(四)

楼主#
更多 发布于:2012-02-06 16:18
到目前为止,我们已经知道如何使用SDK去开发一个简单的扩展。您还可以使用SDK去创建一个可复用,接口定义清晰的CommonJS模块。这些模块随后可以用在其它遵循CommonJS规范的程序中,也包括其它使用SDK构建的扩展。

即便您不打算为其它开发人员提供可复用模块,使用模块化方法来结构化一个大型的或者复杂的扩展也是有意义的。这样会使得您的扩展更加容易理解,也为各个模块提供了一些封装,从而使得您可以随后修改它们的内部实现,而不担心破坏其使用。
如果您喜欢这个系列的文章,请访问盛夏莲花博客以获取最新内容更新及评论,以及更好的阅读体验。
点击此处,在线体验浏览、分享、导航工具-阳光宝盒
在这个例子中,我们仍然从translator扩展开始,并且将创建一个单独的模块来完成翻译任务。
translate.js的实现

在您的transloter工程的根目录下,创建一个名为translater.js的新文件,并且加入下面的代码:

// Import the APIs we need. var request = require("request"); 
// Define the 'translate' function 
using Request;
function translate(text, callback) {
    if (text.length === 0) {
        throw ("Text to translate must not be empty");
    }
    var req = request.Request({
        url:"http://ajax.googleapis.com/ajax/services/language/translate", 
        content:{ v:"1.0", q:text, langpair:"|en" }, 
        onComplete:function (response) {
        callback(response.json.responseData.translatedText);
    } });
    req.get();
} 
// Export the 'translate' function 
exports.translate = translate;


translate函数本质上与我们前面赋值给onMessage的消息处理函数完全一致,只不过它接受一个回调函数来处理翻译后的结果,而不是将它直接替换到被选择的文本原来的位置。

在代码的最后部分,我们通过把它加入到全局对象exports上,以完成对函数的导出。
编辑main.js

接下来,我们需要修改main.js,以使用我们的新模块,而不是原来的request模块。

// Import the APIs we need.
var contextMenu = require("context-menu");
var selection = require("selection");
var translate = require("translate");
exports.main = function (options, callbacks) {
    console.log(options.loadReason);
    // Create a new context menu item. 
    var menuItem = contextMenu.Item({ label:"Translate Selection",
        // Show this item when a selection exists. 
        context:contextMenu.SelectionContext(),
        // When this item is clicked, post a message to the item with the
        // selected text and current URL. 
        contentScript:'self.on("click", function () {' + ' var text = window.getSelection().toString();' + ' self.postMessage(text);' + '});',
        // When we receive the message, call the translator with the 
        //selected text and replace it with the translation. 
        onMessage:function (text) {
            translate.translate(text, function (translation) {
                selection.text = translation;
            })
        } });
};
exports.onUnload = function (reason) {
    console.log(reason);
}


接下来,再次运行cfx run,以测试我们的扩展。这次也应该跟上次的运行结果完全一致,只不过现在我们的核心功能还可以被其它模块使用。
测试

SDK提供了一个用于测试的框架。出于演示目的,我们加上一些简单的单元测试。

浏览至test目录,删除掉test-main.js文件。在同样的位置创建一个名为test-translate.js的文件,并加入下面的代码:
var translate = require("translator/translate")
var testRunner;
var remainingTests;
function check_translation(translation) {
    testRunner.assertEqual("Lizard", translation);
    testRunner.done();
}
function test_languages(test, text) {
    testRunner = test;
    testRunner.waitUntilDone(2000);
    translate.translate(text, check_translation);
}
exports.test_german = function (test) {
    test_languages(test, "Eidechse");
}
exports.test_italian = function (test) {
    test_languages(test, "Lucertola");
}
exports.test_finnish = function (test) {
    test_languages(test, "Lisko");
}
exports.test_error = function (test) {
    test.assertRaises(function () {
        translate.translate("", check_translation);
    }, "Text to translate must not be empty");
};


该文件导出了4个函数,每个函数都有一个且惟有一个参数,即test对象。test对象由unit-test模块提供,它提供了一些简化单元测试的方法。在实现上,该文件导入了我们translator包里的模块。这里的PACKAGE/MODULE语法让您指定某个特定包里的特定模块,而不是在所有可用的包里去搜索它(比如通过使用require(“request”)。module-search的文档提供了更详细的说明。

前面三个函数调用translate方法并在回调函数里调用test.assertEqual来检查翻译结果是否正确。

第四个方法使用test.assertRaises检查被调用方法是否抛出了一个例外。

现在,您的包的结构应该如下图所示:

现在运行cfx –verbose test命令。您应该可以看到类似下面的输出:

cfx test所做的工作:
在test目录中查找您的包。
加载任何以test开头的模块。
调用这些模块中导出函数,将test对象传递给这些函数。
下一节,我们将概述SDK提供的API。
游客

返回顶部