阅读:4073回复:0
Firefox扩展SDK开发指南(四)
到目前为止,我们已经知道如何使用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。 |
|