From a065e04d529da1d847b5062a12c46d916408bf32 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 21:46:22 -0500 Subject: update based on https://github.com/mdn/yari/issues/2028 --- .../mozilla/add-ons/add-on_guidelines/index.html | 9 - files/zh-cn/mozilla/add-ons/amo/index.html | 11 - .../mozilla/add-ons/amo/policy/contact/index.html | 28 - files/zh-cn/mozilla/add-ons/amo/policy/index.html | 23 - .../add-ons/code_snippets/canvas/index.html | 237 ------ .../zh-cn/mozilla/add-ons/code_snippets/index.html | 134 --- .../add-ons/code_snippets/js_xpcom/index.html | 97 --- .../add-ons/code_snippets/modules/index.html | 37 - .../add-ons/code_snippets/queryselector/index.html | 114 --- .../add-ons/code_snippets/timers/index.html | 67 -- .../index.html | 470 ----------- .../index.html | 159 ---- .../index.html | 175 ---- .../index.html | 35 - .../mozilla/add-ons/extension_packaging/index.html | 38 - .../mozilla/add-ons/install_manifests/index.html | 363 --------- .../mozilla/add-ons/legacy_add_ons/index.html | 19 - .../mozilla/add-ons/overlay_extensions/index.html | 61 -- .../index.html | 91 --- files/zh-cn/mozilla/add-ons/plugins/index.html | 116 --- .../mozilla/add-ons/plugins/reference/index.html | 16 - .../plugins/samples_and_test_cases/index.html | 21 - .../index.html | 56 -- files/zh-cn/mozilla/add-ons/sdk/builder/index.html | 13 - .../add-ons/sdk/guides/content_scripts/index.html | 486 ----------- files/zh-cn/mozilla/add-ons/sdk/guides/index.html | 115 --- .../multiprocess_firefox_and_the_sdk/index.html | 212 ----- .../sdk/guides/working_with_events/index.html | 122 --- .../add-ons/sdk/high-level_apis/base64/index.html | 65 -- .../sdk/high-level_apis/clipboard/index.html | 101 --- .../mozilla/add-ons/sdk/high-level_apis/index.html | 12 - .../sdk/high-level_apis/notifications/index.html | 129 --- .../add-ons/sdk/high-level_apis/panel/index.html | 899 --------------------- .../add-ons/sdk/high-level_apis/tabs/index.html | 669 --------------- .../add-ons/sdk/high-level_apis/url/index.html | 191 ----- .../add-ons/sdk/high-level_apis/widget/index.html | 839 ------------------- files/zh-cn/mozilla/add-ons/sdk/index.html | 104 --- .../mozilla/add-ons/sdk/low-level_apis/index.html | 26 - .../sdk/low-level_apis/test_assert/index.html | 283 ------- .../sdk/low-level_apis/ui_button_action/index.html | 526 ------------ files/zh-cn/mozilla/add-ons/sdk/tools/index.html | 14 - .../zh-cn/mozilla/add-ons/sdk/tools/jpm/index.html | 652 --------------- .../add-ons/sdk/tools/package_json/index.html | 312 ------- .../add_a_menu_item_to_firefox/index.html | 92 --- .../adding_a_button_to_the_toolbar/index.html | 83 -- .../annotator/implementing_the_widget/index.html | 92 --- .../add-ons/sdk/tutorials/annotator/index.html | 36 - .../sdk/tutorials/annotator/overview/index.html | 54 -- .../sdk/tutorials/display_a_popup/index.html | 135 ---- .../sdk/tutorials/getting_started/index.html | 172 ---- .../sdk/tutorials/getting_started_(jpm)/index.html | 162 ---- .../zh-cn/mozilla/add-ons/sdk/tutorials/index.html | 144 ---- .../add-ons/sdk/tutorials/installation/index.html | 135 ---- .../mozilla/add-ons/sdk/tutorials/l10n/index.html | 381 --------- .../sdk/tutorials/list_open_tabs/index.html | 72 -- .../sdk/tutorials/listen_for_page_load/index.html | 42 - .../modifying_the_page_hosted_by_a_tab/index.html | 109 --- .../modifying_web_pages_based_on_url/index.html | 210 ----- .../sdk/tutorials/open_a_web_page/index.html | 52 -- .../sdk/tutorials/troubleshooting/index.html | 39 - .../add-ons/sdk/tutorials/unit_testing/index.html | 102 --- .../tutorials/\346\227\245\345\277\227/index.html" | 62 -- .../index.html" | 49 -- .../index.html | 58 -- .../add-ons/submitting_an_add-on_to_amo/index.html | 24 - files/zh-cn/mozilla/add-ons/themes/index.html | 65 -- .../creating_a_skin_for_firefox/index.html | 28 - .../creating_a_skin_for_firefox/uuid/index.html | 6 - .../mozilla/add-ons/themes/obsolete/index.html | 10 - .../obsolete/theme_changes_in_firefox_3/index.html | 92 --- .../embedded_webextensions/index.html | 205 ----- .../working_with_multiprocess_firefox/index.html | 296 ------- .../add-ons/\351\233\267\351\270\237/index.html" | 131 --- 73 files changed, 11285 deletions(-) delete mode 100644 files/zh-cn/mozilla/add-ons/add-on_guidelines/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/amo/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/amo/policy/contact/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/amo/policy/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/code_snippets/canvas/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/code_snippets/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/code_snippets/js_xpcom/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/code_snippets/modules/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/code_snippets/queryselector/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/code_snippets/timers/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/creating_custom_firefox_extensions_with_the_mozilla_build_system/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/creating_opensearch_plugins_for_firefox/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/creating_opensearch_plugins_for_firefox_clone/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/extension_frequently_asked_questions_move/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/extension_packaging/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/install_manifests/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/legacy_add_ons/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/overlay_extensions/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/performance_best_practices_in_extensions/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/plugins/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/plugins/reference/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/plugins/samples_and_test_cases/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/plugins/shipping_a_plugin_as_a_toolkit_bundle/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/builder/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/guides/content_scripts/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/guides/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/guides/multiprocess_firefox_and_the_sdk/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/guides/working_with_events/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/high-level_apis/base64/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/high-level_apis/clipboard/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/high-level_apis/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/high-level_apis/notifications/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/high-level_apis/panel/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/high-level_apis/tabs/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/high-level_apis/url/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/high-level_apis/widget/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/low-level_apis/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/low-level_apis/test_assert/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/low-level_apis/ui_button_action/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tools/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tools/jpm/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tools/package_json/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/add_a_menu_item_to_firefox/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/adding_a_button_to_the_toolbar/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/annotator/implementing_the_widget/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/annotator/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/annotator/overview/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/display_a_popup/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/getting_started/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/getting_started_(jpm)/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/installation/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/l10n/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/list_open_tabs/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/listen_for_page_load/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/modifying_the_page_hosted_by_a_tab/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/modifying_web_pages_based_on_url/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/open_a_web_page/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/troubleshooting/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/sdk/tutorials/unit_testing/index.html delete mode 100644 "files/zh-cn/mozilla/add-ons/sdk/tutorials/\346\227\245\345\277\227/index.html" delete mode 100644 "files/zh-cn/mozilla/add-ons/sdk/tutorials/\346\267\273\345\212\240\344\270\200\344\270\252\350\217\234\345\215\225\351\241\271/index.html" delete mode 100644 files/zh-cn/mozilla/add-ons/setting_up_extension_development_environment/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/submitting_an_add-on_to_amo/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/themes/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/themes/obsolete/creating_a_skin_for_firefox/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/themes/obsolete/creating_a_skin_for_firefox/uuid/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/themes/obsolete/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/themes/obsolete/theme_changes_in_firefox_3/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/webextensions/embedded_webextensions/index.html delete mode 100644 files/zh-cn/mozilla/add-ons/working_with_multiprocess_firefox/index.html delete mode 100644 "files/zh-cn/mozilla/add-ons/\351\233\267\351\270\237/index.html" (limited to 'files/zh-cn/mozilla/add-ons') diff --git a/files/zh-cn/mozilla/add-ons/add-on_guidelines/index.html b/files/zh-cn/mozilla/add-ons/add-on_guidelines/index.html deleted file mode 100644 index 58b185e048..0000000000 --- a/files/zh-cn/mozilla/add-ons/add-on_guidelines/index.html +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: 附加组件准则 -slug: Mozilla/Add-ons/Add-on_guidelines -tags: - - add-on - - 附加组件 -translation_of: 'https://extensionworkshop.com/documentation/publish/add-on-policies/' ---- -

REDIRECT https://developer.mozilla.org/zh-CN/docs/Mozilla/Add-ons/AMO/Policy/Reviews

diff --git a/files/zh-cn/mozilla/add-ons/amo/index.html b/files/zh-cn/mozilla/add-ons/amo/index.html deleted file mode 100644 index 0845e54e3d..0000000000 --- a/files/zh-cn/mozilla/add-ons/amo/index.html +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: AMO -slug: Mozilla/Add-ons/AMO -tags: - - NeedsTranslation - - TopicStub -translation_of: Mozilla/Add-ons/AMO ---- -

{{AddonSidebar}}

- -

Content to be added.

diff --git a/files/zh-cn/mozilla/add-ons/amo/policy/contact/index.html b/files/zh-cn/mozilla/add-ons/amo/policy/contact/index.html deleted file mode 100644 index c847ed92d1..0000000000 --- a/files/zh-cn/mozilla/add-ons/amo/policy/contact/index.html +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: AMO 联系信息 -slug: Mozilla/Add-ons/AMO/Policy/Contact -tags: - - 附加组件支持 -translation_of: Mozilla/Add-ons#Contact_us ---- -

{{AddonSideBar}}

- -

感谢您愿意与Mozilla 附加组件小组联络。 请仔细阅读此页面,以确保您的请求能到达正确的地方。

- -

附加组件支持

- -

如果您有关于特定附加组件的支持问题,例如“如何使用此附加组件?” 或“为什么不能正常工作?”,请通过附加组件列表页上列出的支持渠道联系该附加组件作者。

- -

附加组件审查相关

- -

如果您有关于附加组件审核希望报告违反政策的问题,请发送电子邮件至 amo-editors@mozilla.org。几乎所有的附加组件报告都属于这个类别。请务必包含相关附加组件的链接以及您的问题或评论的详细说明。

- -

附加组件安全漏洞

- -

如果您在附加程序中发现了安全漏洞,即使它不在此处托管,Mozilla也对您的发现感兴趣并将与附加开发人员一起尽快更正该问题。附加组件的安全问题可以直接报告Bugzillaconfidentially 或发邮件给 amo-admins@mozilla.org.

- -

网站功能与发展

- -

如果您发现本网站有问题 , 我们乐意修复。请在Github 上传BUG报告, 报告中包括问题的位置以及您如何遇到这个问题。

- -

关于这些政策或您的插件如何与我们联系。

diff --git a/files/zh-cn/mozilla/add-ons/amo/policy/index.html b/files/zh-cn/mozilla/add-ons/amo/policy/index.html deleted file mode 100644 index 58179ed4fa..0000000000 --- a/files/zh-cn/mozilla/add-ons/amo/policy/index.html +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: AMO Policies -slug: Mozilla/Add-ons/AMO/Policy -tags: - - NeedsTranslation - - TopicStub -translation_of: Mozilla/Add-ons/AMO/Policy ---- -

{{AddonSidebar}}

- -

Mozilla 致力于为我们的用户和开发人员确保极佳的附加体验,在提交您的附加组件之前,请查阅下列政策。

- -
-
开发者协议
-
Effective January 5, 2016
审核处理
-
Add-ons extend the core capabilities of Firefox, allowing users to modify and personalize their Web experience. A healthy add-on ecosystem, built on trust, is vital for developers to be successful and users to feel safe making Firefox their own. For these reasons, Mozilla requires all add-ons to comply with the following set of policies on acceptable practices. The below is not intended to serve as legal advice, nor is it intended to serve as a comprehensive list of terms to include in your add-on’s privacy policy.

-
精选的Add-ons
-
How up-and-coming add-ons become featured and what's involved in the process.

- 联系我们 - -

How to get in touch with us regarding these policies or your add-on.

- -
diff --git a/files/zh-cn/mozilla/add-ons/code_snippets/canvas/index.html b/files/zh-cn/mozilla/add-ons/code_snippets/canvas/index.html deleted file mode 100644 index 002a1b8600..0000000000 --- a/files/zh-cn/mozilla/add-ons/code_snippets/canvas/index.html +++ /dev/null @@ -1,237 +0,0 @@ ---- -title: Canvas 代码片段 -slug: Mozilla/Add-ons/Code_snippets/Canvas -translation_of: Archive/Add-ons/Code_snippets/Canvas ---- -

{{LegacyAddonsNotice}}

- -

关于使用<canvas>的一般信息,请参阅 canvas topic page.

- -

网页中可以用到的代码

- -

在画布中获取特定颜色的像素数量

- -

下面的函数将返回画布上颜色(RGB格式)为r、g、b的像素数量。如果用户希望像这篇博客文章中在另一个区域绘画,那么这将非常有用。 

- -
function getpixelamount(canvas, r, g, b) {
-  var cx = canvas.getContext('2d');
-  var pixels = cx.getImageData(0, 0, canvas.width, canvas.height);
-  var all = pixels.data.length;
-  var amount = 0;
-  for (i = 0; i < all; i += 4) {
-    if (pixels.data[i] === r &&
-        pixels.data[i + 1] === g &&
-        pixels.data[i + 2] === b) {
-      amount++;
-    }
-  }
-  return amount;
-};
-
- -

在画布中获取某一个像素的颜色

- -

下面的代码片段返回一个对象,该对象在画布的x和y的位置上具有RGBA值。这可以用来确定鼠标光标是否在一个特定的形状中。

- -
function getpixelcolour(canvas, x, y) {
-  var cx = canvas.getContext('2d');
-  var pixel = cx.getImageData(x, y, 1, 1);
-  return {
-    r: pixel.data[0],
-    g: pixel.data[1],
-    b: pixel.data[2],
-    a: pixel.data[3]
-  };
-}
-
- -

链式调用方法

- -

这个类允许可以像jQuery那样链式地访问 2D 渲染上下文的方法和属性 。

- -
function Canvas2DContext(canvas) {
-  if (typeof canvas === 'string') {
-    canvas = document.getElementById(canvas);
-  }
-  if (!(this instanceof Canvas2DContext)) {
-    return new Canvas2DContext(canvas);
-  }
-  this.context = this.ctx = canvas.getContext('2d');
-  if (!Canvas2DContext.prototype.arc) {
-    Canvas2DContext.setup.call(this, this.ctx);
-  }
-}
-Canvas2DContext.setup = function() {
-  var methods = ['arc', 'arcTo', 'beginPath', 'bezierCurveTo', 'clearRect', 'clip',
-    'closePath', 'drawImage', 'fill', 'fillRect', 'fillText', 'lineTo', 'moveTo',
-    'quadraticCurveTo', 'rect', 'restore', 'rotate', 'save', 'scale', 'setTransform',
-    'stroke', 'strokeRect', 'strokeText', 'transform', 'translate'];
-
-  var getterMethods = ['createPattern', 'drawFocusRing', 'isPointInPath', 'measureText', // drawFocusRing not currently supported
-    // The following might instead be wrapped to be able to chain their child objects
-    'createImageData', 'createLinearGradient',
-    'createRadialGradient', 'getImageData', 'putImageData'
-  ];
-
-  var props = ['canvas', 'fillStyle', 'font', 'globalAlpha', 'globalCompositeOperation',
-    'lineCap', 'lineJoin', 'lineWidth', 'miterLimit', 'shadowOffsetX', 'shadowOffsetY',
-    'shadowBlur', 'shadowColor', 'strokeStyle', 'textAlign', 'textBaseline'];
-
-  for (let m of methods) {
-    let method = m;
-    Canvas2DContext.prototype[method] = function() {
-      this.ctx[method].apply(this.ctx, arguments);
-      return this;
-    };
-  }
-
-  for (let m of getterMethods) {
-    let method = m;
-    Canvas2DContext.prototype[method] = function() {
-      return this.ctx[method].apply(this.ctx, arguments);
-    };
-  }
-
-  for (let p of props) {
-    let prop = p;
-    Canvas2DContext.prototype[prop] = function(value) {
-      if (value === undefined)
-        return this.ctx[prop];
-      this.ctx[prop] = value;
-      return this;
-    };
-  }
-};
-
-var canvas = document.getElementById('canvas');
-
-// Use context to get access to underlying context
-var ctx = Canvas2DContext(canvas)
-  .strokeStyle('rgb(30, 110, 210)')
-  .transform(10, 3, 4, 5, 1, 0)
-  .strokeRect(2, 10, 15, 20)
-  .context;
-
-// Use property name as a function (but without arguments) to get the value
-var strokeStyle = Canvas2DContext(canvas)
-  .strokeStyle('rgb(50, 110, 210)')
-  .strokeStyle();
-
- -

Code usable only from privileged code

- -

These snippets are only useful from privileged code, such as extensions or privileged apps.

- -

将canvas图片保存到文件中

- -

The following function accepts a canvas object and a destination file path string. The canvas is converted to a PNG file and saved to the specified location. The function returns a promise which resolves when the file has been completely saved.

- -
function saveCanvas(canvas, path, type, options) {
-    return Task.spawn(function *() {
-        var reader = new FileReader;
-        var blob = yield new Promise(accept => canvas.toBlob(accept, type, options));
-        reader.readAsArrayBuffer(blob);
-
-        yield new Promise(accept => { reader.onloadend = accept });
-
-        return yield OS.File.writeAtomic(path, new Uint8Array(reader.result),
-                                         { tmpPath: path + '.tmp' });
-    });
-}
-
- -

将一个远程页面加载到canvas元素上

- -

The following class first creates a hidden iframe element and attaches a listener to the frame's load event. Once the remote page has loaded, the remotePageLoaded method fires. This method gets a reference to the iframe's window and draws this window to a canvas object.

- -

Note that this only works if you are running the page from chrome. If you try running the code as a plain webpage, you will get a 'Security error" code: "1000' error.

- -
RemoteCanvas = function() {
-    this.url = 'http://developer.mozilla.org';
-};
-
-RemoteCanvas.CANVAS_WIDTH = 300;
-RemoteCanvas.CANVAS_HEIGHT = 300;
-
-RemoteCanvas.prototype.load = function() {
-    var windowWidth = window.innerWidth - 25;
-    var iframe;
-    iframe = document.createElement('iframe');
-    iframe.id = 'test-iframe';
-    iframe.height = '10px';
-    iframe.width = windowWidth + 'px';
-    iframe.style.visibility = 'hidden';
-    iframe.src = this.url;
-    // Here is where the magic happens... add a listener to the
-    // frame's onload event
-    iframe.addEventListener('load', this.remotePageLoaded, true);
-    //append to the end of the page
-    window.document.body.appendChild(iframe);
-    return;
-};
-
-RemoteCanvas.prototype.remotePageLoaded = function() {
-    // Look back up the iframe by id
-    var ldrFrame = document.getElementById('test-iframe');
-    // Get a reference to the window object you need for the canvas
-    // drawWindow method
-    var remoteWindow = ldrFrame.contentWindow;
-
-    //Draw canvas
-    var canvas = document.createElement('canvas');
-    canvas.style.width = RemoteCanvas.CANVAS_WIDTH + 'px';
-    canvas.style.height = RemoteCanvas.CANVAS_HEIGHT + 'px';
-    canvas.width = RemoteCanvas.CANVAS_WIDTH;
-    canvas.height = RemoteCanvas.CANVAS_HEIGHT;
-    var windowWidth = window.innerWidth - 25;
-    var windowHeight = window.innerHeight;
-
-    var ctx = canvas.getContext('2d');
-    ctx.clearRect(0, 0,
-                  RemoteCanvas.CANVAS_WIDTH,
-                  RemoteCanvas.CANVAS_HEIGHT);
-    ctx.save();
-    ctx.scale(RemoteCanvas.CANVAS_WIDTH / windowWidth,
-              RemoteCanvas.CANVAS_HEIGHT / windowHeight);
-    ctx.drawWindow(remoteWindow,
-                   0, 0,
-                   windowWidth, windowHeight,
-                   'rgb(255, 255, 255)');
-    ctx.restore();
-};
-
- -

Usage:

- -
var remoteCanvas = new RemoteCanvas();
-remoteCanvas.load();
-
- -

将图像文件转换为base64字符串

- -

下面代码加载远程图片,并把它的内容转化为 Data URI scheme

- -
var canvas = document.createElement('canvas');
-var ctxt = canvas.getContext('2d');
-function loadImageFile(url, callback) {
-  var image = new Image();
-  image.src = url;
-  return new Promise((accept, reject) => {
-    image.onload = accept;
-    image.onerror = reject;
-  }).then(accept => {
-    canvas.width = this.width;
-    canvas.height = this.height;
-    ctxt.clearRect(0, 0, this.width, this.height);
-    ctxt.drawImage(this, 0, 0);
-    accept(canvas.toDataURL());
-  });
-}
-
- -

Usage:

- -
loadImageFile('myimage.jpg').then(string64 => { alert(string64); });
-
- -

如果你想获取本地文件(使用文件选择input元素)的 base64 内容,你必须使用 FileReader 对象。

diff --git a/files/zh-cn/mozilla/add-ons/code_snippets/index.html b/files/zh-cn/mozilla/add-ons/code_snippets/index.html deleted file mode 100644 index bfe77a4e38..0000000000 --- a/files/zh-cn/mozilla/add-ons/code_snippets/index.html +++ /dev/null @@ -1,134 +0,0 @@ ---- -title: Code snippets -slug: Mozilla/Add-ons/Code_snippets -tags: - - Add-ons - - Code snippets - - Extensions - - NeedsTranslation - - TopicStub -translation_of: Archive/Add-ons/Code_snippets ---- -

{{LegacyAddonsNotice}}

- -

This is a quick list of useful code snippets (small code samples) available for developers of extensions for the various Mozilla applications. Many of these samples can also be used in XULRunner applications, as well as in actual Mozilla code itself.

- -

These examples demonstrate how to accomplish basic tasks that might not be immediately obvious.

- -

General

- -
-
Examples and demos from MDN articles
-
A collection of examples and demos from articles.
-
Window code
-
Opening and manipulating windows
-
Toolbar
-
Toolbar related code
-
Sidebar
-
Sidebar related code
-
Forms
-
Forms related code
-
XML
-
Code used to parse, write, manipulate, etc. XML
-
File I/O
-
Code used to read, write and process files
-
Drag & Drop
-
Code used to setup and handle drag and drop events
-
Dialogs
-
Code used to display and process dialog boxes
-
Alerts and Notifications
-
Modal and non-modal ways to notify users
-
Preferences
-
Code used to read, write, and modify preferences
-
JS XPCOM
-
Code used to define and call XPCOM components in JavaScript
-
Running applications
-
Code used to run other applications
-
<canvas> related
-
WHAT WG Canvas-related code
-
Signing a XPI
-
How to sign an XPI with PKI
-
Delayed Execution
-
Performing background operations.
-
Miscellaneous
-
Miscellaneous useful code fragments
-
HTML to DOM
-
Using a hidden browser element to parse HTML to a window's DOM
-
- -

JavaScript libraries

- -

Here are some JavaScript libraries that may come in handy.

- -
-
StringView
-
A library that implements a StringView view for JavaScript typed arrays. This lets you access data in typed arrays using C-like string functions.
-
Rosetta
-
By default, the only possible standardized scripting language for HTML is ECMAScript. Hence, if you are going to use another scripting language you might expect that most of the browsers will not recognize it. Nevertheless, the increasing computational power of modern browsers together with the introduction of typed arrays in ECMAScript allow us, in theory, to build full virtual machines in pure ECMAScript. Therefore, it is also possible, in theory, to use ECMAScript for a smaller task: parsing exotic programming languages (i.e., creating compilers). This snippets shows a possible way to start from.
-
- -

Browser-oriented code

- -
-
Tabbed browser code (Firefox/SeaMonkey)
-
Basic operations, such as page loading, with the tabbed browser, which is the heart of Mozilla's browser applications
-
Cookies
-
Reading, writing, modifying, and removing cookies
-
Page Loading
-
Code used to load pages, reload pages, and listen for page loads
-
Interaction between privileged and non-privileged code
-
How to communicate from extensions to websites and vice-versa.
-
Downloading Files
-
Code to download files, images, and to monitor download progress
-
Password Manager
-
Code used to read and write passwords to/from the integrated password manager
-
Bookmarks
-
Code used to read and write bookmarks
-
JavaScript Debugger Service
-
Code used to interact with the JavaScript Debugger Service
-
- -

SVG

- -
-
General
-
General information and utilities
-
SVG Animation
-
Animate SVG using JavaScript and SMIL
-
SVG Interacting with Script
-
Using JavaScript and DOM events to create interactive SVG
-
Embedding SVG in HTML and XUL
-
Using SVG to enhance HTML or XUL based markup
-
- -

XUL Widgets

- -
-
HTML in XUL for Rich Tooltips
-
Dynamically embed HTML into a XUL element to attain markup in a tooltip
-
Label and description
-
Special uses and line breaking examples
-
Tree
-
Setup and manipulation of trees using XUL and JS
-
Scrollbar
-
Changing style of scrollbars. Applies to scrollbars in browser and iframe as well.
-
Autocomplete
-
Code used to enable form autocomplete in a browser
-
Boxes
-
Tips and tricks when using boxes as containers
-
Tabbox
-
Removing and manipulating tabs in a tabbox
-
- -

Windows-specific

- -
-
Finding Window Handles (HWND) (Firefox)
-
How to use Windows API calls to find various kinds of Mozilla window handles. Window handles can be used for IPC and Accessibility purposes.
-
Using the Windows Registry with XPCOM
-
How to read, write, modify, delete, enumerate, and watch registry keys and values.
-
- - - -

The content at MozillaZine Example Code is slowly being moved here, but you can still find useful examples there for now.

diff --git a/files/zh-cn/mozilla/add-ons/code_snippets/js_xpcom/index.html b/files/zh-cn/mozilla/add-ons/code_snippets/js_xpcom/index.html deleted file mode 100644 index e5ab2b6189..0000000000 --- a/files/zh-cn/mozilla/add-ons/code_snippets/js_xpcom/index.html +++ /dev/null @@ -1,97 +0,0 @@ ---- -title: JS XPCOM -slug: Mozilla/Add-ons/Code_snippets/JS_XPCOM -translation_of: Archive/Add-ons/Code_snippets/JS_XPCOM ---- -

{{LegacyAddonsNotice}}

- -

这是一些解决XPCOM组件相关的有用的JavaScript代码。

- -

Contract IDs

- -

契约ID是XPCOM对象独一无二的名字。它们用于创建或者获得XPCOM中的对象。

- -

Interfaces

- -

Every XPCOM object implements one or more interfaces. An interface is simply a list of constants and methods that can be called on the object, an example is nsIFile. Every XPCOM object must implement the nsISupports interface.

- -

Accessing XPCOM components from JavaScript

- -

XPCOM objects are either created as new instances (each creation gives you a completely new COM object) or as services (each access gives you the same COM object, often called a singleton). Whether you must create a new instance or access as a service depends on the contract. In order to get an XPCOM object you need to know the contract ID of the object and the interface that you wish to use on it.

- -

Creating an instance of a component

- -

The preferred method of creating XPCOM instances is via the Components.Constructor helper. For example,

- -
var nsFile = Components.Constructor("@mozilla.org/file/local;1", "nsIFile", "initWithPath");
-
-var file = new nsFile(filePath);
-
- -

They can also be created and initialized manually:

- -
var file = Components.classes["@mozilla.org/file/local;1"]
-                     .createInstance(Components.interfaces.nsIFile);
-file.initWithPath(filePath);
-
- -

This creates a new instance of the object with contract ID @mozilla.org/file/local;1 and allows you to call methods from the nsIFile interface on it.

- -

Getting an XPCOM service

- -
var preferences = Components.classes["@mozilla.org/preferences-service;1"]
-                            .getService(Components.interfaces.nsIPrefService);
-
- -

You can then call any methods in the nsIPrefService interface on the preferences object.

- -

Getting a different interface for a component

- -

Some components implement more than one interface. Sometimes JavaScript is clever enough to know all the interfaces available on a component, but in most cases you will have to explicitly check for an interface. With the preferences service from the previous example we can do the following:

- -
var preferences = preferences.QueryInterface(Components.interfaces.nsIPrefBranch2);
-
- -

This allows you to use the methods in the nsIPrefBranch2 interface.

- -

Determining which interfaces an XPCOM component supports

- -

To display a list of all interfaces that an XPCOM component supports, do the following:

- -
// |c| is the XPCOM component instance
-for each (i in Components.interfaces) { if (c instanceof i) { alert(i); } }
-
- -

In this context, instanceof is the same as QueryInterface except that it returns false instead of throwing an exception when |c| doesn't support interface |i|. Another difference is that QueryInterface returns an object, where as instanceof returns a boolean.

- -

XPCOMUtils - About protocol handler

- -

{{ Fx_minversion_inline(3) }}This example implements a quick about protocol handler in JS using XPCOMUtils.jsm.

- -
Components.utils.import("resource://gre/modules/Services.jsm");
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-function AboutHandler() {}
-AboutHandler.prototype = {
-    newChannel: function(uri) {
-        var channel = Services.io.newChannel("chrome://mystuff/content/mystuff.xul", null, null);
-        channel.originalURI = uri;
-        return channel;
-    },
-    getURIFlags: function(uri) {
-        // Do NOT return Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT unless
-        // you make sure to set a non-system principal in newChannel.
-        return 0;
-    },
-
-    classDescription: "About MyStuff Page",
-    classID: Components.ID("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"),
-    contractID: "@mozilla.org/network/protocol/about;1?what=mystuff",
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule])
-}
-
-var NSGetModule = XPCOMUtils.generateNSGetModule([AboutHandler]);
-}
-
diff --git a/files/zh-cn/mozilla/add-ons/code_snippets/modules/index.html b/files/zh-cn/mozilla/add-ons/code_snippets/modules/index.html deleted file mode 100644 index 413e32f59a..0000000000 --- a/files/zh-cn/mozilla/add-ons/code_snippets/modules/index.html +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Modules -slug: Mozilla/Add-ons/Code_snippets/Modules -translation_of: Archive/Add-ons/Code_snippets/Modules ---- -

{{LegacyAddonsNotice}}

- -

一些简单的代码将JavaScript模块转换为非Mozilla特定的代码(例如,如果移植到浏览器)。eval()的使用可能不会被关注,因为它仅在EXPORTED_SYMBOLS 数组上使用,而不依赖于用户输入。

- -
函数importModule(thatObj){
-    thatObj = thatObj || 窗口;
-
-    var EXPORTED_SYMBOLS = [
-    //把符号放在这里
-    ]。
-
-    //你的代码在这里...
-
-    //在你的代码结尾处:(假设'i'和'thatObj'都没有被导出!)
-    for(var i = 0; i <EXPORTED_SYMBOLS.length; i ++){thatObj [EXPORTED_SYMBOLS [i]] = eval(EXPORTED_SYMBOLS [i]);}
-}
-
- -

或一次性使用模块:

- -
(function(thatObj){
-    thatObj = thatObj || 窗口;
-
-    var EXPORTED_SYMBOLS = [
-    //把符号放在这里
-    ]。
-
-    //你的代码在这里...
-
-    //在你的代码结尾处:(假设'i'和'thatObj'都没有被导出!)
-    for(var i = 0; i <EXPORTED_SYMBOLS.length; i ++){thatObj [EXPORTED_SYMBOLS [i]] = eval(EXPORTED_SYMBOLS [i]);}
-})(); //可以在这里放置一个对象参数
diff --git a/files/zh-cn/mozilla/add-ons/code_snippets/queryselector/index.html b/files/zh-cn/mozilla/add-ons/code_snippets/queryselector/index.html deleted file mode 100644 index 364909681f..0000000000 --- a/files/zh-cn/mozilla/add-ons/code_snippets/queryselector/index.html +++ /dev/null @@ -1,114 +0,0 @@ ---- -title: QuerySelector -slug: Mozilla/Add-ons/Code_snippets/QuerySelector -tags: - - $ - - $$ - - querySelector -translation_of: Archive/Add-ons/Code_snippets/QuerySelector ---- -

 {{ fx_minversion_header(3.5) }}

- -

沿着其他框架,如jQuery或Prototype, 缩短“querySelector”的名称可以很方便:

- -
    HTMLDocument.prototype.$ = function (selector) {
-        // Only for HTML
-        return this.querySelector(selector);
-    };
-    $(`div`);
-    HTMLDocument.prototype.$$ = function (selector) {
-        // Only for HTML
-        return this.querySelectorAll(selector);
-    };
-    $$(`div`);
- -
function $ (selector, el) {
-     if (!el) {el = document;}
-     return el.querySelector(selector);
-}
-function $$ (selector, el) {
-     if (!el) {el = document;}
-     return el.querySelectorAll(selector);
-     // Note: the returned object is a NodeList.
-     // If you'd like to convert it to a Array for convenience, use this instead:
-     // return Array.prototype.slice.call(el.querySelectorAll(selector));
-}
-alert($('#myID').id);
-
- -

(请注意,在使用火狐浏览器控制台时,上述功能可自动使用.)

- -

 XUL 甚至 XML可以很简单的支持(有以下两种替代方法,添加ChromeWindow.prototype 或者 Window.prototype,访问 this.document.querySelector, 或者根据jQuery 风格的链接,即在每个原型的$()方法中返回的‘this'

- -
HTMLDocument.prototype.$ = function (selector) { // 只用于HTML
-    return this.querySelector(selector);
-};
-
-Example:
-
-<h1>Test!</h1>
-<script>
-HTMLDocument.prototype.$ = function (selector) {
-    return this.querySelector(selector);
-};
-alert(document.$('h1')); // [object HTMLHeadingElement]
-</script>
-
- -
XULDocument.prototype.$ = function (selector) { // 只用于XUL
-    return this.querySelector(selector);
-};
-
-Example:
-
-<label value="Test!"/>
-<script type="text/javascript"><![CDATA[
-XULDocument.prototype.$ = function (selector) { // 只用于XUL
-    return this.querySelector(selector);
-};
-
-alert(document.$('label')); // [object XULElement]
-]]></script>
-
- -
Document.prototype.$ = function (selector) { // 只用于XML
-    return this.querySelector(selector);
-};
-var foo = document.implementation.createDocument('someNS', 'foo', null); // Create an XML document <foo xmlns="someNS"/>
-var bar = foo.createElementNS('someNS', 'bar'); // add <bar xmlns="someNS"/>
-foo.documentElement.appendChild(bar);
-alert(foo.$('bar').nodeName); // gives 'bar'
-
- -
Element.prototype.$ = function (selector) { // 可用于HTML,XUL,XML
-    return this.querySelector(selector);
-};
-
-HTML 例子:
-<h1><a>Test!<a/></h1>
-<script>
-Element.prototype.$ = function (selector) {
-    return this.querySelector(selector);
-};
-alert(document.getElementsByTagName('h1')[0].$('a').nodeName); // 'A'
-
-XUL 例子:
-<hbox><vbox/></hbox>
-<script type="text/javascript"><![CDATA[
-Element.prototype.$ = function (selector) {
-    return this.querySelector(selector);
-};
-var XULNS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
-alert(document.getElementsByTagNameNS(XULNS, 'hbox')[0].$('vbox').nodeName); // vbox
-]]></script>
-
-XML 例子:
-<foo xmlns="someNS"><bar/></foo> in document earlier
-var foo = document.getElementsByTagNameNS('someNS', 'foo')[0];
-alert(foo.$('bar'));
-
-
- -

注意在XML中,  # 'id'选择器将不能体现为'id'属性(因此一个这样名字的属性不一定是XML的ID,尽管他在HTML 和XUL中是这样的), 也不会对 xml:id 起作用.

- -

然而,它将工作于指向没有无前缀属性选择器 (例如'id',但是不是 xml:id: http://www.w3.org/TR/selectors-api/#resolving) (即使 CSS3 支持命名空间属性选择器: http://www.w3.org/TR/css3-selectors/#attrnmsp 以及可能将xml:id 当作 #: http://www.w3.org/TR/css3-selectors/#id-selectors ).

diff --git a/files/zh-cn/mozilla/add-ons/code_snippets/timers/index.html b/files/zh-cn/mozilla/add-ons/code_snippets/timers/index.html deleted file mode 100644 index f15f127f61..0000000000 --- a/files/zh-cn/mozilla/add-ons/code_snippets/timers/index.html +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: JavaScript timers -slug: Mozilla/Add-ons/Code_snippets/Timers -translation_of: Archive/Add-ons/Code_snippets/Timers ---- -

{{LegacyAddonsNotice}}

- -

 

- -

JavaScript的代码块通常情况下是顺序执行的。不过有几个JavaScript内置函数(计时器),能够让我们推迟任意指令的执行:

- - - -

The setTimeout() function is commonly used if you wish to have your function called once after the specified delay. The setInterval() function is commonly used to set a delay for functions that are executed again and again, such as animations. The setImmediate() function can be used instead of the setTimeout(fn, 0) method to execute heavy operations in IE. The requestAnimationFrame() function tells the browser that you wish to perform an animation and requests that the browser schedule a repaint of the window for the next animation frame.

- -

Documentation

- -
-
{{domxref("window.setTimeout","setTimeout()")}}
-
Calls a function or executes a code snippet after specified delay.
-
{{domxref("window.setInterval","setInterval()")}}
-
Calls a function or executes a code snippet repeatedly, with a fixed time delay between each call to that function.
-
{{domxref("window.setImmediate","setImmediate()")}}
-
Calls a function immediately after the browser has completed other operations, such as events and display updates.
-
{{domxref("window.clearTimeout","clearTimeout()")}}
-
Clears the delay set by setTimeout().
-
{{domxref("window.clearInterval","clearInterval()")}}
-
Cancels repeated action which was set up using setInterval().
-
{{domxref("window.clearImmediate","clearImmediate()")}}
-
Cancels the immediate actions, just like {{domxref("window.clearTimeout","clearTimeout()")}} for {{domxref("window.setTimeout","setTimeout()")}}.
-
Using JavaScript timers within animations (Javascript Daemons Management)
-
In Computer science a daemon is a task that runs as a background process, rather than being under the direct control of an interactive user. In JavaScript programming language, all daemons are processes created by JavaScript timers or by a {{domxref("Worker")}} instantiation. Here are some code snippets which simplify and abstract the management of daemons.
-
{{domxref("window.requestAnimationFrame","requestAnimationFrame()")}}
-
requestAnimationFrame() tells the browser that you wish to perform an animation and requests that the browser schedule a repaint of the window for the next animation frame. The method takes as an argument a callback to be invoked before the repaint.
-
{{domxref("performance.now","performance.now()")}}
-
-

performance.now() returns a timestamp, measured in milliseconds, accurate to one thousandth of a millisecond. This timestamp is equal to the number of milliseconds since the navigationStart attribute of the performance.timing interface.

-
-
Date.now()
-
Date.now() returns the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC.
-
Using JavaScript timers within workers
-
Workers can use timeouts and intervals just like the main thread can. This can be useful, for example, if you want to have your worker thread run code periodically instead of nonstop.
-
Functions available to workers
-
In addition to the standard JavaScript set of functions (such as String, Array, Object, JSON etc), there are a variety of functions available from the DOM to workers. This article provides a list of those.
-
Basic animations
-
Since we're using script to control canvas elements it's also very easy to make (interactive) animations. Unfortunately the canvas element was never designed to be used in this way (unlike Flash) so there are limitations.
-
Timer.jsm
-
The Timer.jsm JavaScript code module contains pure-JavaScript implementations of setTimeout and clearTimeout that are compatible with the DOM window functions, but that can be used by code that does not have access to a DOM window (for example, JavaScript code modules or content frame scripts).
-
- -

See also

- - - -

<embed height="0" id="xunlei_com_thunder_helper_plugin_d462f475-c18e-46be-bd10-327458d045bd" type="application/thunder_download_plugin" width="0">

diff --git a/files/zh-cn/mozilla/add-ons/creating_custom_firefox_extensions_with_the_mozilla_build_system/index.html b/files/zh-cn/mozilla/add-ons/creating_custom_firefox_extensions_with_the_mozilla_build_system/index.html deleted file mode 100644 index 617d86487c..0000000000 --- a/files/zh-cn/mozilla/add-ons/creating_custom_firefox_extensions_with_the_mozilla_build_system/index.html +++ /dev/null @@ -1,470 +0,0 @@ ---- -title: Creating Custom Firefox Extensions with the Mozilla Build System -slug: >- - Mozilla/Add-ons/Creating_Custom_Firefox_Extensions_with_the_Mozilla_Build_System -translation_of: >- - Archive/Add-ons/Creating_Custom_Firefox_Extensions_with_the_Mozilla_Build_System ---- -
- Note: All instructions in this article apply to the Mozilla 1.8 branch only (i.e. Firefox 1.5). I'll try to keep it up-to-date as the trunk changes, but you certainly should not assume that this will work with the 1.7 branch (i.e. Firefox 1.0) or older.
-

There is a wealth of material on creating extensions for Firefox. All of these documents currently assume, however, that you are developing your extension using XUL and JavaScript only. For complex extensions, it may be necessary to create components in C++ that provide additional functionality. Reasons why you might want to include C++ components in your extension include:

-

有大量如何创建扩展的资料, 但是这些文档都假定仅仅使用XUL和Javascript开发扩展. 对于复杂的扩展, 可能需要C++开发相关的功能代码. 下列原因可能使你想要在扩展中包括C++组件(Components):

- -

This article describes how to set up the development environment for a large, complex Firefox extension with any or all of the above-mentioned requirements. The process of garnering this information has been somewhat painful due to the lack of published information on this topic, but has been assisted by the contributions of various members of the Mozilla development community, who have shown extraordinary patience in fielding ignorant newbie questions. I can’t stress enough that I’m far from a Mozilla expert, though I’m getting better. There may be much in this document that is inaccurate, misleading or just plain wrong. In fact, one of my goals in writing this is to fine-tune these instructions until they constitute a definite guide for hardcore hackers who want to extend the Firefox platform. If you’re one of the many people who know more about this than I do, your help in improving this article would be greatly appreciated.

-

I should also stress that you do not have to build Mozilla or use the Mozilla build system if you want to create C++ components for Mozilla. If you are just looking to create an XPCOM component or two, this is probably overkill, and you might want to take a look at this guide instead. On the other hand, if you are an experienced developer or team, and you know that you are going to build a large, complex extension, you would do well to consider the approach described in this article.

-

One final note: I’ve only tried these techniques inside Firefox, but they’ll probably work more or less unchanged on other Gecko-based platforms like Thunderbird or Seamonkey. If someone can confirm this and/or provide guidelines for what’s different, I’ll update the article to incorporate this information.

-

Bambi Meets Mozilla(小鹿斑比遇见Mozilla)

-

None of this is for the faint of heart. In particular, the initial step involves building Mozilla, which is a huge - nay, gargantuan! - project. Many intelligent developers have been driven to the brink of insanity trying to build it for the first time. If you're not an experienced C++ developer, I wouldn’t even bother. Stick to JavaScript.

-

(小鹿斑比小时候很胆小)其实这些并不适合胆小者. 尤其是, 第一步编译Mozilla, 那是庞大的 -- 非常非常巨大的 -- 项目. 在初次编译Mozilla时, 许多聪明的开发者都快被逼疯了. 如果你不是资深的C++开发者, 就别烦恼了, 继续玩Javascript.

-

On Windows Platforms

-

The first time I built Mozilla I used this guide. I can’t even remember why anymore, but I got stuck in a number of places, and the whole affair ended up taking far longer than I originally expected. Much furniture was smashed, much hair torn out by the roots. Here’s a comprehensive looking guide that’s gotten good reviews. Follow every step methodically and you’ll probably be alright. Focus on the fact that once you get the build working, it’ll probably work effortlessly from then on. Maybe.

-

On Other Platforms

-

On other platforms, namely Linux and MacOS, the process is much easier. All the tools for building are available built-in, and therefore all you have to do is run some commands in the terminal. You can find full instructions for almost any OS here.

-

Structuring Your Project(构造您的项目)

-

Mozilla includes a number of complex extensions that are integrated into its build process. It has thus been necessary to solve all of the issues involved in creating and registering XPCOM components, building JAR files and manifests, installing the lot into the Firefox extensions/ directory and so forth. So it behooves us to piggyback on this infrastructure to build our extension.

-

First of all, think of a catchy name for your extension and create a directory with that name under the /mozilla/extensions/ directory. Use only lowercase letters. You should see a bunch of other directories (inspector/, reporter/ and so forth) at the same level in the build tree.

-

Note that before actually building anything, the Mozilla build system invokes a configuration process that generates the actual makefiles used for the build from makefile templates called Makefile.in. The actual makefiles tend to be very similar or identical to the templates, but the extra flexibility gained from having the makefiles generated dynamically is one of the things that makes the build system so powerful.

-

Anatomy of a Simple C++ Extension(分析一个简单的C++扩展)

-

We assume that you are using C++ to write XPCOM components that can be used either from other C++ components or from JavaScript. The process of creating a component is actually relatively straightforward when the Mozilla build system is used.

-

In the simplest case, a component will consist of a single main directory with two subdirectories, public/ and src/. The main directory and each subdirectory must contain a Makefile.in (from now on I’ll just refer to this file as a makefile although we know that it is actually used to generate the real makefile). This makefile says two things. First of all, it lists the subdirectories that make up the extension, so the build system knows where to look for additional makefiles. Secondly, it instructs the build system to create a new extension, rather than copying the components directly into Firefox’s binary directory. The main advantage of using an extension is that it is easy to package everything up and install it on another machine.

-

So here’s your basic, plain-vanilla top-level makefile (Makefile.in in the main extension directory):

-
DEPTH		= ../..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-MODULE = myextension
-
-DIRS		= public src
-
-XPI_NAME		= myextension
-INSTALL_EXTENSION_ID	= myextension@mycompany.com
-XPI_PKGNAME		= myextension
-
-DIST_FILES = install.rdf
-
-include $(topsrcdir)/config/rules.mk
-
-

A detailed description of the make process, describing the key features of this makefile, can be found here. MODULE and XPI_NAME are both set to the name of your extension; they should be repeated in all project makefiles so that all of the files land in the same place in the XPI staging area (see below). INSTALL_EXTENSION_ID is the unique ID of your extension. This can be a GUID, but the format shown above is prettier and, let’s face it, a lot easier to remember. You don’t have to provide an XPI_PKGNAME, but if you do an XPI file, suitable for distribution, is automatically created in the root of the XPI staging area (/mozilla/$(MOZ_OBJDIR)/dist/xpi-stage/).

-

Every extension must include an install.rdf file that tells Firefox how to install it. This file should be located in the main extension directory and look something like this:

-
<?xml version="1.0"?>
-
-<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
-  <Description about="urn:mozilla:install-manifest">
-    <em:id>myextension@mycompany.com</em:id>
-    <em:version>0.1</em:version>
-
-    <em:targetApplication>
-      <!-- Firefox -->
-      <Description>
-        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
-        <em:minVersion>1.0+</em:minVersion>
-        <em:maxVersion>1.0+</em:maxVersion>
-      </Description>
-    </em:targetApplication>
-
-    <!-- front-end metadata -->
-    <em:name>My First Extension</em:name>
-    <em:description>Just an example.</em:description>
-    <em:creator>allpeers.com</em:creator>
-    <em:homepageURL>http://www.allpeers.com/blog/</em:homepageURL>
-  </Description>
-</RDF>
-
-

There's a detailed description of the format of the install.rdf file. Use the DIST_FILES variable in the makefile to tell make to copy the file into the extension directory and (optional) XPI file.

-

Public Interfaces(公共接口)

-

The public/ directory contains any interfaces that need to be accessed by other modules. These can be IDL files describing XPCOM interfaces, which are used to generate normal C++ header files for inclusion in your source files. They can also be normal C++ header files that are to be used directly by other modules. The easiest way to accomplish the latter is to use inline implementations for all methods so you don’t have any additional linking dependencies. Otherwise you will have to link statically to your module if you use these public headers in other modules. Personally I would discourage this practice (among other things, static linking means the same code gets loaded more than once into memory, and the code won’t be available from JavaScript or other non-C++ languages) and encourage the use of XPCOM wherever possible.

-

The makefile in the public/ directory should follow this model:

-
DEPTH		= ../../..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-MODULE		= myextension
-XPIDL_MODULE	= myextension
-
-XPI_NAME = myextension
-
-EXPORTS = \
-		myHeader.h \
-		$(NULL)
-
-XPIDLSRCS	= \
-		myIFirstComponent.idl \
-		myISecondComponent.idl \
-		$(NULL)
-
-include $(topsrcdir)/config/rules.mk
-
-

XPIDL_MODULE is the name of the generated XPT file that contains type information about your IDL interfaces. If you have multiple modules, make absolutely sure that you use a different value for XPIDL_MODULE for each one. Otherwise the first module’s XPT file will be overwritten by the second and you’ll get NS_ERROR_XPC_BAD_IID errors when you try to access its IDL interfaces from your code. The files under EXPORTS are copied directly to the /mozilla/$(MOZ_OBJDIR)/dist/include/myextension/ directory and are thus accessible from other modules (the value of MOZ_OBJDIR is defined in /mozilla/.mozconfig). XPIDLSRCS are run through the IDL processor, and the generated C++ headers are copied into the same include directory. In addition, an XPT (type library) file is generated and placed in the components/ subdirectory of your extension.

-

Source Files(源文件)

-

Now it’s time to create the makefile and source files in the src/ subdirectory. If you're implementing interfaces that you've described using IDL, the easiest way to do this is to leave the src/ directory empty and run make on the public/ directory only; this will be explained shortly.

-

Then open the generated header file for your interface from /mozilla/$(MOZ_OBJDIR)/dist/include/myextension/. It contains stubs for the component .H and .CPP files that you can copy and paste into your implementation files. All you have to do is fill in the implementation stubs in the C++ file and you’re good to go.

-

Here’s an example of the makefile you need to place into your src directory:

-
DEPTH		= ../../..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-IS_COMPONENT = 1
-MODULE = myextension
-LIBRARY_NAME =  myExtension
-USE_STATIC_LIBS = 1
-
-XPI_NAME = myextension
-
-REQUIRES	= xpcom \
-		  string \
-		  $(NULL)
-
-CPPSRCS		= \
-		  myFirstComponent.cpp \
-		  mySecondComponent.cpp \
-		  myExtension.cpp \
-		  $(NULL)
-
-include $(topsrcdir)/config/rules.mk
-
-EXTRA_DSO_LDOPTS += \
-  $(XPCOM_GLUE_LDOPTS) \
-  $(NSPR_LIBS) \
-  $(NULL)
-
-# NOTE: If you are coding against the 1.8.0 branch (not 1.8 branch or trunk), the
-# above line won't work, due to linker flag issues. Use the following
-# variables instead:
-#
-# EXTRA_DSO_LDOPTS += \
-#   $(MOZ_COMPONENT_LIBS) \
-#   $(NULL)
-#
-# Unfortunately, using MOZ_COMPONENT_LIBS links against xpcom_core, which means
-# your components will not work in future versions of Firefox.
-
-

The REQUIRES section tells make which modules your components uses. This causes the relevant subdirectories of /mozilla/$(MOZ_OBJDIR)/dist/include/ to be added to the C++ compiler's include path. If you’re including Mozilla headers and the compiler isn’t finding them, it could well mean that you haven’t listed all of the necessary modules here. CPPSRCS lists the source files that need to be built.

-

In this example, the first two files contain the implementation of the extension’s two components. The final file, myExtension.cpp, contains the code necessary to register these components, as described in the next section.

-

Registering Your Components(注册组件)

-

In order to use your components from other C++ modules and JavaScript, you first have to register them. To do this, your extension needs to implement a class that exposes the nsIModule interface, which has methods for accessing the components defined in a module. Luckily, this can be accomplished through the use of a few simple macros, so you don’t have to concern yourself with the messy details of what’s happening under the hood.

-

The first step is to define a CID, contract ID and class name for each of your components. Place the following code (adapting the #defines accordingly) into the header of each component that you want to be able to instantiate using the component manager:

-
// {00000000-0000-0000-0000-000000000000}
-#define MYFIRSTCOMPONENT_CID \
-	{ 0x00000000, 0x0000, 0x0000, \
-	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
-
-#define MYFIRSTCOMPONENT_CONTRACTID	"@mycompany.com/myfirst;1"
-#define MYFIRSTCOMPONENT_CLASSNAME	"My First Component"
-
-

Obviously you need to fill in the CID with a real GUID. Under Windows, this can be generated using guidgen.exe. Unix people can use uuidgen (comes standard with most unixes and Linux distros).

-

Now create the myExtension.cpp file like so:

-
#include "nsXPCOM.h"
-
-#include "nsIGenericFactory.h"
-
-/**
- * Components to be registered
- */
-#include "myFirstComponent.h"
-#include "mySecondComponent.h"
-
-NS_GENERIC_FACTORY_CONSTRUCTOR(myFirstComponent)
-NS_GENERIC_FACTORY_CONSTRUCTOR(mySecondComponent)
-
-//----------------------------------------------------------
-
-static const nsModuleComponentInfo components[] =
-{
-	{
-		MYFIRSTCOMPONENT_CLASSNAME,
-		MYFIRSTCOMPONENT_CID,
-		MYFIRSTCOMPONENT_CONTRACTID,
-		myFirstComponentConstructor
-	},
-	{
-		MYSECONDCOMPONENT_CLASSNAME,
-		MYSECONDCOMPONENT_CID,
-		MYSECONDCOMPONENT_CONTRACTID,
-		mySecondComponentConstructor
-	},
-};
-
-NS_IMPL_NSGETMODULE(MyExtension, components)
-
-

The NS_IMPL_NSGETMODULE macro creates the appropriate module object providing access to all of the components listed in the nsModuleComponentInfo array.

-

Building It(编译扩展)

-

As mentioned above, you’ll probably want to build your extension immediately after creating your IDL files in order to generate the C++ stubs for your component implementations. I’m assuming that you’ve already built Firefox successfully. If not, return immediately to the beginning of this article and don’t come back til you have a functioning firefox.exe. Do not pass go. Do not collect $200.

-

Still here? Okay, now we have to modify your .mozconfig (in the /mozilla/ root directory) so that your extension is built along with Mozilla. Add the following line at the end of the file:

-
ac_add_options --enable-extensions=default,myextension
-
-

Now launch make from the Mozilla root:

-
make -f client.mk build
-
-

Even if you have an up-to-date Firefox build, you’ll have to wait a while for make to recurse over the entire Mozilla source tree looking for new stuff (on my machine, which is pretty fast, this takes a good 10-15 minutes). Eventually it will reach your extension and generate a bunch of stuff under /mozilla/$(MOZ_OBJDIR)/:

- -

A lot of this stuff won’t get created on this first pass since make will gag when it doesn’t find the source files for your components. Don’t worry about this; all you need are the generated header files that contain the C++ implementation stubs. Go back and flesh out the C++ implementation of your components so that the build can complete next time. Remember that you should never, ever modify any of these generated files. Always modify the files used to generate them and rerun make. There might be exceptions to this rule, but if you’re changing the generated files directly, you’re probably doing something wrong.

-

The process of walking the entire Mozilla tree takes a long time. If you already have a Mozilla build, you can avoid this by creating a makefile for your extension directly. Go to the root of your $(MOZ_OBJDIR) and (from a bash-compatible shell) enter:

-
../build/autoconf/make-makefile extensions/myextension
-
-

If your $(MOZ_OBJDIR) is located outside your $(TOPSRCDIR), you'll need to do:

-
$(TOPSRCDIR)/build/autoconf/make-makefile -t $(TOPSRCDIR) extensions/myextension
-
-

in order for the script to know where your source is (it'll use the extension path you gave it relative to the current dir to figure out where you want your makefiles to go).

-

This will generate the proper makefile for your extension. Whether you build the whole Mozilla tree or take this shortcut, you can build from now on by going to /mozilla/$(MOZ_OBJDIR)/extensions/myextension/ and typing "make" on the command line. It should build your component without bothering with the rest of Mozilla. If everything works out, you’ll see your XPI file in the XPI staging area. You’ll also see the "exploded" version of the XPI (i.e. the unzipped directory structure) underneath /mozilla/$(MOZ_OBJDIR)/dist/bin/extensions. (If something goes wrong, figure out what, fix it and then come back here and add it to this article.)

-

To make sure that the build really finished, launch Firefox and check that your extension is listed when you select Tools/Extensions. If you are using Firefox as your regular browser (and if you’re not, why not!?), you might be annoyed by the fact that you have to close regular Firefox before running your custom-built version. If so, try setting the MOZ_NO_REMOTE environment variable to "1" before running the development version of Firefox. You’ll also need to use a different profile for your development version:

-
firefox -P development
-
-

Where development is replaced with the name of the extra profile you’ve created. This will let you run both versions of Firefox simultaneously, saving you oodles of time over the course of the build/test cycle.

-

No Place Like Chrome

-

Yippee-ki-yay! Now you have an extension that does, well, absolutely nothing. It’s time to do something with those groovy components that you’ve implemented and registered. The simplest way to do this is to write some JavaScript and XUL code. At this point, it would be very helpful to have a bit of experience writing "regular" extensions (i.e. without using custom C++ components). If you’ve never done this, I strongly recommend that you think of a cool idea for something simple that you’ve always wanted to tweak in Firefox and write it. Just displaying a new menu item that opens a "Hello, World!" dialog box would be already be a great exercise to get warmed up with.

-

Assuming you know how to write XUL/JavaScript extensions, you’re aware that the most important stuff goes in the chrome/ directory of your extension. Well, the fact that you’re also using C++ components doesn’t change that one whit. So now you need to create the normal content/, locale/ and skin/ directories in which to place your chrome files. Personally I like placing these directly under the root directory of my module, but I don’t suppose it makes any difference if you prefer putting them under a chrome/ subdirectory or whatever. Let freedom reign!

-

Once you’ve written the necessary chrome files (for instance, an overlay that adds a menu item to instantiate and use one of your components), you need to package them up as part of your extension. This is accomplished through the use of a JAR Manifest. For our simple extension example, this file might look something like this:

-
myextension.jar:
-%  content myextension %content/
-%  locale myextension en-US %locale/en-US/
-%  skin myextension classic/1.0 %skin/classic/
-%  overlay chrome://browser/content/browser.xul chrome://myextension/content/MyExtensionOverlay.xul
-	content/MyExtensionOverlay.js		(content/MyExtensionOverlay.js)
-	content/MyExtensionOverlay.xul		(content/MyExtensionOverlay.xul)
-	locale/en-US/MyExtension.dtd		(locale/en-US/MyExtension.dtd)
-	locale/en-US/MyExtension.properties	(locale/en-US/MyExtension.properties)
-	skin/classic/MyExtension.css		(skin/classic/MyExtension.css)
-
-

Place this code in a file called jar.mn in the root directory of your extension, making sure that the paths in parentheses point to actual files (when interpreted relative to the root directory). You also have to make one small change to the makefile in the same directory, adding the following line:

-
USE_EXTENSION_MANIFEST = 1
-
-

This tells make to create a single manifest file called chrome.manifest instead of creating separate manifests with goofy names for each package.

-

Now launch make again, and you should see a chrome subdirectory appear in your extension (/mozilla/$(MOZ_OBJDIR)/dist/bin/extensions/myextension@mycompany.com/). Note that the chrome directory contains a JAR (i.e. ZIP) file with all the chrome files listed in jar.mn as well as a complete directory structure mirroring that of the JAR file. The directory structure, however, is empty. Why? I don’t know. Don’t worry about this, the files in the JAR are the ones that are actually used.

-

Keeping it Complex

-

If you’re developing a really complex extension with lots of XPCOM components, you’ll probably want to divide your code up into smaller modules.

-
Kinda, Sorta Complex Extensions
-

For a moderately complex extension, it’s probably enough just to subdivide the code into a single level of modules. Let’s assume that you have a base/ module that defines a bunch of basic XPCOM components and an advanced/ module that defines some chrome as well as other components that use the basic components. Your complete directory structure will look something like this:

- -

Other than that, nothing really changes. The makefiles in the base/ and advanced/ directories should look more or less like your original root makefile, remembering to change the DEPTH variable to account for the fact that they’ve moved a level further away from the Mozilla root. You also need to remove the DIST_FILES variable since that’s going to be in the top-level makefile. Every makefile that generates anything should define the XPI_NAME variable to make sure generated files go into your extension and not into the global components/ directory. In fact, just define this in every makefile to be safe. You can use the same MODULE in both base/ and advanced/ so that all the generated include files go into the same directory, but make sure that you don’t use the same XPIDL_MODULE in the two public/ directories or one of the component type libraries (i.e. XPT files) will overwrite the other one and all hell will break loose.

-

Each module must also have a different value for the LIBRARY_NAME variable. This is the name of the generated dynamic library, so if we call the libraries "myBase" and "myAdvanced", we’ll end up with myBase.dll and myAdvanced.dll (on Windows, at least). And each of these modules is going to have a separate C++ file for registering components. So there will be two files that look like myExtension.cpp in the original example, say Base.cpp and Advanced.cpp. Finally, each module will obviously have its own jar.mn, though they can reference the same JAR filename and package name if you want all the chrome files to be organized in a single JAR file and package. The only file that really stays put is install.rdf, which still exists once and only once in the extension root directory.

-

As for the top-level makefile, it will now look like this:

-
DEPTH		= ../..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-MODULE = myextension
-
-DIRS		= base advanced
-
-XPI_NAME               = myextension
-INSTALL_EXTENSION_ID   = myextension@mycompany.com
-XPI_PKGNAME		= myextension
-
-DIST_FILES = install.rdf
-
-include $(topsrcdir)/config/rules.mk
-
-
Seriously Complex Extensions
-

At some point, even a single module may grow to the point where you want to divide it further into submodules. The difference between having separate modules and having a single module with separate submodules is that the submodules all share the same file for registering components (the famous myExtension.cpp file), and when compiled they create a single dynamic library. The decision to split a module into submodules is all about code organization; it doesn’t really affect the final product at all.

-

To split a module into submodules, first create a subdirectory for each submodule. Then create an additional directory called build/. Each submodule will be configured to create a static library, and the build/ directory will pull these libraries together to create a single dynamic component library. Confused? Here’s an example, showing just the advanced/ subbranch of the myextension/ directory:

- -

As you can see, we’ve split advanced/ into two submodules: intricate/ and multifarious/, and we’ve added an additional build/ subdirectory. We’ve left the chrome directories directly under advanced/, since they aren’t tied to any specific submodule. This means that jar.mn will stay in the same place.

-

The intricate/ and multifarious/ makefiles will look a lot like the original advanced/ makefile, but we’ll need to tweak them a bit. As always, we have to adjust the DEPTH variable since the makefiles are deeper in the directory structure. And we should change the LIBRARY_NAME to indicate that we’re generating a static library for each submodule. By convention the "_s" suffix is used for this purpose. So let’s call them "myIntricate_s" and "myMultifarious_s". Finally, we define the variable FORCE_STATIC_LIB, resulting in a makefile that starts something like this:

-
DEPTH		= ../../../../..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-MODULE = myextension
-LIBRARY_NAME = myIntricate_s
-FORCE_STATIC_LIB = 1
-USE_STATIC_LIBS = 1
-
-XPI_NAME = myextension
-
-...more stuff here...
-
-

The build makefile pulls together the static libraries generated by the submodules and creates a single (dynamic) component library:

-
DEPTH		= ../../../..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-IS_COMPONENT = 1
-MODULE = myextension
-LIBRARY_NAME = myAdvanced
-USE_STATIC_LIBS = 1
-
-XPI_NAME = myextension
-
-DEFINES += XPCOM_GLUE
-
-SHARED_LIBRARY_LIBS = \
-		$(DIST)/lib/$(LIB_PREFIX)myIntricate_s.$(LIB_SUFFIX) \
-		$(DIST)/lib/$(LIB_PREFIX)myMultifarious_s.$(LIB_SUFFIX) \
-                $(DIST)/lib/$(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \
-                $(DIST)/lib/$(LIB_PREFIX)xpcom.$(LIB_SUFFIX) \
-                $(DIST)/lib/$(LIB_PREFIX)nspr4.$(LIB_SUFFIX) \
-                $(DIST)/lib/$(LIB_PREFIX)plds4.$(LIB_SUFFIX) \
-                $(DIST)/lib/$(LIB_PREFIX)plc4.$(LIB_SUFFIX) \
-		$(NULL)
-
-REQUIRES	= \
-		xpcom \
-		string \
-		$(NULL)
-
-CPPSRCS		= \
-		Advanced.cpp \
-		$(NULL)
-
-include $(topsrcdir)/config/rules.mk
-
-LOCAL_INCLUDES += \
-        -I$(srcdir)/../intricate/src \
-        -I$(srcdir)/../multifarious/src \
-        $(NULL)
-
-

The makefile in the advanced/ directory should list the intricate/, multifarious/ and build/ directories in its DIRS variable. Make sure that build/ comes last since it can’t create the component library until the other makefiles have completed.

-

Other Topics

-

Adding Data Files to Your Extensions

-

In some cases, you may wish to include additional files in your extension that don’t belong in the chrome/ subdirectory. Examples might be database files or XML schemas. This can be achieved by adding a custom step to your makefile that copies the files from the source tree into the extension’s target directory.

-
Copying Data Files Into Target Directory
-

Let’s say that you have some data files containing statistical information that you want to include in your extension and make available to your components. You’ve placed these files, which have the extension .TXT, into a stats/ subdirectory under your extension directory in the source tree. The following makefile rule can be used to copy these files into the final target directory of the extension:

-
export::
-	if test ! -d $(FINAL_TARGET)/stats; then \
-		$(NSINSTALL) -D $(FINAL_TARGET)/stats; \
-	fi
-	$(INSTALL) $(srcdir)/*.txt $(FINAL_TARGET)/stats
-
-
Accessing Data Files From Components
-

The trick to accessing your data files is to figure out where the home directory of your extension is. Rumor has it that at some future date, this will possible through the nsIExtensionManager interface or something similar. In the meantime, there is a simple and reliable hack that can be used to achieve this. In the implementation of any JavaScript XPCOM component, there is a special __LOCATION__ (two leading and two trailing underscores) symbol that points to the component’s implementation file. So you can write a simple component which deduces the root directory of your extensions by extrapolating from its location.

-

This article explains how to create an XPCOM component in JavaScript. You’ll need an IDL file for an interface that looks something like this:

-
interface myILocation : nsISupports
-{
-    readonly attribute nsIFile locationFile;
-};
-
-

Place the IDL file in the public/ directory of your project or subproject. In the src/ directory, place the JavaScript file that implements the component. The component implementation will include the methods for retrieving the path or file for the extension’s home directory:

-
myLocation.prototype =
-{
-  QueryInterface: function(iid)
-  {
-    if (iid.equals(nsISupports))
-      return this;
-    if (iid.equals(myILocation))
-      return this;
-
-    Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
-    return null;
-  },
-
-  get locationFile()
-  {
-     return __LOCATION__.parent.parent;
-  }
-}
-
-

This assumes that the component resides in a subdirectory of the extension directory (by convention, this directory is called components/). The parent property of __LOCATION__ returns the components/, and the parent of this is the extension directory.

-

The last step is to modify the makefile of the source directory where you placed your JavaScript file so that it is copied into the appropriate location in the extension:

-
export::
-	$(INSTALL) $(srcdir)/*.js $(FINAL_TARGET)/components
-
-

Now you can instantiate an instance of this component and use the locationFile property to get an nsIFile interface that points to your extension’s home directory.

-

Using Third-Party Libraries

-

For more sophisticated extensions, you may want to integrate third-party libraries that provide specialized functionality for database connectivity, image processing, networking and the like. If you want your extension to run on all Firefox platforms, you will need to have the source code for the library in question, so I assume that this is available.

-

The most convenient approach from the perspective of the development cycle is to create a Mozilla-style makefile for the library. This works well for libraries that have a straightforward make process without extensive configuration. A good example of this is the SQLite library included in the Mozilla build tree at db/sqlite. By adapting the makefile in this way, the library is created as part of the standard Mozilla build process, which eliminates additional build steps. The downside is that you will need to update the modified makefile any time a new version of the library is released.

-

For libraries that have complex configuration processes, use a non-standard compiler or have other special characteristics, it may be unfeasible to create a Mozilla-compliant makefile. In this case, I would recommend placing the entire library distribution inside the project or subproject that uses it. So if library acmelib is used inside the multifarious/ subproject in the above example, it would be placed as a subdirectory underneath that subproject (at the same level as public/ and src/).

-

Of course, this means that you will have to build acmelib manually on all platforms before launching the Mozilla build. But at least you can then refer to include files and import libraries from your component using relative paths.

-

Building for Multiple Platforms

-

TODO

-
-

Original Document Information

- -
-

 

diff --git a/files/zh-cn/mozilla/add-ons/creating_opensearch_plugins_for_firefox/index.html b/files/zh-cn/mozilla/add-ons/creating_opensearch_plugins_for_firefox/index.html deleted file mode 100644 index b03cc689c9..0000000000 --- a/files/zh-cn/mozilla/add-ons/creating_opensearch_plugins_for_firefox/index.html +++ /dev/null @@ -1,159 +0,0 @@ ---- -title: 为 Firefox 创建 OpenSearch 插件 -slug: Mozilla/Add-ons/Creating_OpenSearch_plugins_for_Firefox -translation_of: Web/OpenSearch ---- -

{{ fx_minversion_header("2") }}

-

Firefox 2 支持使用 OpenSearch 格式开发搜索引擎插件. 使用 OpenSearch 格式开发能够在IE 7 以及 Firefox上实现兼容. 这是这种语法被推荐使用的原因.

-

Firefox 也支持不被包括在 OpenSearch格式  中的其它的搜索功能,例如搜索建议(search suggestion)以及 SearchForm 元素. 这篇文章主要关注创建与OpenSearch格式兼容的支持额外的firefox特殊特征的搜索插件.

-

OpenSearch 描述文件也能被如在 Autodiscovery of search plugins  中描述的一样被advertised(道歉这里不知如何翻译) ,并且能够如在 Adding search engines from web pages中所说的进行编程安装.

-

OpenSearch 描述文件

-

遵循以下的模板,你就会发现通过 XML 文件写一个搜索引擎实际上是如此的简单。 粗体字部分需要根据具体你所写的搜索引擎需要来进行定制 。

-
<?xml version="1.0" encoding="UTF-8"?>
-<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"
-                       xmlns:moz="http://www.mozilla.org/2006/browser/search/">
-  <ShortName>engineName</ShortName>
-  <Description>engineDescription</Description>
-  <InputEncoding>inputEncoding</InputEncoding>
-  <Image width="16" height="16" type="image/x-icon">data:image/x-icon;base64,imageData</Image>
-  <Url type="text/html" method="method" template="searchURL">
-    <Param name="paramName1" value="paramValue1"/>
-    ...
-    <Param name="paramNameN" value="paramValueN"/>
-  </Url>
-  <Url type="application/x-suggestions+json" template="suggestionURL"/>
-  <moz:SearchForm>searchFormURL</moz:SearchForm>
-</OpenSearchDescription>
-
-
- ShortName
-
- 对搜索引擎的简称
-
- 限制: 名称仅能包含16个字符以下的纯文本. 名称不能包含HTML标志或其他标志.
-
-
-
- Description
-
- 对于搜索引擎的简单描述
-
- 限制: 描述仅能包含少于1024个字符的纯文本.  名称不能包含HTML标志或其他标志.
-
-
-
- InputEncoding
-
- 向搜索引擎所输内容的字符编码.例如: <InputEncoding>UTF-8</InputEncoding>.
-
-
-
- Image
-
- 使用指向一个图标的URL来代表这个搜索引擎. 可能的话, 应提供16x16大小的"image/x-icon"类型的图像以及一个64x64大小的 "image/jpeg" 或 "image/png"类型的图像. 链接也可以使用 data: URI schemeThe data: URI kitchen在这能找到一个能有效地帮助你构建写在此处的数据的工具. -
<Image height="16" width="16" type="image/x-icon">http://example.com/favicon.ico</Image>
-  OR
-<Image height="16" width="16">data:image/x-icon;base64,AAABAAEAEBAAA ... DAAA=</Image>
-
- Firefox以base64编码的data: URI (搜索插件被保存在 profile中的 "searchplugins" 文件夹) 缓存此图标. 当这完成时, http: URIs 被改变为 data: URIs.
-
-
-
- Url
-
- 描述用来实现搜索请求的一个或多个URL.  method 属性决定使用 GET 还是 POST请求来获取返回的数据. template 属性指定实现搜索请求的 URL.
-
-
- 注意: IE7 不支持 POST 请求.
-
-
-
-
- 这是两种firefox支持的URL类型:
-
- -
-
- 这两种URL任何一种你都能使用 {searchTerms}来替换用户在搜索栏中输入的搜索内容. 其他支持的动态搜索参数可见 OpenSearch 1.1 parameters.
-
-
-
- 对使用搜索建议查询来说,  URL template用来获取JSON格式的建议列表. 若需要知道关于如何在服务器上实现搜索建议支持, 请见 Supporting search suggestions in search plugins.
-
-

Image:SearchSuggestionSample.png

-
-
- Param
-
- 这个参数用来包括那些需要和搜索查询一起被传递的作为键值对的参数. 你能使用{searchTerms}来指代用户输入的搜索条目.
-
-
- 注意: IE7不支持此元素.
-
-
-
-
- SearchForm
-
- 跳往搜索页的 URL. 这使得Firefox能让用户直接浏览目的网站.
-
-
- 注意: 这个元素是firefox限定的, 并不是 OpenSearch 的一部分, 我们在例子中使用 "moz:" XML命名前缀来确保其它的不支持此元素的用户代理能安全地忽略此元素.
-
-
-

自动搜寻搜索插件

-

提供搜索插件的网站能宣传自己以使firefox使用者能容易地下载并安装此插件.

-

要支持自动搜寻 你仅需在 你网页的<head> 中加上一条:

-
<link rel="search" type="application/opensearchdescription+xml" title="searchTitle" href="pluginURL">
-
-

斜体字部分解释如下:

-
-
- searchTitle
-
- 搜索的名称, 如 "Search MDC" or "Yahoo! Search". 这个值应该与你在插件文件中的ShortName相一致.
-
-
-
- pluginURL
-
- 指向 XML搜索插件的URL, 能让浏览者下载插件.
-
-

如果你的网站提供多个插件, 你能为他们每一个都支持自动搜寻功能. 例如:

-
<link rel="search" type="application/opensearchdescription+xml" title="MySite: By Author" href="http://www.mysite.com/mysiteauthor.xml">
-<link rel="search" type="application/opensearchdescription+xml" title="MySite: By Title" href="http://www.mysite.com/mysitetitle.xml">
-
-

这样,你的网站提供的插件就能同时以作者和名称分别作为搜索条目而被搜索.

-

为 OpenSearch 插件支持自动更新

-

{{ fx_minversion_note("3.5", "This section covers a feature introduced in Firefox 3.5.") }}

-

从Firefox 3.5开始, OpenSearch 插件能够自动更新.  要支持这个, 需要包括一个额外的 "application/opensearchdescription+xml"类型Url 元素.  rel属性需要设为 "self" , template 属性需要是指向能自动更新的OpenSearch文档的 URL.

-

例如:

-
<Url type="application/opensearchdescription+xml"
-     rel="self"
-     template="http://www.foo.com/mysearchdescription.xml" />
-
-
- 注意:  addons.mozilla.org (AMO) 不支持 OpenSearch 插件的自动更新. 如果你想将你的插件发布在 AMO上, 你不应该使用自动更新.
-

排错指南

-

如果你的搜索插件有错误, 当在firefox2中添加插件时会出错. 然而,错误信息可能并不是完全有所帮助的, 因此接下来的建议能帮你发现问题.

- -

另外, 搜索插件服务提供了日志机制,这对于插件开发者来说可能能起到一定作用 . 使用 about:config 设定 'browser.search.log' 为 true. 插件被加载后日志信息将显示在火狐的 Error Console 中(Tools->Error Console).

-

参考资料

- -

{{ languages( { "es": "es/Creación_de_plugins_OpenSearch_para_Firefox", "de": "de/OpenSearch_Plugin_für_Firefox_erstellen", "ca": "ca/Creació_de_connectors_OpenSearch_per_al_Firefox", "fr": "fr/Création_de_plugins_OpenSearch_pour_Firefox", "ja": "ja/Creating_OpenSearch_plugins_for_Firefox", "pl": "pl/Tworzenie_wtyczek_OpenSearch_dla_Firefoksa", "pt": "pt/Criando_plugins_OpenSearch_para_o_Firefox" } ) }}

diff --git a/files/zh-cn/mozilla/add-ons/creating_opensearch_plugins_for_firefox_clone/index.html b/files/zh-cn/mozilla/add-ons/creating_opensearch_plugins_for_firefox_clone/index.html deleted file mode 100644 index 5c511cc132..0000000000 --- a/files/zh-cn/mozilla/add-ons/creating_opensearch_plugins_for_firefox_clone/index.html +++ /dev/null @@ -1,175 +0,0 @@ ---- -title: 为 Firefox 创建 OpenSearch 插件 -slug: Mozilla/Add-ons/Creating_OpenSearch_plugins_for_Firefox_clone -tags: - - 定制 - - 搜索 ---- -

{{ fx_minversion_header("2") }}

- -

Firefox 2 支持使用 OpenSearch 格式开发搜索引擎插件. 使用 OpenSearch 格式开发能够在IE 7 以及 Firefox上实现兼容. 这是这种语法被推荐使用的原因.

- -

Firefox 也支持不被包括在 OpenSearch格式  中的其它的搜索功能,例如搜索建议(search suggestion)以及 SearchForm 元素. 这篇文章主要关注创建与OpenSearch格式兼容的支持额外的firefox特殊特征的搜索插件.

- -

OpenSearch 描述文件也能被如在 Autodiscovery of search plugins  中描述的一样被advertised(道歉这里不知如何翻译) ,并且能够如在 Adding search engines from web pages中所说的进行编程安装.

- -

OpenSearch 描述文件

- -

遵循以下的模板,你就会发现通过 XML 文件写一个搜索引擎实际上是如此的简单。 粗体字部分需要根据具体你所写的搜索引擎需要来进行定制 。

- -
<?xml version="1.0" encoding="UTF-8"?>
-<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"
-                       xmlns:moz="http://www.mozilla.org/2006/browser/search/">
-  <ShortName>engineName</ShortName>
-  <Description>engineDescription</Description>
-  <InputEncoding>inputEncoding</InputEncoding>
-  <Image width="16" height="16" type="image/x-icon">data:image/x-icon;base64,imageData</Image>
-  <Url type="text/html" method="method" template="searchURL">
-    <Param name="paramName1" value="paramValue1"/>
-    ...
-    <Param name="paramNameN" value="paramValueN"/>
-  </Url>
-  <Url type="application/x-suggestions+json" template="suggestionURL"/>
-  <moz:SearchForm>searchFormURL</moz:SearchForm>
-</OpenSearchDescription>
- -
-
ShortName
-
对搜索引擎的简称
-
限制: 名称仅能包含16个字符以下的纯文本. 名称不能包含HTML标志或其他标志.
-
- -
-
Description
-
对于搜索引擎的简单描述
-
限制: 描述仅能包含少于1024个字符的纯文本.  名称不能包含HTML标志或其他标志.
-
- -
-
InputEncoding
-
向搜索引擎所输内容的字符编码.例如: <InputEncoding>UTF-8</InputEncoding>.
-
- -
-
Image
-
使用指向一个图标的URL来代表这个搜索引擎. 可能的话, 应提供16x16大小的"image/x-icon"类型的图像以及一个64x64大小的 "image/jpeg" 或 "image/png"类型的图像. 链接也可以使用 data: URI schemeThe data: URI kitchen在这能找到一个能有效地帮助你构建写在此处的数据的工具. -
<Image height="16" width="16" type="image/x-icon">http://example.com/favicon.ico</Image>
-  OR
-<Image height="16" width="16">data:image/x-icon;base64,AAABAAEAEBAAA ... DAAA=</Image>
-
- Firefox以base64编码的data: URI (搜索插件被保存在 profile中的 "searchplugins" 文件夹) 缓存此图标. 当这完成时, http: URIs 被改变为 data: URIs.
-
- -
-
Url
-
描述用来实现搜索请求的一个或多个URL.  method 属性决定使用 GET 还是 POST请求来获取返回的数据. template 属性指定实现搜索请求的 URL.
-
-
注意: IE7 不支持 POST 请求.
-
-
- -
-
这是两种firefox支持的URL类型:
-
- - - -
-
这两种URL任何一种你都能使用 {searchTerms}来替换用户在搜索栏中输入的搜索内容. 其他支持的动态搜索参数可见 OpenSearch 1.1 parameters.
-
- -
-
对使用搜索建议查询来说,  URL template用来获取JSON格式的建议列表. 若需要知道关于如何在服务器上实现搜索建议支持, 请见 Supporting search suggestions in search plugins.
-
- -

Image:SearchSuggestionSample.png

- -
-
Param
-
这个参数用来包括那些需要和搜索查询一起被传递的作为键值对的参数. 你能使用{searchTerms}来指代用户输入的搜索条目.
-
-
注意: IE7不支持此元素.
-
-
- -
-
SearchForm
-
跳往搜索页的 URL. 这使得Firefox能让用户直接浏览目的网站.
-
-
注意: 这个元素是firefox限定的, 并不是 OpenSearch 的一部分, 我们在例子中使用 "moz:" XML命名前缀来确保其它的不支持此元素的用户代理能安全地忽略此元素.
-
-
- -

自动搜寻搜索插件

- -

提供搜索插件的网站能宣传自己以使firefox使用者能容易地下载并安装此插件.

- -

要支持自动搜寻 你仅需在 你网页的<head> 中加上一条:

- -
<link rel="search" type="application/opensearchdescription+xml" title="searchTitle" href="pluginURL">
-
- -

斜体字部分解释如下:

- -
-
searchTitle
-
搜索的名称, 如 "Search MDC" or "Yahoo! Search". 这个值应该与你在插件文件中的ShortName相一致.
-
- -
-
pluginURL
-
指向 XML搜索插件的URL, 能让浏览者下载插件.
-
- -

如果你的网站提供多个插件, 你能为他们每一个都支持自动搜寻功能. 例如:

- -
<link rel="search" type="application/opensearchdescription+xml" title="MySite: By Author" href="http://www.mysite.com/mysiteauthor.xml">
-<link rel="search" type="application/opensearchdescription+xml" title="MySite: By Title" href="http://www.mysite.com/mysitetitle.xml">
-
- -

这样,你的网站提供的插件就能同时以作者和名称分别作为搜索条目而被搜索.

- -

为 OpenSearch 插件支持自动更新

- -

{{ fx_minversion_note("3.5", "This section covers a feature introduced in Firefox 3.5.") }}

- -

从Firefox 3.5开始, OpenSearch 插件能够自动更新.  要支持这个, 需要包括一个额外的 "application/opensearchdescription+xml"类型Url 元素.  rel属性需要设为 "self" , template 属性需要是指向能自动更新的OpenSearch文档的 URL.

- -

例如:

- -
<Url type="application/opensearchdescription+xml"
-     rel="self"
-     template="http://www.foo.com/mysearchdescription.xml" />
-
- -
注意:  addons.mozilla.org (AMO) 不支持 OpenSearch 插件的自动更新. 如果你想将你的插件发布在 AMO上, 你不应该使用自动更新.
- -

排错指南

- -

如果你的搜索插件有错误, 当在firefox2中添加插件时会出错. 然而,错误信息可能并不是完全有所帮助的, 因此接下来的建议能帮你发现问题.

- - - -

另外, 搜索插件服务提供了日志机制,这对于插件开发者来说可能能起到一定作用 . 使用 about:config 设定 'browser.search.log' 为 true. 插件被加载后日志信息将显示在火狐的 Error Console 中(Tools->Error Console).

- -

参考资料

- - - -

{{ languages( { "es": "es/Creación_de_plugins_OpenSearch_para_Firefox", "de": "de/OpenSearch_Plugin_für_Firefox_erstellen", "ca": "ca/Creació_de_connectors_OpenSearch_per_al_Firefox", "fr": "fr/Création_de_plugins_OpenSearch_pour_Firefox", "ja": "ja/Creating_OpenSearch_plugins_for_Firefox", "pl": "pl/Tworzenie_wtyczek_OpenSearch_dla_Firefoksa", "pt": "pt/Criando_plugins_OpenSearch_para_o_Firefox" } ) }}

diff --git a/files/zh-cn/mozilla/add-ons/extension_frequently_asked_questions_move/index.html b/files/zh-cn/mozilla/add-ons/extension_frequently_asked_questions_move/index.html deleted file mode 100644 index 6b9e091642..0000000000 --- a/files/zh-cn/mozilla/add-ons/extension_frequently_asked_questions_move/index.html +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: 扩展的常见问题解答 -slug: Mozilla/Add-ons/Extension_Frequently_Asked_Questions_move -translation_of: Archive/Mozilla/Extension_Frequently_Asked_Questions ---- -

这里是关于扩展开发中最常见问题的解答集锦。其中的绝大多数是关于 FireFox 的,但是大部分能够方便的移植到 SeaMonkey,Thunderbird 或其它 Mozilla 应用上。

-

如果你还不知道怎么开始,可以先看看我们的教程:构建一个扩展或者 MozillaZine 上的新手教程。然后用扩展向导创建一个供开始用的简单扩展。

-

不要忘记先设置好扩展的开发环境

-

调试

-

调试之前先设置扩展的开发环境

-

如果调试的代码很复杂,可能会用到 Venkman JavaScript 调试器。在用 Venkman 调试扩展代码之前需要把 "Debug -> Exclude Browser Files" 选项勾掉。

-

怎样记录代码中的错误?

-

javascript.options.showInConsole 设为 true,这样错误就会被记录在错误控制台中,使得 bug 容易追踪些。

-

怎样显示扩展当前状态?

-

要想显示变量值,调试消息等,可以使用 alert(),dump() ,Components.utils.reportError() 或者控制台服务。当然也可以用 Venkman 调试器。

-

为什么我的脚本不能正确运行?

-

如果你的脚本不能如预期运行,第一个要检查的是错误控制台(参见#)。

-

访问尚未加载完毕的 DOM 也常常是错误的来源。这种错误通常是因为初始化代码被放在程序顶层(即所有函数之外)。通过监听 load 事件延期执行初始化代码可以解决这个问题(load 事件表示窗口已经加载完毕):

-
function exampleBrowserStartup(event)
-{
-  // 初始化代码
-}
-window.addEventListener("load", exampleBrowserStartup, false);
-
-

 

-

不能访问网页的文档(document)对象

-

要从 browser.xul 这个 overlay 中访问当前网页,应当使用 content.document 而不是 document。这是因为 document 表示浏览器窗口自身。更多信息参考 Working with windows in chrome code

-

无法在扩展中使用 XMLHttpRequest

-

使用 XMLHttpRequest 发送接收信息时,一般都需要做跨域(crosss domain)操作。 一般来说跨域很麻烦,但因为在 chrome 窗口内发起请求时,是在安全区域内的,所以请求会被默许。

-

You need to make sure that you are initializing the cross domain XMLHttpRequest from JavaScript code that is referencing a XUL window. If you try and execute the request in relation to the browser content document, as opposed to the "document" of the XUL window, you will receive a Permission Denied error.

-

XML 文件是规范的,但是却出现 XML 解析错误!

-

示例代码

-

得到更多帮助

-

 

-

 

diff --git a/files/zh-cn/mozilla/add-ons/extension_packaging/index.html b/files/zh-cn/mozilla/add-ons/extension_packaging/index.html deleted file mode 100644 index 8057385c7c..0000000000 --- a/files/zh-cn/mozilla/add-ons/extension_packaging/index.html +++ /dev/null @@ -1,38 +0,0 @@ ---- -title: 扩展打包 -slug: Mozilla/Add-ons/Extension_Packaging -tags: - - Extensions - - Toolkit API -translation_of: Archive/Add-ons/Extension_Packaging ---- -

 

-

扩展为一种可安装包的形式,它可以由使用者下载并安装,或者是由外部程序或应用程序提供的预安装包。扩展使用目录结构,此结构提供有chrome,components,和其他文件以扩展XUL程序的功能。

-

每个扩展必须提供一个install.rdf文件,包含关于扩展的元数据,例如唯一的ID,版本,作者,和兼容性信息。

-

扩展文件和install.rdf准备好之后,有几种方法准备扩展以便安装:将扩展目录ZIP打包为用户可安装的XPI(xpinstall)文件,直接将扩展解开到用户程序或设置目录中,或将扩展注册到Windows注册表中。

-

制作扩展XPI

-

一个XPI (XPInstall) 文件就是一个简单的ZIP文件,包括了扩展文件,install.rdf文件在ZIP的根目录中。使用者可以从网站上下载或者从本地安装XPI文件,将其打开或拖拽到扩展管理窗口。

-

XPI文件的MIME类型被Firefox识别为 - - application/x-xpinstall - ,因为大多数HTTP服务器不能够默认设置为将.xpi返回MIME类型。在Apache HTTP服务器上,可以在设置文件或.htaccess中增加以下命令来实现:

-
AddType application/x-xpinstall .xpi
-
-

直接安装扩展文件

-

如果你知道程序的位置(例如,如果你作为应用程序安装者的角色来安装扩展),你可以直接将扩展文件安装到<appdir>/extensions/<extensionID>中。在下次程序启动的时候扩展管理器会自动找到此扩展。

-

当使用此方法的时候你必须核实以确保系统允许扩展目录和文件正确设置。否则,扩展管理器在此扩展下不能够正确运行,或者扩展本身不能正确工作。

-

使用Windows注册表工具注册扩展所在目录

-

外部安装程序(例如Java虚拟机)也许希望将应用程序整合点作为扩展安装,即便是应用程序还没有安装。这可以在Windows中使用注册表来完成。

-

多条目扩展 XPIs

-

在有些情况下也许希望用单独的XPI文件安装多个扩展/主题。一种特殊的扩展XPI称为多条目包,用来解释如何创建此类型的扩展包。(需要Firefox 1.5/XULRunner 1.8。)

-

Toolkit API的官方参考

-

-

diff --git a/files/zh-cn/mozilla/add-ons/install_manifests/index.html b/files/zh-cn/mozilla/add-ons/install_manifests/index.html deleted file mode 100644 index 936ae3fb86..0000000000 --- a/files/zh-cn/mozilla/add-ons/install_manifests/index.html +++ /dev/null @@ -1,363 +0,0 @@ ---- -title: 安装清单 -slug: Mozilla/Add-ons/Install_Manifests -tags: - - bug-840092 - - bug-840092-dup -translation_of: Archive/Add-ons/Install_Manifests ---- -

简介

-

安装清单是一个附加文件,具有Add-on的XUL程序(例如火狐或者雷鸟),用这个文件来确定即将要安装的add-on的安装信息。他包含了add-on的元数据验证、创建者信息、add-on的详细介绍页面地址、版本号、如何更新、兼容性、等等。

-

安装清单的格式是 RDF/XML.

-

这个文件名字必须为 install.rdf 并且必须放在 XPI 文件的根目录。

-

结构

-

安装清单的最基本结构如下:

-
-
<?xml version="1.0"?>
-
-<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
-  <Description about="urn:mozilla:install-manifest">
-    <!-- properties -->
-  </Description>
-</RDF>
-
-
-

有些属性是是必须的,有些是可选的。有些属性只是简单的字符串啥啥啥的,有些属性会很复杂。

-

必要的属性

-

你的清单必须要包含下面的这些属性,不听话的话,你的add-on是不会安装成功滴。

-

id

-

id是一个这样子的东东:

- -
extensionname@example.org
-

后面的这个格式更容易生成和操作。火狐1.5已经检测你的id,确保它是属于第一种格式还是其他格式,并且让那些id格式乱七八糟的add-on不会被安装。

-

例如:

-
<em:id>extensionname@example.org</em:id>
-
-<em:id>{daf44bf7-a45e-4450-979c-91cf07434c3d}</em:id>
-

版本

-

一个标志当前add-on版本的字符串。

-

对于火狐/雷鸟1.0来说,这个格式必须满足这里所说的要求: Extension Versioning, Update and Compatibility. 对于火狐/雷鸟1.5, 看这里:Toolkit version format.

-

示例:

-
<em:version>2.0</em:version>
-
-<em:version>1.0.2</em:version>
-
-<em:version>0.4.1.2005090112</em:version>
-

Firefox 1.5 / XULRunner 1.8 - add-ons that do not use a valid version format will not be installed. The version format is different from, although backwards-compatible with, 1.0's.

-

For addons hosted on addons.mozilla.org - Mozilla's update website may repackage your add-on and correct or reject malformed version strings.

-

类型

-

一个整数代表add-on的类型

- - - - - - - - - - - - - - - - - - - - - - - -
2扩展
4主题
8地区(译者注:多语言)
32多个物品包
64拼写检测字典
-

例如:

-
<em:type>2</em:type>
-

{{ Fx_minversion_inline(1.5) }} This property was added for Firefox 1.5, and is only required for add-on types other than Extensions and Themes.

-

{{ Fx_minversion_inline(3) }} Firefox 2 and previous supported a value of 16 to represent plug-ins. In Firefox 3 this has been removed.

-

targetApplication

-

An object specifying an application targeted by this add-on. This means that the add-on will work with the application identified by the id property (<em:id>) specified (for a comprehensive list of application IDs and valid min/maxVersions for them see Valid application versions for add-on developers), from the minimum version (<em:minVersion>) up to and including the maximum version (<em:maxVersion>). These version strings are formatted in the same fashion as the version property and will be compared to the application version; this allows the extension author to specify which versions of Firefox an extension has been tested with.

-

id, minVersion, and maxVersion are all required.

-
- Extensions compatible with Firefox 3.5 should specify a maxVersion of 3.5.*, so that they are automatically compatible with security and stability updates. For Firefox 3.0, a maxVersion of 3.0.* should be used. Extensions compatible only with Firefox or Thunderbird 2 should specify a maxVersion of 2.0.0.*.
-

The Install Manifest must specify at least one of these objects, and may specify more if the add-on targets multiple applications that support the Add-on Manager (e.g. Firefox and Thunderbird)

-

Examples

-
<em:targetApplication>
- <Description>
-  <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!--Firefox-->
-  <em:minVersion>1.5</em:minVersion>
-  <em:maxVersion>3.0.*</em:maxVersion>
- </Description>
-</em:targetApplication>
-

{{ Fx_minversion_inline(3) }} Gecko 1.9 based applications allow you to use the special targetApplication id toolkit@mozilla.org to say that the add-on is compatible with any toolkit app with a toolkit version matching the minVersion and maxVersion.

-

name

-

The name of the add-on; intended for display in the UI.

-

Examples

-
<em:name>My Extension</em:name>
-

Optional Property Reference

-

You may need to supply these properties, depending on the capabilities of your add-on.

-

bootstrap

-

{{ Fx_minversion_inline(4) }} A Boolean value that tells the application whether the extension is boot-strappable. At the moment this only works for add-ons with em:type="2". The default value is false. For more information, see Bootstrapped extensions.

-

unpack

-

{{ Fx_minversion_inline(4) }} A true or false value that tells the application whether the extension requires its files be unpacked into a directory in order to work or whether the extension can be loaded direct from the XPI. In versions before Gecko 2.0 all extensions were unpacked, in Gecko 2.0 and later the default is to not unpack. If an extension includes the following then it must request unpacking:

- -

Examples

-
<Description about="urn:mozilla:install-manifest">
-   <em:id>extension@mysite.com</em:id>
-   <em:unpack>true</em:unpack>
-   ...
-</Description>
-

localized

-

{{ Fx_minversion_inline(3) }} Allows you to localize the add-on's name, description, contributors and other metadata. The localized description must specify at least one em:locale which indicates which locales to use this information for.

-

Examples

-

This declares a set of add-on metadata to be displayed when the application is running in the de-DE locale.

-
<em:localized>
-  <Description>
-    <em:locale>de-DE</em:locale>
-    <em:name>Tab Sidebar</em:name>
-    <em:description>Zeigt in einer Sidebar Vorschaubilder der Inhalte aller offenen Tabs an.</em:description>
-  </Description>
-</em:localized>
-

The following properties which are described elsewhere in this page can be included in the localized property:

- -

More documentation can be found at Localizing extension descriptions.

-

description

-

A short description of the add-on - intended for display in the user interface. This description should fit on one short line of text.

-

Examples

-
<em:description>Advanced foo tools.</em:description>
-

creator

-

The name of the creator/principal developer - intended for display in the user interface.

-

Examples

-
<em:creator>John Doe</em:creator>
-

or

-
<em:creator>CoolExtension Team</em:creator>
-

developer

-

{{ Fx_minversion_inline(2) }} The name(s) of co-developers. You may specify more than one of this value to specify multiple developers.

-

Examples

-
<em:developer>Jane Doe</em:developer>
-<em:developer>Koos van der Merwe</em:developer>
-
-

translator

-

{{ Fx_minversion_inline(2) }} The name(s) of translators. You may specify more than one of this value to specify multiple translators.

-

Examples

-
<em:translator>Janez Novak</em:translator>
-<em:translator>Kari Nordmann</em:translator>
-
-

contributor

-

The name(s) of additional contributors. You may specify more than one of this value to specify multiple contributors.

-

Examples

-
<em:contributor>John Doe</em:contributor>
-
-<em:contributor>John Doe</em:contributor>
-<em:contributor>Jane Doe</em:contributor>
-<em:contributor>Elvis Presley</em:contributor>
-
-

homepageURL

-

A link to the add-on's home page - intended for display in the user interface.

-

Examples

-
<em:homepageURL>http://www.foo.com/</em:homepageURL>
-
-

updateURL

-

A link to a custom Update Manifest file that specifies available updates to the add-on. The format is described below. If enabled, the add-on manager periodically checks with this Manifest file to determine if newer versions are available.

-
- Note: It is strongly recommended that the updateURL be an HTTPS (secure) link. Non-secure update URLs can be hijacked by a malicious update.rdf file, enabling malware to infiltrate the user's computer. Alternatively, you could host your extension on AMO and leave out the updateURL completely. This provides secure updates automatically.
-

{{ Fx_minversion_inline(3) }} For security reasons, Gecko 1.9 applications require that if you specify an updateURL, it must be an https URL, or you must include an updateKey.

-

Your server must send this file as text/rdf, text/xml or application/xml+rdf or the update checker may not work.

-

The addon manager will substitute the following values into this URL in case you wish to generate the response RDF dynamically, such as using PHP or CGI:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
%REQ_VERSION%The version of the request. Currently 1
%ITEM_ID%The id of the addon being updated
%ITEM_VERSION%The version of the addon being updated
%ITEM_MAXAPPVERSION%The maxVersion of the targetApplication object corresponding to the current application for the addon being updated.
%ITEM_STATUS%{{ Fx_minversion_inline(2) }} Comma separated list of the add-ons operating status in the application. Contains at the least either userEnabled or userDisabled plus any number of incompatible, blockslisted or needsDependencies.
%APP_ID%The id of the current application
%APP_VERSION%The version of the application to check for updates for
%CURRENT_APP_VERSION%{{ Fx_minversion_inline(3.5) }} The version of the current application
%APP_OS%{{ Fx_minversion_inline(1.5) }} The value of OS_TARGET from the Firefox build system, identifying the operating system being used.
%APP_ABI%{{ Fx_minversion_inline(1.5) }} The value of the TARGET_XPCOM_ABI value from the Firefox build system, identifying the compiler/architecture combination used to compile the current application.
%APP_LOCALE%{{ Fx_minversion_inline(3) }} The current application's locale.
%UPDATE_TYPE%{{ Fx_minversion_inline(4) }} UPDATE_TYPE_COMPATIBILITY(32), UPDATE_TYPE_NEWVERSION(64)
%COMPATIBILITY_MODE%{{ Fx_minversion_inline(10) }} related to default to compatible, values could be normal, ignore or strict.
-

Examples

-
<em:updateURL>http://www.foo.com/update.cgi?id=%ITEM_ID%&amp;version=%ITEM_VERSION%</em:updateURL>
-<em:updateURL>http://www.foo.com/extension/windows.rdf</em:updateURL>
-
-

For add-ons hosted on addons.mozilla.org: You may not specify an updateURL property. By default, Mozilla applications using the Add-on Manager (such as Firefox and Thunderbird) will send update requests to addons.mozilla.org using the default web service. Every time you upload a new version of your add-on or change its compatibility parameters through the author interface, your update manifest will be generated automatically. Add-ons currently marked as experimental will not be updated due to security concerns.

-

Format of the Update Manifest: The Update Manifest is a RDF/XML datasource. For examples of an update manifest, see Extension Versioning, Update and Compatibility and Enabling Extension Updates (external).

-

updateKey

-
- {{ Gecko_minversion_header(1.9) }} {{ Fx_minversion_header(3) }}
-

To ensure the security of update rdf data that is retrieved over plain http you must use a digital signature to verify the contents of the data. In order to do so you must include the public part of the cryptographic key in an updateKey entry in the install.rdf of the add-on. This can be generated using the McCoy tool. Any line breaks and whitespace as part of this entry are ignored.

-
<em:updateKey>MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK426erD/H3XtsjvaB5+PJqbhj
-              Zc9EDI5OCJS8R3FIObJ9ZHJK1TXeaE7JWqt9WUmBWTEFvwS+FI9vWu8058N9CHhD
-              NyeP6i4LuUYjTURnn7Yw/IgzyIJ2oKsYa32RuxAyteqAWqPT/J63wBixIeCxmysf
-              awB/zH4KaPiY3vnrzQIDAQAB</em:updateKey>
-
-

optionsURL

-

The chrome:// URL of the extension's options dialog box. This is only useful to extensions. If this property is specified, when the extension is selected in the Extensions list, the Options button is enabled and will show this.

-
<em:optionsURL>chrome://myext/content/options.xul</em:optionsURL>
-

{{ gecko_minversion_note("7", "In Firefox 7 you can also simply include your options XUL as a file named options.xul, in the base directory of the add-on.") }}

-

{{ h3_gecko_minversion("optionsType", 7) }}

-

The type of user-interface used for displaying the options. Accepted values are:

- - - - - - - - - - - - - - - -
1Opens optionsURL in a dialog box
2Options are displayed inside the Add-on Manager
3Opens optionsURL in a new tab (if the application supports that), or a dialog box
-

optionsType defaults to 1 if there is an optionsURL included in install.rdf or 2 if there is no optionsURL and the file options.xul exists in the root of the add-on.

-
<em:optionsType>2</em:optionsType>
-
-

aboutURL

-

The chrome:// URL of the extension's about dialog box. This is only useful to extensions. If this property is specified, when the extension is selected in the Extensions list, the About... link in the extension's context menu will show this dialog, rather than the default.

-
-

{{ gecko_callout_heading("2.0") }}

-

The dialog receives the Addon object representing your add-on as a parameter.

-
-

Examples

-
<em:aboutURL>chrome://myext/content/about.xul</em:aboutURL>
-
-

iconURL

-

A chrome:// URL to an icon to display in the add-ons list. The icon will be displayed at 32x32 in Firefox 3.6 and lower. In Firefox 4.0 and later the icon can be up to 48x48 pixels in size. If this property is not specified, a default icon is used.

-
<em:iconURL>chrome://myext/skin/icon.png</em:iconURL>
-
-
- Note: For the above example to work you will also have to add a skin package line to your chrome.manifest file. See Chrome Registration#skin. Alternatively you can place your icon in the directory specified in your content package line.
-

{{ gecko_minversion_note("1.9.2", "Starting in Gecko 1.9.2 (Firefox 3.6), you can also simply include your icon, named icon.png, in the base directory of the add-on. This allows your add-on's icon to be displayed even when the add-on is disabled, or if the manifest is missing an iconURL entry.") }}

-

{{ h3_gecko_minversion("icon64URL", "2.0") }}

-

A chrome:// URL to a 64x64 pixel icon to display in the add-on's details view . If this property is not specified, the smaller icon above will be used.

-
<em:icon64URL>chrome://myext/skin/icon64.png</em:icon64URL>
-
-
- Note: For the above example to work you will also have to add a skin package line to your chrome.manifest file. See Chrome Registration#skin. Alternatively you can place your icon in the directory specified in your content package line.
-

{{ h3_gecko_minversion("targetPlatform", "1.8") }}

-

A string specifying a platform that the add-on supports. It contains either the value of OS_TARGET alone or combined with TARGET_XPCOM_ABI, separated by an underscore (_).

-

You can specify multiple targetPlatform properties per manifest. If any value matches the application's build parameters, it will be installed; if not, the user will get an appropriate error message.

-

Examples

-
<em:targetPlatform>WINNT_x86-msvc</em:targetPlatform>
-
-<em:targetPlatform>Linux</em:targetPlatform>
-
-<em:targetPlatform>Darwin_ppc-gcc3</em:targetPlatform>
-
-<em:targetPlatform>SunOS_sparc-sunc</em:targetPlatform>
-

Usually, you would use only the OS part for themes or for extensions that are not fully cross-platform. For extensions including binary (compiled) components, you should never use the OS alone, but include the ABI (s) that you compiled the components with. If you want to include multiple versions of the components, you should also use Platform-specific Subdirectories.

-

Notes

- -

This property was added for Firefox/Thunderbird 1.5. Previous versions of these applications will ignore the restrictions and install the add-on regardless of the platform.

-

{{ h3_gecko_minversion("strictCompatibility", "10.0") }}

-

A Boolean value indicating if the add-on should be enabled when the version of the application is greater than its max version. By default, the value of this property is false meaning that the compatibility checking will not be performed against the max version.

-
<em:strictCompatibility>true</em:strictCompatibility>
-

Usually, there is no need to restrict the compatibility: not all new releases will break your extension and, if it is hosted on AMO, you'll get notice several weeks in advance if a potential risk has been detected. Moreover, an extension being disabled, even for a short period, leads to a bad experience for the user. About the only time you should need to set this if your add-on does things that are likely to be broken by Firefox updates. You do not need to set this flag if your add-on has a binary component, since add-ons with binary components are always subject to strict compatibility checking (because binary components need to be rebuilt for every major application release anyway).

-
- Note: If you want to restore the old behavior of strict compatibility checking of all add-ons, regardless of the value of this setting in their manifests, you can set the extensions.strictCompatibility preference to true.
-
-

{{ gecko_callout_heading("11.0") }}

-

Starting in Gecko 11.0 {{ geckoRelease("11.0") }}, applications such as Firefox will assume add-ons that have not been updated in a very long time are no longer compatible by default.

-
-

Obsolete Property Reference

-

These properties were required in older versions of the Add-on Manager, but have been replaced with newer and better mechanisms.

-

file

-

Firefox 1.0 This property pointed to a chrome .jar file that contains chrome packages that require registration with the Chrome Registry.

-

The <em:file> property has a complex object value. The uri of the value is urn:mozilla:extension:file:jarFile.jar where jarFile.jar is the name of the jar file that contains the chrome package's files. This could also be the name of a directory that contains the chrome package's files, un-jarred (e.g. urn:mozilla:extension:file:directory). In either case, the referenced chrome package file(s) must be placed in the chrome subdirectory of the XPI's top level.

-

This object has a package property (with a path within the jar file or directory that leads to the location where the contents.rdf file responsible for registering that package is located), a locale property (ditto, but to register the locale) and a skin property (ditto, but to register the theme material).

-

In extensions for Firefox 1.5, this property is no longer necessary: the chrome.manifest at the top level of the XPI is used to locate chrome to register. If there is no chrome.manifest, this property is still read by the Add-on Manager and a chrome.manifest is generated from old-style contents.rdf.

-

Examples

-
<em:file>
- <Description about="urn:mozilla:extension:file:myext.jar">
-  <em:package>content/myext/</em:package>
-  <em:locale>locale/en-US/myext/</em:locale>
-  <em:skin>skin/classic/myext/<em:skin>
- </Description>
-</em:file>
-
-

An Install Manifest may specify multiple file properties, one for each jar file or subdirectory that contains chrome to register.

-

hidden

-

Firefox 1.0 - 3.5 A boolean value that when true makes the add-on not show up in the add-ons list, provided the add-on is installed in a {{ Anch("restricted access area") }} (so it does not work for add-ons installed in the profile). This is for bundling integration hooks to larger applications where having an entry in the Extensions list does not make sense.

-
- Note: This property is no longer supported under Gecko 1.9.2 (Firefox 3.6) or later, to prevent extensions from being installed in such a way that the user might not be able to tell they're installed.
-

Examples

-
<em:hidden>true</em:hidden>
-
-

requires

-

Firefox 2.0 - 3.6.x. Other versions will ignore the restrictions and install the add-on regardless of the requirements.

-

See Replacement for install.rdf property "requires" discussion for rationale behind removing this feature and the suggested workaround.

-

<em:requires> has a similar syntax to the <em:targetApplication> tag (i.e. you must specify <em:id>, <em:minVersion>, <em:maxVersion> when using it). If the add-on specified by the <em:id> tag is not installed or has an incompatible version, the extension manager will disable your extension and show the message "Requires additional items". You can add as many <em:requires> tags as you like. Your extension will be disabled if any of the specified requirements fail. It is not possible to add dependencies that are specific to a <em:targetApplication>. See Extension Dependencies for more details.

-

Glossary

-

restricted access area

-

A restricted access area is an install location that could be restricted on a restricted-access account, regardless of whether or not the location is restricted with the current user privileges (see {{ Source("toolkit/mozapps/extensions/public/nsIExtensionManager.idl#80", "nsIInstallLocation::restricted") }}). Currently, the ($APPDIR)/extensions folder and the registry install location under HKEY_LOCAL_MACHINE (see Adding Extensions using the Windows Registry for details) are restricted.

-

The ($PROFILE)/extensions and HKEY_CURRENT_USER install locations, on the other hand, are not restricted.

diff --git a/files/zh-cn/mozilla/add-ons/legacy_add_ons/index.html b/files/zh-cn/mozilla/add-ons/legacy_add_ons/index.html deleted file mode 100644 index 9200ccb0f6..0000000000 --- a/files/zh-cn/mozilla/add-ons/legacy_add_ons/index.html +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: 旧式附件组件 -slug: Mozilla/Add-ons/Legacy_add_ons -translation_of: Archive/Add-ons/Legacy_add_ons ---- -

{{LegacyAddonsNotice}}{{AddonSidebar}}

- -

本节包含附件组件开发的旧式技术文档链接,包括:

- - diff --git a/files/zh-cn/mozilla/add-ons/overlay_extensions/index.html b/files/zh-cn/mozilla/add-ons/overlay_extensions/index.html deleted file mode 100644 index 6504a2ef16..0000000000 --- a/files/zh-cn/mozilla/add-ons/overlay_extensions/index.html +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: Overlay扩展 -slug: Mozilla/Add-ons/Overlay_Extensions -tags: - - Add-ons - - Extensions - - Landing - - NeedsTranslation - - TopicStub -translation_of: Archive/Add-ons/Overlay_Extensions ---- -

{{LegacyAddonsNotice}}{{AddonSidebar}}

- -

本页面为那些基于 Gecko 的应用开发扩展插件的开发者们提供了可用的参考文献链接。

- - - -

唯一可行的方法是开发扩展在 Gecko 2.0 发布之前. 但是现在有两种可以选择的技术:免重启扩展和基于 SDK 的扩展插件. 这些特定的 JavaScript APIs 仍旧可以被这些较新的技术使用。

- -

Prior to Firefox 4, and the Gecko 2 engine that powers it, this was the only way to develop extensions. This methodology has largely been superseded by restartless extensions, and the Add-on SDK, which is built on top of them. The privileged JavaScript APIs described here can still be used in these newer types of add-ons.

- -

XUL 学校

- -

XUL 学校 是一个综合性的拓展开发指南,主要针对 Firefox 的扩展开发,但是绝大多数可应用于其他基于 Gecko 的应用。

- -

更多资源

- -
-
-
-
设置环境
-
设置扩展开发需要的应用.
-
XUL
-
相关的指南介绍XUL 扩展的接口.
-
代码片段
-
提供了很多的简单示例代码片段.
-
安装扩展
-
如何通过把扩展的文件拷贝进应用的安装目录来安装扩展.
-
Firefox 插件的开发者指南
-
开发扩展的指南.
-
-
- -
-
-
JavaScript 模块代码
-
适用于扩展开发者的 JavaScript 模块。
-
扩展偏好
-
如何在你的扩展出现在附加组件管理界面的时候指定偏好设置。
-
常见问题
-
常见的扩展开发中的错误。
-
扩展打包
-
看看扩展是如何被打包和安装的。
-
Firefox 的二进制扩展
-
为 Firefox 创建二进制扩展。
-
-
-
diff --git a/files/zh-cn/mozilla/add-ons/performance_best_practices_in_extensions/index.html b/files/zh-cn/mozilla/add-ons/performance_best_practices_in_extensions/index.html deleted file mode 100644 index d6a6f7515b..0000000000 --- a/files/zh-cn/mozilla/add-ons/performance_best_practices_in_extensions/index.html +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: 扩展中的性能最佳实践 -slug: Mozilla/Add-ons/Performance_best_practices_in_extensions -translation_of: Archive/Add-ons/Performance_best_practices_in_extensions ---- -

Firefox 的一个巨大优势就是可扩展性非常强。扩展组件几乎可以做任何事情。但这也带来了一个劣势: 扩展组件如果写的不好,将会大大的影响浏览器性能,包括 firefox 的整体体验。 本文则提供了一些最佳实践方式,他们不仅能够提升你的组件的性能和速度,也会对 firefox 带来同样的影响。

-

提升启动性能

-

Extensions are loaded and run whenever a new browser window opens. That means every time a window opens, your extension can have an impact on how long it takes the user to see the content they're trying to view. There are several things you can do to reduce the amount of time your extension delays the appearance of the user's desired content.

-

只在需要的时候装载需要的东西

-

Don't load things during startup that are only needed if the user clicks a button, or if a given preference is enabled when it's not. If your extension has features that only work when the user has logged into a service, don't load the resources for those features until the user actually logs in.

-

使用  JavaScript code modules

-

You can create your own JavaScript code modules incorporating sets of features that are only needed under specific circumstances. This makes it easy to load chunks of your extension on the fly as needed, instead of loading everything all at once.

-

This has an advantage over XPCOM modules, which are always loaded when your extension starts up.

-

Of course, for extremely simple extensions it may not make sense to modularize your code.

-

Defer everything that you can

-

Most extensions have a load event listener in the main overlay that runs their startup functions. Do as little as possible here. The browser window is blocked while your add-on's load handler runs, so the more it does, the slower Firefox will appear to the user.

-

If there is anything that can be done even a fraction of a second later, you can use an {{ interface("nsITimer") }} or the {{ domxref("window.setTimeout()") }} method to schedule that work for later.  Even a short delay can have a big impact.

-

通用性能提示

-

避免产生内存泄漏

-

Memory leaks require the garbage collector and the cycle collector to work harder, which can significantly degrade performance.

-

Zombie compartments are a particular kind of memory leak that you can detect with minimal effort.  See the Zombie compartments page, especially the Proactive checking of add-ons section.

-

See Common causes of memory leaks in extensions for ways to avoid zombie compartments and other kinds of leaks.

-

As well as looking for these specific kinds of leaks, it's worth exercising your extension's functionality and checking the contents of about:memory for any excessive memory usage.  For example, bug 719601 featured a "System Principal" JavaScript compartment containing 100s of MBs of memory, which is much larger than usual.

-

Use JavaScript Modules

-

JavaScript modules are just like any other JavaScript, with the exception that they are singletons and Firefox can cache the compiled code for faster use the next time the browser is started. Any time your add-on loads JavaScript from an {{ HTMLElement("script") }} element you should consider using a JavaScript Module instead. For more on how JavaScript modules work, see the Using JavaScript Code Modules page.

-

Avoid Writing Slow CSS

- -

Avoid DOM mutation event listeners

-

Adding DOM mutation listeners to a document disables most DOM modification optimizations and profoundly degrades the performance of further DOM modifications to that document. Moreover, removing the listeners does not reverse the damage. For these reasons, the following events should be avoided wherever possible: DOMAttrModified, DOMAttributeNameChanged, DOMCharacterDataModified, DOMElementNameChanged, DOMNodeInserted, DOMNodeInsertedIntoDocument, DOMNodeRemoved, DOMNodeRemovedFromDocument, DOMSubtreeModified

-

For more on these events and their deprecation, see Mutation events. Use Mutation Observers instead if possible.

-

延迟加载服务 services

-

The XPCOMUtils JavaScript module provides two methods for lazily loading things:

- -

As of Firefox 4.0, many common services are already cached for you in Services.jsm.

-

Reduce file I/O

-

TODO: Give examples below, link to code, bugs, docs.

- -

Use the right compression level for JAR and XPI files

-

Reading data from compressed archives costs time. The higher the compression level of the archive, the higher also the performance cost of reading the data from it. So any JAR files in your extension should always be packed with compression level 0 (no compression) for better performance. It may seem counter-intuitive, but doing this will increase the JAR file size and actually decrease the XPI file size as it allows for compression between files inside the JAR to be done when compressing the XPI (essentially a poor-man's solid archive effect).

-

If your extension doesn't specify em:unpack then its XPI file will not be unpacked in Firefox 4 and used directly instead. This makes choosing a low compression level preferable; we recommend using compression level 1. It will increase the download size only a small amount, even compared to maximum compression.

-

使用异步 I/O

-

This cannot be stressed enough: never do synchronous I/O on the GUI thread.

- -

Unnecessary onreadystatechange in XHR

-

addEventListener(load/error) and/or xhr.onload/.onerror are usually sufficient for most uses and will only be called once, contrary to onreadystatechange. When using XHR in websites people tend to use onreadystatechange (for compatiblity reasons). Often it is enough to just load the resource or handle errors. load/error event listener are far less often called than onreadystatechange, i.e. only once, and you don't need to check readyState or figure out if it is an error or not. Only use onreadystatechange if you want to process the response while it is still arriving.

-

Removing Event Listeners

-

Remove event listener if they are not needed any more. It is better to actually remove event listener instead of just having some flag to check if the listener is active which is checked every time when an event is propagated. Abandon schemes like: function onMouseOver(evt) { if (is_active) { /* doSomeThing */ } } Also, remove "fire-once" listeners again:

-
 function init() {
-   var largeArray;
-   addEventListener('load', function onLoad() {
-        removeEventListener('load', onLoad, true);
-        largeArray.forEach();
- }, true);
-
-

Else a lot of closure stuff might be still referenced (largeArray in this example). And the listener will sit idle in some internal table.

-

Populate menus as needed

-

Populate "context" menus (page, tabs, tools) as needed and keep computation to a minimum (UI responsiveness). There is no need to populate the context menu every time something changes. It is enough to populate it once the user actually needs it. Add a listener to the "popupshowing" event and compute there.

-

Avoid mouse movement events

-

Avoid mouse movement events (enter/over/exit) or at least keep computation to a minimum. Mouse movement events, especially the mouseover event, usually happen at high frequency. Best would be to only store the new information and compute "stuff" once the user actually requests it (e.g. in a popupshowing event). Also don't forget to remove the event listeners when no longer needed (see above).

-

Avoid polling

-

Use {{ interface("nsIObserverService") }} functionality instead. Everybody is free to post "custom" notifications via {{ interface("nsIObserverService") }}, but few extensions actually use this. However, a lot of other services also provide observer functionality, such as nsIPrefBranch2.

-

aPNG/aGIF inappropriate in a lot of cases

-

Animations require a lot of time to set up, as a lot of images are decoded (the frames). Animated images may have their cached representations evicted quite often, causing the frames of your animated images to be reloaded lots of times, not just once. {{ interface("nsITree") }} / {{ XULElem("tree") }} seems to be extra special in this regard, as it doesn't seem to cache animations at all under certain circumstances.

-

base64/md5/sha1 implementations

-

Do not ship your own base64/md5/sha1 implementations. Regarding base64 there are the built-in atob/btoa functions that do the job just well and are available in overlay script as well as in in JavaScript modules and components. Hashes can be computed using {{ interface("nsICryptoHash") }}, which accepts either a string or an {{ interface("nsIInputStream") }}.

-

Image sprites

-

You may combine multiple images into one (sprites). See {{ cssxref("-moz-image-region") }}. Most XUL widgets that are used to display some image (incl. {{ XULElem("button") }} and {{ XULElem("toolbarbutton") }}) allow to use {{ cssxref("list-style-image") }}. Avoid the imagesrc/src attributes to define images where possible.

-

Consider using Chrome Workers

-

You can use a {{ domxref("ChromeWorker") }} to execute long running tasks or do data processing.

-

参考

- diff --git a/files/zh-cn/mozilla/add-ons/plugins/index.html b/files/zh-cn/mozilla/add-ons/plugins/index.html deleted file mode 100644 index f35791a3bf..0000000000 --- a/files/zh-cn/mozilla/add-ons/plugins/index.html +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: Plugins -slug: Mozilla/Add-ons/Plugins -tags: - - Add-ons - - NPAPI - - NeedsTranslation - - Plugins - - TopicStub -translation_of: Archive/Plugins ---- -
-

Important: Since Firefox 52, all plugin support except Flash has been dropped (see Plug-in support has been dropped other than Flash for more details). Flash usage is also set to be phased out in the future.

-
- -
-

Note: Plugins are now a legacy technology. They are not available on most mobile devices. Mozilla encourages website developers to avoid using plugins wherever possible and use standard Web APIs instead. If there are plugin features which are not available in the web platform, we encourage developers to post their use cases to mozilla.dev.platform project list, so that Mozilla can prioritize web platform work to make those use cases possible.

-
- -

For more information about plugin roadmap, see non-archived plugin information.

- -

Plugins are shared libraries that users can install to display content that the browser can't display natively. For example, the Adobe Reader plugin lets the user open PDF files directly inside the browser, and the QuickTime and RealPlayer plugins are used to play special format videos in a web page.

- -

Plugins are written using NPAPI, the cross-browser API for plugins. The main source of documentation for NPAPI is the Gecko Plugin API Reference. To make your plugin scriptable from web pages, use npruntime.

- -

Plugins can be written completely from scratch using C APIs (usually in C or C++) or they may be built on a plugin framework such as Firebreath, JUCE, or QtBrowserPlugin. There are also some code generation tools that may be helpful. More information about these tools can be found on the External Resources page.

- -

Plugins are different from extensions, which modify or enhance the functionality of the browser itself. Plugins are also different from search plugins, which plug additional search engines in the search bar.

- -
-
-
-
-
Gecko Plugin API Reference (NPAPI)
-
This reference describes the application programming interfaces for NPAPI plugins and provides information about how to use these interfaces.
-
Site Author Guide For Click-To-Activate Plugins
-
These guidelines will help website authors use plugins when they are blocked by default with the Firefox click-to-activate feature.
-
- -
-
Scripting plugins (npruntime)
-
This reference describes the new cross-browser NPAPI extensions that let plugins be scriptable and also let them access the script objects in the browser.
-
- -
-
Shipping a plugin as a Toolkit bundle
-
Plugins can be shipped as a Toolkit bundle, allowing a user to easily install, uninstall and manage their personal plugins.
-
- -
-
Supporting private browsing in plugins
-
Firefox 3.5 introduced support for private browsing; learn how to make your plugin respect the user's privacy wishes.
-
Multi-Process Plugin Architecture
-
How Firefox loads plugins into a separate process. Firefox 3.6.4 introduced out-of-process plugins which execute in a separate process so that a crashing plugin does not crash the browser.
-
Logging and Debugging for Multi-Process Plugins
-
How to create a plugin log to aid in debugging problems with multi-process plugins.
-
-
- -
-
-
Writing a plugin for Mac OS X
-
Learn how to write a plugin for Mac OS X; a template Xcode project is provided.
-
- -
-
Monitoring Plugins
-
Use an observer service notification to monitor the amount of time spent executing calls in plugins. This can be useful when trying to determine if a plug-in is consuming too many resources.
-
- -
-
Scripting Plugins: Macromedia Flash
-
This article explains how JavaScript can be used to access methods from within the Flash plugin, as well as how a feature called FSCommands can be used to access JavaScript functions from within the Flash animation.
-
- -
-
Plugins: The First Install Problem
-
The First Install Problem is the name given to the conditions arising when a plugin or embeddable software installs itself on a system first, before any other Gecko-based browser.
-
- -
-
Plugins: Samples and Test Cases
-
NPAPI plugin samples and test cases.
-
External Resources for Plugin Creation
-
External projects, frameworks, and blog posts that may be useful.
-
- -
-
XEmbed Extension for Mozilla Plugins
-
Recent versions of Mozilla on *nix-based systems include an extension for writing plugins that use XEmbed instead of using the old Xt-based main loop that most plugins have been using since the Netscape 3.x days.
-
-
-
- -
-

Categories

- -

Interwiki Language Links

- -
-
-

Join the plugin development community

- -
-
Choose your preferred method for joining the discussion:
- - -
- -
-
-
diff --git a/files/zh-cn/mozilla/add-ons/plugins/reference/index.html b/files/zh-cn/mozilla/add-ons/plugins/reference/index.html deleted file mode 100644 index fcb2ba7232..0000000000 --- a/files/zh-cn/mozilla/add-ons/plugins/reference/index.html +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: NPAPI plugin reference -slug: Mozilla/Add-ons/Plugins/Reference -tags: - - Deprecated - - Landing - - NPAPI - - NeedsTranslation - - Plugins - - Reference - - TopicStub -translation_of: Archive/Plugins/Reference ---- -

{{deprecated_header}}

-

The articles below describe each of the APIs related to NPAPI plugins.

-

{{LandingPageListSubpages}}

diff --git a/files/zh-cn/mozilla/add-ons/plugins/samples_and_test_cases/index.html b/files/zh-cn/mozilla/add-ons/plugins/samples_and_test_cases/index.html deleted file mode 100644 index 4d0ac34085..0000000000 --- a/files/zh-cn/mozilla/add-ons/plugins/samples_and_test_cases/index.html +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: Samples and Test Cases -slug: Mozilla/Add-ons/Plugins/Samples_and_Test_Cases -translation_of: Archive/Plugins/Samples_and_Test_Cases ---- -

NPAPI Plugin Samples

-

Collections of NPAPI plugin samples can be found in the Seamonkey source code at /modules/plugin/sdk/samples.

-

The samples may not build any more on all platforms. There are plans to clean up the sample plugin situation - better organization, updated build systems, get them building on all platforms. However, even if one cannot build the samples they can still be very valuable as code references.

-

There is a guide to compiling the npruntime sample in Visual Studio.

-

In addition to those samples, there are 2 more plugins in the tree that might be helpful.

- -

NPAPI Plugin Test Cases

- -

{{ languages( { "de": "de/Plugins/Beispiele_und_Testfälle" } ) }}

diff --git a/files/zh-cn/mozilla/add-ons/plugins/shipping_a_plugin_as_a_toolkit_bundle/index.html b/files/zh-cn/mozilla/add-ons/plugins/shipping_a_plugin_as_a_toolkit_bundle/index.html deleted file mode 100644 index 30aae2d422..0000000000 --- a/files/zh-cn/mozilla/add-ons/plugins/shipping_a_plugin_as_a_toolkit_bundle/index.html +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Shipping a plugin as an extension -slug: Mozilla/Add-ons/Plugins/Shipping_a_plugin_as_a_Toolkit_bundle -tags: - - Extensions - - Plugins -translation_of: Archive/Plugins/Shipping_a_plugin_as_a_Toolkit_bundle ---- -

One of the new features that is available in Firefox 1.5 is the ability to place browser plug-ins in a Firefox extension.

-

Historically, most people have chosen to use an install.js script to install a plug-in. When this method is used, you can choose to either place the plug-in into the plugins directory, or place it into your own directory and modify the Windows registry to let Firefox know where to find the plug-in. The downside to this method is that once the plug-in is installed, it might be difficult for users to upgrade, uninstall, or disable the plug-in. As of Firefox 3 (and any Gecko 1.9 based application) the use of install.js scripts is no longer possible and plugins must either be shipped as an executable installer or as an extension as described here.

-

Bundle structure

-

Toolkit bundles can be used for all add-ons including extensions, themes and plugins. Plugin packages should only need to package a small set of files in the follow structure in the xpi file:

-
install.rdf
-plugins/
-    pluginlib.dll
-    plugintypes.xpt
-
-

The install.rdf file contains an install manifest that describes the plugin to the user. The library and scripting interfaces are held in the <tt>plugins</tt> directory.

-

Platform-specific files

-

It is possible to package multiple plugin libraries for different operating systems into a single xpi bundle. In the xpi you can use the following structure:

-
platform/
-    Linux_x86-gcc3/
-        plugins/
-            libplugin.so
-    Darwin_ppc-gcc3/
-        plugins/
-            libplugin.dylib
-
-

More specific information can be found in the platform-specific subdirectories documentation.

-

Install Manifest

-

The install manifest describes the plugin to the user. For a plugin the manifest only needs to be very simple:

-
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
-  <Description about="urn:mozilla:install-manifest">
-    <em:id>mypluginid@myplugin.com</em:id>
-    <em:name>My Plugin</em:name>
-    <em:version>1.0</em:version>
-    <em:targetApplication>
-      <Description>
-        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
-        <em:minVersion>1.5</em:minVersion>
-        <em:maxVersion>3.0.*</em:maxVersion>
-      </Description>
-    </em:targetApplication>
-  </Description>
-</RDF>
-
-

This contains 4 required pieces of information.

-
    -
  1. Every add-on must have a unique id. This can be in a guid form but the simpler email form is preferred now. You should aim to use a domain-name that you own and then your own unique short-name for the plugin before the @.
  2. -
  3. The plugin must have a name to identify the plugin to the user in the list of add-ons.
  4. -
  5. The version is fairly self-descriptive, it must be a toolkit version format.
  6. -
  7. The target application block says which versions of an application the plugin is compatible with. It includes the application ID and the minimum and maximum version of the application that the plugin works with. There can be multiple targetApplication blocks listed.
  8. -
-

Providing updates

-

When plugins are packaged in this way they can make use of the built in add-on update system. This allows a remote update file to be read periodically and an updated version of the plugin offered to the user or to mark the plugin as compatible with a wider range of applications.

-

This is performed by including an updateURL in the install manifest. This should point to an update.rdf file on the internet which will include the updated versions and version information for the plugin.

diff --git a/files/zh-cn/mozilla/add-ons/sdk/builder/index.html b/files/zh-cn/mozilla/add-ons/sdk/builder/index.html deleted file mode 100644 index 1baa282d43..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/builder/index.html +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Builder -slug: Mozilla/Add-ons/SDK/Builder -translation_of: Archive/Add-ons/Add-on_SDK/Builder ---- -

The Add-on Builder was a web-based development environment that allowed developers to create add-ons using the SDK APIs, but without needing to use the cfx command line tool. It was retired on April 1, 2014, and the "builder.addons.mozilla.org" domain now redirects to this page.
-
- If you have only used the SDK through the Builder, you already know most of what you need to know to develop using just the SDK. The high-level and low-level APIs used for Builder add-ons are exactly the same for Builder and SDK. To switch to the SDK:

- diff --git a/files/zh-cn/mozilla/add-ons/sdk/guides/content_scripts/index.html b/files/zh-cn/mozilla/add-ons/sdk/guides/content_scripts/index.html deleted file mode 100644 index fa95b15db3..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/guides/content_scripts/index.html +++ /dev/null @@ -1,486 +0,0 @@ ---- -title: Content Scripts(内容脚本) -slug: Mozilla/Add-ons/SDK/Guides/Content_Scripts -translation_of: Archive/Add-ons/Add-on_SDK/Guides/Content_Scripts ---- -
{{AddonSidebar}} -

很多 add-ons 需要访问和修改 web 页面的内容。但是 add-on 的主代码不能直接访问 web 内容。替代方案是, SDK add-ons 需要使用一些分散的脚本代理访问 web 内容,这些脚本被称作内容脚本(content scripts)。本页面描述如何开发和部署内容脚本。

- -

内容脚本是在使用SDK时很令人疑惑的点,但你很有可能不得不使用它们。下面有五个基本原则:

- - - -

这个完整的 add-on 表现出所有的这些原则。它的"main.js"使用 tabs 模块附加了一个内容脚本到当前标签页。本例中内容脚本作为字符串传递,内容脚本简单地替换了页面的内容:

- -
// main.js
-var tabs = require("sdk/tabs");
-var contentScriptString = 'document.body.innerHTML = "<h1>this page has been eaten</h1>";'
-
-tabs.activeTab.attach({
-  contentScript: contentScriptString
-});
- -

下面的高层次 SDK 模块能使用内容脚本来修改 web 页面:

- - - -

另外,还能使用 HTML 定义了一些 SDK 用户接口组件,并且使用分类的脚本来和这些内容交互。从很多方面来讲,这些脚本就像内容脚本一样,但它们并不是本文的关注点。要学习如何和用户接口模块的内容交互,请参看模块定义文档:panelsidebarframe

- -

这篇指南中列出的几乎所有的示例都是完整并且且最小的,可以在 Github 的 addon-sdk-content-scripts repository 页面上获得。

- -

加载用户脚本

- -
-

你可以声明一个字符串或者指定 contentScriptcontentScriptFile 选项加载一个单独的脚本。contentScript 选项接受一个作为脚本的字符串:

- -
// main.js
-
-var pageMod = require("sdk/page-mod");
-var contentScriptValue = 'document.body.innerHTML = ' +
-                         ' "<h1>Page matches ruleset</h1>";';
-
-pageMod.PageMod({
-  include: "*.mozilla.org",
-  contentScript: contentScriptValue
-});
- -

contentScriptFile 选项接受一个作为 resource:// URL 的字符串,指向一个存储在你的 add-on 的 data 目录中的脚本文件。jpm不会默认创建"data"目录,所以你必须创建该目录并将你的用户脚本放进去。

- -

本 add-on 提供一个 URL ,指向"content-script.js"文件,存储在 add-on 根目录下的 data 子目录:

- -
// main.js
-
-var data = require("sdk/self").data;
-var pageMod = require("sdk/page-mod");
-
-pageMod.PageMod({
-  include: "*.mozilla.org",
-  contentScriptFile: data.url("content-script.js")
-});
- -
// content-script.js
-
-document.body.innerHTML = "<h1>Page matches ruleset</h1>";
- -
-

从 Firefox 34 开始,你可以使用"./content-script.js"替代 self.data.url("content-script.js")。所以你可以像这样重写:

- -
var pageMod = require("sdk/page-mod");
-
-pageMod.PageMod({
-  include: "*.mozilla.org",
-  contentScriptFile: "./content-script.js"
-});
-
-
- -
-

除非你的内容脚本非常简单并且固定是一个静态的字符串,请不要使用 contentScript:否则,你会在从 AMO 获取你的add-on上遇到问题。

- -

相反,把脚本放到一个单独的文件并用 contentScriptFile 加载它。这回事你的代码更易维护、安全、调试和审核。

-
- -

你可以给 contentScriptcontentScriptFile 传递字符串数组来加载多个脚本:

- -
// main.js
-
-var tabs = require("sdk/tabs");
-
-tabs.on('ready', function(tab) {
-  tab.attach({
-      contentScript: ['document.body.style.border = "5px solid red";', 'window.alert("hi");']
-  });
-});
-
- -
// main.js
-
-var data = require("sdk/self").data;
-var pageMod = require("sdk/page-mod");
-
-pageMod.PageMod({
-  include: "*.mozilla.org",
-  contentScriptFile: [data.url("jquery.min.js"), data.url("my-content-script.js")]
-});
- -

如果你这么做,这些脚本之间可以直接交互,就像他们被同一个 web 页面加载一样。

- -

你也可以把 contentScriptcontentScriptFile 一起用。如果你这么做,使用 contentScriptFile 定义的脚本会在使用 contentScript 定义的脚本之前加载。这使你能够用 URL 加载比如 jQuery 这样的 JavaScript 库,然后传递一个简单的能够使用jQuery脚本:

- -
// main.js
-
-var data = require("sdk/self").data;
-var pageMod = require("sdk/page-mod");
-
-var contentScriptString = '$("body").html("<h1>Page matches ruleset</h1>");';
-
-pageMod.PageMod({
-  include: "*.mozilla.org",
-  contentScript: contentScriptString,
-  contentScriptFile: data.url("jquery.js")
-});
- -
-

除非你的内容脚本非常简单并且固定是一个静态的字符串,请不要使用 contentScript:否则,在从 AMO 获取你的 add-on 上,你会遇到问题。

- -

相反,把脚本放到一个单独的文件并用 contentScriptFile 加载它。这回事你的代码更易维护、安全、调试和审核。

-
- -

控制附加脚本的时间

- -

contentScriptWhen 选项指定了什么时候加载内容脚本。从这里选一个:

- -
    -
  • "start":页面 document 元素插入 DOM 之后,立即加载脚本。这时 DOM 的内容仍未加载,所以脚本不能与其交互。
  • -
  • "ready":页面 DOM 加载完后加载脚本:也就是说,在那个时间点 DOMContentLoaded 事件触发。这时,内容脚本可以和DOM内容交互,但外部引用的样式表和图片可能还没有完成加载。
  • -
  • "end":页面上所有内容(DOM、JS、CSS、images)加载完后,加载脚本,就是在 window.onload 事件触发的时候
  • -
- -

默认值为 "end"

- -

注意 tab.attach() 不支持 contentScriptWhen,因为它原来就是在页面加载页面的时候被调用的。

- -

传递配置选项

- -

contentScriptOptions 是一个作为只读对象暴露给内容脚本的JSON对象,在 self.options 的属性里:

- -
// main.js
-
-var tabs = require("sdk/tabs");
-
-tabs.on('ready', function(tab) {
-  tab.attach({
-      contentScript: 'window.alert(self.options.message);',
-      contentScriptOptions: {"message" : "hello world"}
-  });
-});
- -

这里可以使用任何可以转成json的值(object、array、string等等)。

- -

访问 DOM

- -

内容脚本可以访问页面的 DOM,就像任何页面中加载的脚本(页面脚本)一样。但是内容脚本和页面脚本之间是隔离的:

- -
    -
  • 内容脚本不能看到任何由页面脚本添加到页面的 JavaScript 对象
  • -
  • 如果页面脚本重定义了某个 DOM 对象的行为,但内容脚本只会看到原来的那个行为。
  • -
- -

相反也是如此:页面脚本不能看到内容脚本添加的 JavaScript 对象。

- -

例如,假想一个页面用页面脚本添加变量 foowindow 对象:

- -
<!DOCTYPE html">
-<html>
-  <head>
-    <script>
-    window.foo = "hello from page script"
-    </script>
-  </head>
-</html>
- -

在这个脚本后面加载到页面的其他脚本也可以访问 foo。但是内容脚本不能:

- -
// main.js
-
-var tabs = require("sdk/tabs");
-var mod = require("sdk/page-mod");
-var self = require("sdk/self");
-
-var pageUrl = self.data.url("page.html")
-
-var pageMod = mod.PageMod({
-  include: pageUrl,
-  contentScript: "console.log(window.foo);"
-})
-
-tabs.open(pageUrl);
- -
console.log: my-addon: null
-
- -

这种隔离策略有着很合理的理由。首先,这意味着内容脚本不会泄露对象给 web 页面,这样可能会打开安全漏洞。第二,这意味着,在内容脚本创建对象的时候,可以不用担心是否会和页面脚本添加的对象相冲突。

- -

这种隔离意味着,例如,如果一个 web 页面加载了 jQuery 库,那么内容脚本不能够看到由该库添加的 jQuery 对象——但是可以看到内容脚本添加的自己的 jQuery 对象,并且它不会和页面脚本的 jQuery 版本冲突。

- -

和页面脚本交互

- -

一般来说,这种内容脚本和页面脚本的隔离正是你所希望的。但是有时候你也许会希望和页面脚本交互:你想在内容脚本和页面脚本之间共享对象来,来在它们之间发送消息。如果你需要这么做,请阅读和页面脚本交互

- -

事件监听器

- -

你可以监听 DOM 的事件,就像在页面脚本中一样,但是有两个重要的区别:

- -

第一,如果你向 setAttribute() 传递字符串,来定义了事件监听器,那么此监听器被当做是在页面上下文中的,所以它不能访问任何内容脚本中的变量。

- -

如下,内容脚本会失败报错"theMessage is not defined":

- -
var theMessage = "Hello from content script!";
-anElement.setAttribute("onclick", "alert(theMessage);");
- -

Second, if you define an event listener by direct assignment to a global event handler like onclick, then the assignment might be overridden by the page. For example, here's an add-on that tries to add a click handler by assignment to window.onclick:

- -
var myScript = "window.onclick = function() {" +
-               "  console.log('unsafewindow.onclick: ' + window.document.title);" +
-               "}";
-
-require("sdk/page-mod").PageMod({
-  include: "*",
-  contentScript: myScript,
-  contentScriptWhen: "start"
-});
- -

这个示例会在大多数页面上正常工作,但是会在定义 onclick 的页面上失败:

- -
<html>
-  <head>
-  </head>
-  <body>
-    <script>
-    window.onclick = function() {
-      window.alert("it's my click now!");
-    }
-    </script>
-  </body>
-</html>
- -

由于这些原因,最好还是用 addEventListener() 添加一个事件监听器,定义监听器为一个函数:

- -
var theMessage = "Hello from content script!";
-
-anElement.onclick = function() {
-  alert(theMessage);
-};
-
-anotherElement.addEventListener("click", function() {
-  alert(theMessage);
-});
- -

和 add-on 通信

- -

为了使 add-on 脚本和内容脚本相互通信,任何一通信端都要访问 port 对象。

- -
    -
  • 要从一头发送消息到另一头,使用 port.emit()
  • -
  • 要从另一头接收消息,使用 port.on()
  • -
- -

消息是异步的:也就是说,发送方不会等待接收方的回应,而仅仅是发送消息完后继续处理别的事情。

- -

这里有一个简单的 add-on 使用 port 发送一个消息到内容脚本:

- -
// main.js
-
-var tabs = require("sdk/tabs");
-var self = require("sdk/self");
-
-tabs.on("ready", function(tab) {
-  var worker = tab.attach({
-    contentScriptFile: self.data.url("content-script.js")
-  });
-  worker.port.emit("alert", "Message from the add-on");
-});
-
-tabs.open("http://www.mozilla.org");
- -
// content-script.js
-
-self.port.on("alert", function(message) {
-  window.alert(message);
-});
- -
-

context-menu 模块没有使用这里描述的通信模型。了解更多关于使用 context-menu 和内容脚本通信的事情,参看 context-menu documentation

-
- -

在内容脚本中访问 port

- -

内容脚本中,port 对象是作为global下 self 对象的属性。所以要从内容脚本中发送消息的话:

- -
self.port.emit("myContentScriptMessage", myContentScriptMessagePayload);
- -

要从 add-on 代码接收消息

- -
self.port.on("myAddonMessage", function(myAddonMessagePayload) {
-  // Handle the message
-});
- -
-

注意 global下 self 对象和 self 模块完全不一样,后者提供一个API给 add-on,用来访问它的数据文件和ID。

-
- -

在内容脚本中访问 port

- -

在 add-on 代码中,联通 add-on 和某一特定内容脚本上下文的通道被封装入 worker 对象。所以和内容脚本通信的 port 对象其实是其相对应的 worker 对象的一个属性。

- -

但是,这个 worker 没有暴露给 add-on 代码,以及同样所有的模块。

- -

page-worker

- -

page-worker 对象直接整合了 work API。所以要从一个由 page-worker 关联的内容脚本接收消息的话,你可以使用 pageWorker.port.on()

- -
// main.js
-
-var self = require("sdk/self");
-
-var pageWorker = require("sdk/page-worker").Page({
-  contentScriptFile: self.data.url("content-script.js"),
-  contentURL: "http://en.wikipedia.org/wiki/Internet"
-});
-
-pageWorker.port.on("first-para", function(firstPara) {
-  console.log(firstPara);
-});
- -

要从你的 add-on 发送用户定义的消息,你可以只调用 pageWorker.port.emit()

- -
// main.js
-
-var self = require("sdk/self");
-
-var pageWorker = require("sdk/page-worker").Page({
-  contentScriptFile: self.data.url("content-script.js"),
-  contentURL: "http://en.wikipedia.org/wiki/Internet"
-});
-
-pageWorker.port.on("first-para", function(firstPara) {
-  console.log(firstPara);
-});
-
-pageWorker.port.emit("get-first-para");
- -
// content-script.js
-
-self.port.on("get-first-para", getFirstPara);
-
-function getFirstPara() {
-  var paras = document.getElementsByTagName("p");
-  if (paras.length > 0) {
-    var firstPara = paras[0].textContent;
-    self.port.emit("first-para", firstPara);
-  }
-}
- -

page-mod

- -

单个 page-mod 对象可以附加它的脚本到多个页面,每个页面有它自己的上下文来运行内容脚本,所以每个页面都需要相互隔离的通道(worker)。

- -

所以 page-mod 没有直接整合 worker 的 API。而是在每次内容脚本被附加到页面时,page-mod 发送一个 attach 事件,它的监听器会给对应的上下文传递一个 worker。通过为 attach 提供一个监听器,你可以访问被一个 page-mod 附加到页面上的内容脚本的 port 对象:

- -
// main.js
-
-var pageMods = require("sdk/page-mod");
-var self = require("sdk/self");
-
-var pageMod = pageMods.PageMod({
-  include: ['*'],
-  contentScriptFile: self.data.url("content-script.js"),
-  onAttach: startListening
-});
-
-function startListening(worker) {
-  worker.port.on('click', function(html) {
-    worker.port.emit('warning', 'Do not click this again');
-  });
-}
- -
// content-script.js
-
-window.addEventListener('click', function(event) {
-  self.port.emit('click', event.target.toString());
-  event.stopPropagation();
-  event.preventDefault();
-}, false);
-
-self.port.on('warning', function(message) {
-  window.alert(message);
-});
-
- -

上面的 add-on 里有两条消息:

- -
    -
  • 当用户点击页面元素时,click 从 page-mod 被发送到当前 add-on。
  • -
  • warning 发送一条傻气的字符串回给page-mod
  • -
- -

Tab.attach()

- -

Tab.attach() 方法返回一个 worker,你可以用来和附加的内容脚本通信。

- -

这个 add-on 添加了一个按钮到Firefox:等用户点击按钮是,这个 add-on 附加一个内容脚本到当前的标签页,发送给内容脚本一条名为 "my-addon-message"的消息,并且监听名为"my-script-response"的响应:

- -
//main.js
-
-var tabs = require("sdk/tabs");
-var buttons = require("sdk/ui/button/action");
-var self = require("sdk/self");
-
-buttons.ActionButton({
-  id: "attach-script",
-  label: "Attach the script",
-  icon: "./icon-16.png",
-  onClick: attachScript
-});
-
-function attachScript() {
-  var worker = tabs.activeTab.attach({
-    contentScriptFile: self.data.url("content-script.js")
-  });
-  worker.port.on("my-script-response", function(response) {
-    console.log(response);
-  });
-  worker.port.emit("my-addon-message", "Message from the add-on");
-}
-
- -
// content-script.js
-
-self.port.on("my-addon-message", handleMessage);
-
-function handleMessage(message) {
-  alert(message);
-  self.port.emit("my-script-response", "Response from content script");
-}
- -

port的API

- -

参看 port 对象的参考文档.

-
- -

postMessage的API

- -

port 对象加载之前,add-on 代码和内容脚本可以使用另一个 API 通信:

- - - -

这个API依然可用,并且还有文档,但是没有理由替代前文描述的 port API。 例外是 context-menu 模块,它还是使用 postMessage。

- -

内容脚本的内容脚本

- -

内容脚本可用直接和其他同一个上下文中的内容脚本通信。举个例子,如果一次 Tab.attach() 的调用附加了两个脚本,那么他们可用直接相互查看,就像加载在同一页面内的页面脚本一样。但是如果你调用 Tab.attach() 两次,每次附加一个内容脚本,那么这些内容脚本之间不能通信。你必须使用port API 通过 add-on 的主代码来传递消息。

- -

跨域的内容脚本

- -

默认情况下,内容脚本没有跨域的权限。特别是,它们不能访问在不同 iframe 中的在另外的域名上的内容,也不能发起跨域的 XMLHttpRequests。

- -

但是,你可以把需要的域名添加到 package.json"permissions"键下的 "cross-domain-content"键下,为这些域名打开这些特性。参阅文章跨域内容脚本

-
- -
 
- -
 
diff --git a/files/zh-cn/mozilla/add-ons/sdk/guides/index.html b/files/zh-cn/mozilla/add-ons/sdk/guides/index.html deleted file mode 100644 index 51fbdef445..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/guides/index.html +++ /dev/null @@ -1,115 +0,0 @@ ---- -title: 教程 -slug: Mozilla/Add-ons/SDK/Guides -tags: - - NeedsTranslation - - TopicStub -translation_of: Archive/Add-ons/Add-on_SDK/Guides ---- -

下面列出了一些文章可以加深你对SDK的理解

-
-

投稿者的教程

-
-
-
-
- 起步
-
- 学会如何使用SDK : 编写代码, 调试bug, 提交补丁, 审核项目, 获得帮助.
-
- 模块
-
- 通过SDK学会模块的使用 (以CommonJS为规范), 懂得如何使用 sandboxes 和compartments 提高安全性, 并且了解内置的 SDK module loader (被称为Cuddlefish).
-
- 类 和 继承
-
- 学会继承在JavaScript中的运行机制, 使用构造(constructors)原型(prototypes), 并知道如何使用SDK提供的函数帮助器简化它.
-
-
-
-
-
- 私有成员
-
- 通过 前缀, 闭包, 和WeakMaps 学会私有成员如何在JavaScript中的实现, 使用 命名空间(通常指WeakMaps) 学会SDK如何支持私有成员.
-
- 脚本运行流程
-
- SDK的设计目的是为了使控制网页内容的扩展脚本可以在不同进程的环境中运行. 这篇文章强调了这一设计的特点.
-
-
-
-
-

SDK的基础结构

-
-
-
-
- SDK 模块结构
-
- SDK是可重复使用的 JavaScript 模块. 这里解释了什么是模块, 怎样加载模块, 和SDK模块树的构造.
-
- SDK API 生存周期
-
- 为SDK的API定义生命周期,  包括API稳定性的排名
-
-
-
-
-
- 程序 ID
-
- 程序ID 是扩展独一无二的标识符. 教程解释了如何定义你自己的程序 ID.
-
- Firefox 兼容
-
- 解决不同版本SDK生成的扩展与不同版本Firefox的兼容问题
-
-
-
-
-

SDK 常用技巧

-
-
-
-
- 善用 事件触发
-
- 通过SDK的事件触发框架 写出以事件驱动为基础的代码
-
-
-
-
-
- 脚本的两种类型
-
- 这篇文章可以帮助你理解扩展中的API和普通脚本的区别
-
-
-
-

 

-
-

XUL 迁移

-
-
-
-
- XUL 迁移教程
-
- 把XUL扩展迁移到SDK的技巧
-
- XUL 与 SDK 不同
-
- 比较 传统的以XUL为基础的扩展 和 SDK 两者优点和缺点
-
-
-
-
-
- 移植例子
-
- 一个简单地教你如何让 基于XUL的扩展 迁移到 SDK中的实例
-
-
-
-

 

diff --git a/files/zh-cn/mozilla/add-ons/sdk/guides/multiprocess_firefox_and_the_sdk/index.html b/files/zh-cn/mozilla/add-ons/sdk/guides/multiprocess_firefox_and_the_sdk/index.html deleted file mode 100644 index c22dd0181e..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/guides/multiprocess_firefox_and_the_sdk/index.html +++ /dev/null @@ -1,212 +0,0 @@ ---- -title: 多进程 Firefox 与 SDK -slug: Mozilla/Add-ons/SDK/Guides/Multiprocess_Firefox_and_the_SDK -translation_of: Archive/Add-ons/Add-on_SDK/Guides/Multiprocess_Firefox_and_the_SDK ---- -

我们目前正在使 Firefox 变为多进程,它为浏览器界面使用一个操作系统进程,为运行的网页使用另一个进程来执行代码,这个项目被称为 "electrolysis" 或者 "e10s"。更多信息请参考多进程 Firefox 相关页面

- -

本文章介绍了开发者如何测试基于 SDK 的附加组件是否与多进程的 Firefox 兼容,以及如何解决出现的问题。

- -

SDK 的合约

- -

SDK 为附加组件的开发者承诺了:

- - - -

在实践中,大多数底层 API 将正常工作,但可以直接访问网页内容的底层 API 无法正常工作。

- -

兼容性垫片

- -

举例来说,你可能认为这是行不通的:

- -
var contentDocument = require("sdk/window/utils")
-  .getMostRecentBrowserWindow().content.document;
- -

但是,Firefox 为附加组件提供了许多 API 的兼容性垫片。这意味着许多 API,包括上述例子的那个,仍然工作。虽然有两条警示需注意:

- - - -

We don't yet have a complete list of low-level APIs that are not multiprocess compatible: that is, will not work without the shims. Where we know that a low-level API is not multiprocess compatible, we've indicated that in the documentation page for it.

- -

测试

- -

To test whether an add-on works without the shims, use the "multiprocess" permission.

- -
-

Note that you can only do this if you are using jpm. You can't use the "multiprocess" permission if you are using cfx.

-
- -

Setting this permission will disable the shims for your add-on, so you can test to see if it's really multiprocess compatible or not.

- -

However, there's a catch: some of the SDK's APIs themselves still depend on the shims. So by setting the "multiprocess" permission, your add-on might not work, even if you are only using high-level APIs. For example:

- -
var selection = require("sdk/selection");
-
-function myListener() {
-  console.log(selection.text);
-}
-
-selection.on('select', myListener);
-
- -

This add-on will not work if you've set the "multiprocess" permission, because sdk/selection depends on the shims. We're working on fixing these problems: see bug 1004745 and its dependencies.

- -

使用框架脚本

- -

If the shims don't enable your add-on to work properly, or you're trying to remove your dependency on the shims, then the solution is the same as it is for all add-ons:

- - - -

In the rest of this section we'll outline some SDK-specific details of using the message manager. However, you'll also need to read the main message manager documentation for the details on working with frame scripts.

- -
-

If you're used to working with content scripts in the SDK, then frame scripts might feel similar, but they're actually very different. Frame scripts are more like a part of the main add-on code that just happens to be running in the content process.

- -

Differences between frame scripts and content scripts include:

- - -
- -

访问消息管理器

- -

全局消息管理器

- -

To access the global message manager, you load the nsIMessageListenerManager service. Before you can do this in an SDK add-on, you have to require("chrome") to get access to the Components object:

- -
const {Cc, Ci} = require("chrome");
-
-var globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
-  .getService(Ci.nsIMessageListenerManager);
- -

窗口消息管理器

- -

The window message manager is available as the messageManager property of a chrome window. To understand what a chrome window is, you need to distinguish three sorts of windows:

- - - -

So to get a window message manager from the SDK, you have a couple of options:

- -

(1) Use the window/utils module:

- -
// Note that although this code uses window/utils,
-// it's safe to run in the chrome process because
-// it only accesses chrome objects.
-
-// get the active chrome window
-var browserWindow = require("sdk/window/utils").getMostRecentBrowserWindow();
-
-var windowMM = browserWindow.messageManager;
- -

(2) Use viewFor to convert an SDK window to a chrome window:

- -
// get the active SDK window
-var windows = require("sdk/windows").browserWindows;
-var activeWindow = windows.activeWindow;
-
-// convert it to a chrome window
-var browserWindow = require("sdk/view/core").viewFor(activeWindow);
-
-var windowMM = browserWindow.messageManager;
- -

浏览器消息管理器

- -

The browser message manager is available as the messageManager property of an XUL browser.

- -

In the SDK, to get a browser for a given tab, you can use the tabs/utils module's getBrowserForTab function. getBrowserForTab expects an XUL tab as an argument, so if you have an SDK tab object, you'll need to convert it to an XUL tab using viewFor:

- -
// get the active SDK tab
-var tab = require("sdk/tabs").activeTab;
-// convert it to an XUL tab
-var xulTab = require("sdk/view/core").viewFor(tab);
-// get the XUL browser for this tab
-var xulBrowser = require("sdk/tabs/utils").getBrowserForTab(xulTab);
-
-var browserMM = xulBrowser.messageManager;
- -

Again, although this code uses tabs/utils, it's safe to run in the chrome process because it only accesses chrome objects.

- -

载入框架脚本

- -

You can load frame scripts using the message manager, passing in a chrome:// or resource:// URL pointing to the script. With the SDK, the simplest approach is to keep frame scripts under your add-on's data directory, and pass in a resource:// URL created using self.data.url:

- -
const self = require("sdk/self");
-
-messageManager.loadFrameScript(self.data.url("frame-script.js"), false);
- -

Note that unlike the APIs to load content scripts, you can only load a single frame script here.

- -

例子

- -

For example, this add-on trivially accesses content directly using a low-level API:

- -
function logContent() {
-  var contentDocument = require("sdk/window/utils")
-    .getMostRecentBrowserWindow().content.document;
-  console.log(contentDocument.body.innerHTML);
-}
-
-require("sdk/ui/button/action").ActionButton({
-  id: "log-content",
-  label: "Log Content",
-  icon: "./icon-16.png",
-  onClick: logContent
-});
- -

This add-on will work by default due to the shims, but will break if you set multiprocessCompatible. So you could rewrite the add-on to use frame scripts:

- -
/*
-frame-script.js is in the "data" directory, and has this content:
-
-sendAsyncMessage("sdk-low-level-apis-e10s@jetpack:got-content",
-                 content.document.body.innerHTML);
-
-*/
-
-const self = require("sdk/self");
-
-function logContentAsync() {
-  var tab = require("sdk/tabs").activeTab;
-  var xulTab = require("sdk/view/core").viewFor(tab);
-  var xulBrowser = require("sdk/tabs/utils").getBrowserForTab(xulTab);
-
-  var browserMM = xulBrowser.messageManager;
-  browserMM.loadFrameScript(self.data.url("frame-script.js"), false);
-  browserMM.addMessageListener("sdk-low-level-apis-e10s@jetpack:got-content",
-                               logContent);
-}
-
-function logContent(message) {
-  console.log(message.data);
-}
-
-require("sdk/ui/button/action").ActionButton({
-  id: "log-content",
-  label: "Log Content",
-  icon: "./icon-16.png",
-  onClick: logContentAsync
-});
- -

现在附加组件能正常工作了,即使你设置了 multiprocessCompatible。

diff --git a/files/zh-cn/mozilla/add-ons/sdk/guides/working_with_events/index.html b/files/zh-cn/mozilla/add-ons/sdk/guides/working_with_events/index.html deleted file mode 100644 index 4c24b84e13..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/guides/working_with_events/index.html +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: Working with Events -slug: Mozilla/Add-ons/SDK/Guides/Working_with_Events -translation_of: Archive/Add-ons/Add-on_SDK/Guides/Working_with_Events ---- -

The Add-on SDK supports event-driven programming.

-

Objects emit events on state changes that might be of interest to add-on code, such as browser windows opening, pages loading, network requests completing, and mouse clicks. By registering a listener function to an event emitter an add-on can receive notifications of these events.

-

We talk about content scripts in more detail in the Working with Content Scripts guide.

-

Additionally, if you're using content scripts to interact with web content, you can define your own events and use them to communicate between the main add-on code and the content scripts. In this case one end of the conversation emits the events, and the other end listens to them.

-

So there are two main ways you will interact with the EventEmitter framework:

- -

This guide only covers the first of these; the second is explained in the Working with Content Scripts guide.

-

Adding Listeners

-

You can add a listener to an event emitter by calling its on(type, listener) method.

-

It takes two parameters:

- -

For example, the following add-on registers a listener with the tabs module to listen for the ready event, and logs a string to the console reporting the event:

-
var tabs = require("sdk/tabs");
-
-tabs.on("ready", function () {
-  console.log("tab loaded");
-});
-
-

It is not possible to enumerate the set of listeners for a given event.

-

The value of this in the listener function is the object that emitted the event.

-

Listening to all events

-
-

This example uses the action button API, which is only available from Firefox 29 onwards.

-
-

From Firefox 28 onwards, you can pass the wildcard "*" as the type argument. If you do this, the listener will be called for any event emitted by that object, and its argument will be the name of the event:

-
var ui = require('sdk/ui');
-var panels = require("sdk/panel");
-var self = require("sdk/self");
-
-var panel = panels.Panel({
-  contentURL: self.data.url("panel.html")
-});
-
-panel.on("*", function(e) {
-  console.log("event " + e + " was emitted");
-});
-
-var button = ui.ActionButton({
-  id: "my-button",
-  label: "my button",
-  icon: "./icon-16.png",
-  onClick: handleClick
-});
-
-function handleClick(state) {
-  panel.show({
-    position: button
-  });
-}
-

This wildcard feature does not yet work for the tabs or windows modules.

-

Adding Listeners in Constructors

-

Event emitters may be modules, as is the case for the ready event above, or they may be objects returned by constructors.

-

In the latter case the options object passed to the constructor typically defines properties whose names are the names of supported event types prefixed with "on": for example, "onOpen", "onReady" and so on. Then in the constructor you can assign a listener function to this property as an alternative to calling the object's on() method.

-

For example: the ActionButton object emits an event when the button is clicked.

-

The following add-on creates a button and assigns a listener to the onClick property of the options object supplied to the button's constructor. The listener loads https://developer.mozilla.org/:

-
require("sdk/ui/button/action").ActionButton({
-  id: "visit-mozilla",
-  label: "Visit Mozilla",
-  icon: "./icon-16.png",
-  onClick: function() {
-    require("sdk/tabs").open("https://developer.mozilla.org/");
-  }
-});
-
-

This is exactly equivalent to constructing the button and then calling the button's on() method:

-
var button = require("sdk/ui/button/action").ActionButton({
-  id: "visit-mozilla",
-  label: "Visit Mozilla",
-  icon: "./icon-16.png"
-});
-
-button.on("click", function() {
-  require("sdk/tabs").open("https://developer.mozilla.org/");
-});
-
-

Removing Event Listeners

-

Event listeners can be removed by calling removeListener(type, listener), supplying the type of event and the listener to remove.

-

The listener must have been previously been added using one of the methods described above.

-

In the following add-on, we add two listeners to the tabs module's ready event. One of the handler functions removes the listener again.

-

Then we open two tabs.

-
var tabs = require("sdk/tabs");
-
-function listener1() {
-  console.log("Listener 1");
-  tabs.removeListener("ready", listener1);
-}
-
-function listener2() {
-  console.log("Listener 2");
-}
-
-tabs.on("ready", listener1);
-tabs.on("ready", listener2);
-
-tabs.open("https://www.mozilla.org");
-tabs.open("https://www.mozilla.org");
-
-

We should see output like this:

-
info: tabevents: Listener 1
-info: tabevents: Listener 2
-info: tabevents: Listener 2
-
-

Listeners will be removed automatically when the add-on is unloaded.

diff --git a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/base64/index.html b/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/base64/index.html deleted file mode 100644 index bbde3e418f..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/base64/index.html +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: base64 -slug: Mozilla/Add-ons/SDK/High-Level_APIs/base64 -translation_of: Archive/Add-ons/Add-on_SDK/High-Level_APIs/base64 ---- -

{{AddonSidebar}}

- -
-

不稳定

-
- -

使用Base64算法编码和解码数据

- -
var base64 = require("sdk/base64");
-
-var encodedData = base64.encode("Hello, World");//"SGVsbG8sIFdvcmxk"
-var decodedData = base64.decode(encodedData);//"Hello, World"
- -

Globals

- -

函数

- -

encode(data, charset)

- -

将数据编码成ASCII的Base64字符串。

- -
参数
- -

data : string
- 需要被编码的字符串

- -

charset : string
- 字符串的编码字符集(可选)。唯一能接受的值“UTF-8”。为了进行编码和解码Unicode字符串,需要设置字符集参数:

- -
var base64 = require("sdk/base64");
-
-var encodedData = base64.encode(unicodeString, "utf-8");
-
- -
返回
- -

string : 编码后的Base64字符串。

- -

decode(data, charset)

- -

解码一个已使用base-64编码的数据字符串

- -
参数
- -

data : string
- 需要被解码的字符串

- -

charset : string
- 字符串的编码字符集(可选)。唯一能接受的值“UTF-8”。为了进行编码和解码Unicode字符串,需要设置字符集参数:

- -
var base64 = require("sdk/base64");
-
-var decodedData = base64.decode(encodedData, "utf-8");
-
- -
返回
- -

string : 解码后的字符串

- -
 
diff --git a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/clipboard/index.html b/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/clipboard/index.html deleted file mode 100644 index e56a9223cd..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/clipboard/index.html +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: clipboard(剪贴板) -slug: Mozilla/Add-ons/SDK/High-Level_APIs/clipboard -translation_of: Archive/Add-ons/Add-on_SDK/High-Level_APIs/clipboard ---- -

{{AddonSidebar}}

- -
-

稳定版

-
- -

操作系统剪贴板,设置或获取其内容

- -

用法

- -

你可以选择性地设置将要获取或设置的内容的格式. 支持一下格式:

- - - -

如果没有提供格式参数的话,剪贴板模块会自动检测。

- -

现在在Windows操作系统下,"image"格式并不支持透明度。

- -

示例

- -

设置和获取剪贴板内容。

- -
var clipboard = require("sdk/clipboard");
-clipboard.set("Lorem ipsum dolor sit amet");
-var contents = clipboard.get();
- -

将剪贴板内容设置为某些html。

- -
var clipboard = require("sdk/clipboard");
-clipboard.set("<blink>Lorem ipsum dolor sit amet</blink>", "html");
- -

如果剪贴板内容中包含有html,则将其在新标签页中打开。

- -
var clipboard = require("sdk/clipboard");
-if (clipboard.currentFlavors.indexOf("html") != -1)
-  require("sdk/tabs").open("data:text/html;charset=utf-8," + clipboard.get("html"));
- -

将剪贴板内容设置为一幅图片。

- -
var clipboard = require("sdk/clipboard");
-clipboard.set("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYA" +
-              "AABzenr0AAAASUlEQVRYhe3O0QkAIAwD0eyqe3Q993AQ3cBSUKpygfsNTy" +
-              "N5ugbQpK0BAADgP0BRDWXWlwEAAAAAgPsA3rzDaAAAAHgPcGrpgAnzQ2FG" +
-              "bWRR9AAAAABJRU5ErkJggg%3D%3D");
- -

如果剪贴板内容中包含图片,则将其在新标签页中打开。

- -
var clipboard = require("sdk/clipboard");
-if (clipboard.currentFlavors.indexOf("image") != -1)
-  require("sdk/tabs").open(clipboard.get());
- -

如前所述,图片的参数类型很容易被忽略,例如在网页中选中复制一张图片,得到的格式会是html而不是所预期的image。如果你是想将剪贴板的内容设置成像data URL这样的文本字符串而不是图片的话,可以通过将格式设置为text实现。

- -
var clipboard = require("sdk/clipboard");
-
-clipboard.set("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYA" +
-              "AABzenr0AAAASUlEQVRYhe3O0QkAIAwD0eyqe3Q993AQ3cBSUKpygfsNTy" +
-              "N5ugbQpK0BAADgP0BRDWXWlwEAAAAAgPsA3rzDaAAAAHgPcGrpgAnzQ2FG" +
-              "bWRR9AAAAABJRU5ErkJggg%3D%3D", "text");
- -

Globals

- -

函数

- -

set(data, datatype)

- -

将用户剪贴板上的内容用data替换。

- -
参数
- -

data : string
- 要放入剪贴板的内容。

- -

datatype : string
- 内容的格式 ,为"text"或"html" 或 "image"。可选参数.

- -

get(datatype)

- -

获取用户当前剪贴板的内容。

- -
参数
- -

datatype : string
- 只有当剪贴板中的内容格式为datatype指定的格式时才获取 (可选).。当剪贴板中的内容非所提供的datatype指定的格式时,函数回返回null。

- -

属性

- -

currentFlavors

- -

剪贴板上的内容有时会是多种格式。例如,HTML内容即能匹配HTML格式(html),又能匹配纯文本格式(text)。这个属性为一个数组,数组中的元素是剪贴板内容所匹配的所有格式,如["text","html"]。

- -
 
diff --git a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/index.html b/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/index.html deleted file mode 100644 index d0d7bd569a..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/index.html +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: High-Level APIs -slug: Mozilla/Add-ons/SDK/High-Level_APIs -translation_of: Archive/Add-ons/Add-on_SDK/High-Level_APIs ---- -

{{AddonSidebar}}

- -

此页面列出的模块使用的是高级的API:创建用户界面,与网络进行交互并与浏览器交互。

- -

除非文件明确说明,否则这些API是稳定的,我们避免做出不兼容的改变。 - -{{ LandingPageListSubpages ("/en-US/Add-ons/SDK/High-Level_APIs", 5) }}

diff --git a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/notifications/index.html b/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/notifications/index.html deleted file mode 100644 index 415450dca7..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/notifications/index.html +++ /dev/null @@ -1,129 +0,0 @@ ---- -title: notifications(通知) -slug: Mozilla/Add-ons/SDK/High-Level_APIs/notifications -tags: - - Add-on SDK - - 通知 -translation_of: Archive/Add-ons/Add-on_SDK/High-Level_APIs/notifications ---- -

{{AddonSidebar}}

- -
-

Stable

-
- -

向用户展示短暂的 toaster 风格的桌面消息。

- -

用法

- -

本 API 支持Windows、使用Growl(或者像OS X 10.9 Mavericks那样的通知中心)的 OS X 的桌面通知,以及使用 libnotify 的Linux系统

- -

这儿有个典型的例子。当消息被点击,控制台上回记录一个字符串。

- -
var notifications = require("sdk/notifications");
-notifications.notify({
-  title: "Jabberwocky",
-  text: "'Twas brillig, and the slithy toves",
-  data: "did gyre and gimble in the wabe",
-  onClick: function (data) {
-    console.log(data);
-    // console.log(this.data) would produce the same result.
-  }
-});
-
- -

下面这个示例用来展示一个保存在 add-on 的 data 目录下的图标。参看 self 模块文档以获取更多信息。

- -
var notifications = require("sdk/notifications");
-var self = require("sdk/self");
-var myIconURL = self.data.url("myIcon.png");
-
-notifications.notify({
-  text: "I have an icon!",
-  iconURL: myIconURL
-});
- -
-

从 Firefox 34 起,你能使用 "./myIcon.png" 作为 self.data.url("myIcon.png") 的别名。所以你也可以把上面的代码重写成这样:

- -
var notifications = require("sdk/notifications");
-var myIconURL = "./myIcon.png";
-
-notifications.notify({
-  text: "I have an icon!",
-  iconURL: myIconURL
-});
-
- -

本模块依赖于底层系统的通知服务。如果用户的系统不支持桌面通知或者通知服务没有运行:

- - - -

Globals

- -

函数

- -

notify(options)

- -

向用户展示一个短暂的通知

- -
参数
- -

options : object
- 可选项:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameType 
titlestring -

作为消息标题的字符串。

-
text作为消息体的字符串。 -

 

-
iconURLstring -

消息里的图标的 URL 。可以是个远程的、本地的或者使用 self 模块的 URL。

-
onClickfunction -

用户点击消息是调用的函数。它会传递一个 data 值。

-
datastring -

传递给 onClick 的字符串。

-
- -
 
- -
 
- -
 
diff --git a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/panel/index.html b/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/panel/index.html deleted file mode 100644 index 3a86fb0c61..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/panel/index.html +++ /dev/null @@ -1,899 +0,0 @@ ---- -title: panel -slug: Mozilla/Add-ons/SDK/High-Level_APIs/panel -translation_of: Archive/Add-ons/Add-on_SDK/High-Level_APIs/panel ---- -
-

稳定版本

-
- -

创建临时的 add-on's 用户界面对话框.

- -

用法

- -

该模块导出了一个单独的构造函数函数 Panel() 构建一个Panel对话框 .

- -

面板是一个对话框。其内容是指定的HTML,你可以在它执行脚本,所以面板的外观和行为是有限的只有你可以使用HTML,CSS,JavaScript。

- -

下面的截图显示了一个面板,其内容是从当前打开的选项卡的列表中构建的:

- -

- -

面板是呈现临时用户界面中容易忽视和解聘的用户比模态对话框的方式,是有用的,因为面板隐藏瞬间用户交互部分的应用程序接口外。

- -


- 面板的内容加载快作为它是创建,面板显示之前,和内容仍然加载时面板是隐藏的,所以它是可能保持面板周围的背景,更新其内容适当地准备下一次显示。

- -


- 您的插件可以接收通知,当面板显示或隐藏通过听其显示和隐藏事件。
- 打开面板将关闭已打开的面板。

- -

Panel 内容

- -

该面板的内容指定为HTML,它是在contenturl选项面板的构造函数提供的URL加载。

- -


- 你可以加载远程HTML到面板:

- -
var panel = require("sdk/panel").Panel({
-  width: 180,
-  height: 180,
-  contentURL: "https://en.wikipedia.org/w/index.php?title=Jetpack&useformat=mobile"
-});
-
-panel.show();
- -

- -

你也可以加载HTML已经打包你的 add-on,这可能是你将如何创建对话框。要做到这一点,在你的 add-on 的 data 目录中保存的HTML 和加载使用 data.url()方法,由 self 模块导出, 像下面:

- -
var panel = require("sdk/panel").Panel({
-  contentURL: require("sdk/self").data.url("myFile.html")
-});
-
-panel.show();
- -
-

从Firefox 34以后, 你可以使用 "./myFile.html" 作为self.data.url("myFile.html")别名. 所以你可以重写成下面的示例:

- -
var panel = require("sdk/panel").Panel({
-  contentURL: "./myFile.html"
-});
-
-panel.show();
-
-
- -

Panel positioning

- -

By default the panel appears in the center of the currently active browser window. You can position the panel by passing a position to the panel's constructor or to its show() method.

- -

Attaching panels to buttons

- -

You can attach a panel to a toggle button by passing the button itself as the position option to the panel's show() method or to its constructor:

- -
var { ToggleButton } = require('sdk/ui/button/toggle');
-var panels = require("sdk/panel");
-var self = require("sdk/self");
-
-var button = ToggleButton({
-  id: "my-button",
-  label: "my button",
-  icon: {
-    "16": "./icon-16.png",
-    "32": "./icon-32.png",
-    "64": "./icon-64.png"
-  },
-  onChange: handleChange
-});
-
-var panel = panels.Panel({
-  contentURL: self.data.url("panel.html"),
-  onHide: handleHide
-});
-
-function handleChange(state) {
-  if (state.checked) {
-    panel.show({
-      position: button
-    });
-  }
-}
-
-function handleHide() {
-  button.state('window', {checked: false});
-}
- -

- -

Updating panel content

- -

You can update the panel's content by:

- - - -

Scripting panel content

- -

You can't directly access your panel's content from your main add-on code. To access the panel's content, you need to load a script into the panel. In the SDK these scripts are called "content scripts" because they're explicitly used for interacting with web content.

- -

While content scripts can access the content they're attached to, they can't use the SDK's APIs. So implementing a complete solution usually means you have to send messages between the content script and the main add-on code.

- - - -

For example, here's an add-on whose content script intercepts mouse clicks on links inside the panel, and sends the target URL to the main add-on code. The content script sends messages using self.port.emit() and the add-on script receives them using panel.port.on().

- -
var myScript = "window.addEventListener('click', function(event) {" +
-               "  var t = event.target;" +
-               "  if (t.nodeName == 'A')" +
-               "    self.port.emit('click-link', t.toString());" +
-               "}, false);"
-
-var panel = require("sdk/panel").Panel({
-  contentURL: "http://www.bbc.co.uk/mobile/index.html",
-  contentScript: myScript
-});
-
-panel.port.on("click-link", function(url) {
-  console.log(url);
-});
-
-panel.show();
- -

This example uses contentScript to supply the script as a string. It's usually better practice to use contentScriptFile, which is a URL pointing to a script file saved under your add-on's data directory.

- -
-

Warning: Unless your content script is extremely simple and consists only of a static string, don't use contentScript: if you do, you may have problems getting your add-on approved on AMO.

- -

Instead, keep the script in a separate file and load it using contentScriptFile. This makes your code easier to maintain, secure, debug and review.

-
- -

Getting user input

- -
-

Note: This example uses the action button API, which is only available from Firefox 29 onwards.

-
- -

The following add-on adds a button which displays a panel when clicked. The panel just contains a {{HTMLElement("textarea")}} element: when the user presses the return key, the contents of the <textarea> is sent to the main add-on code.

- -

- -

The add-on consists of six files:

- - - -

"main.js" is saved in your add-on's lib directory, and the other files go in your add-on's data directory:

- -
my-addon/
-         data/
-              get-text.js
-              icon-16.png
-              icon-32.png
-              icon-64.png
-              text-entry.html
-         lib/
-             main.js
-
- -

The "main.js" looks like this:

- -
var data = require("sdk/self").data;
-// Construct a panel, loading its content from the "text-entry.html"
-// file in the "data" directory, and loading the "get-text.js" script
-// into it.
-var text_entry = require("sdk/panel").Panel({
-  contentURL: data.url("text-entry.html"),
-  contentScriptFile: data.url("get-text.js")
-});
-
-// Create a button
-require("sdk/ui/button/action").ActionButton({
-  id: "show-panel",
-  label: "Show Panel",
-  icon: {
-    "16": "./icon-16.png",
-    "32": "./icon-32.png",
-    "64": "./icon-64.png"
-  },
-  onClick: handleClick
-});
-
-// Show the panel when the user clicks the button.
-function handleClick(state) {
-  text_entry.show();
-}
-
-// When the panel is displayed it generated an event called
-// "show": we will listen for that event and when it happens,
-// send our own "show" event to the panel's script, so the
-// script can prepare the panel for display.
-text_entry.on("show", function() {
-  text_entry.port.emit("show");
-});
-
-// Listen for messages called "text-entered" coming from
-// the content script. The message payload is the text the user
-// entered.
-// In this implementation we'll just log the text to the console.
-text_entry.port.on("text-entered", function (text) {
-  console.log(text);
-  text_entry.hide();
-});
- -

The content script "get-text.js" looks like this:

- -
// When the user hits return, send the "text-entered"
-// message to main.js.
-// The message payload is the contents of the edit box.
-var textArea = document.getElementById("edit-box");
-textArea.addEventListener('keyup', function onkeyup(event) {
-  if (event.keyCode == 13) {
-    // Remove the newline.
-    text = textArea.value.replace(/(\r\n|\n|\r)/gm,"");
-    self.port.emit("text-entered", text);
-    textArea.value = '';
-  }
-}, false);
-// Listen for the "show" event being sent from the
-// main add-on code. It means that the panel's about
-// to be shown.
-//
-// Set the focus to the text area so the user can
-// just start typing.
-self.port.on("show", function onShow() {
-  textArea.focus();
-});
- -

Finally, the "text-entry.html" file defines the <textarea> element:

- -
<html>
-<head>
-    <style type="text/css" media="all">
-      textarea {
-        margin: 10px;
-      }
-      body {
-        background-color: gray;
-      }
-    </style>
-  </head>
-<body>
-    <textarea rows="13" cols="33" id="edit-box"></textarea>
-  </body>
-</html>
- -

Finally, save these three icon files to the "data" directory:

- - - - - - - - - - - - - - - - -
icon-16.png
icon-32.png
icon-64.png
- -

To learn much more about content scripts, see the Working with Content Scripts guide.

- -

Scripting trusted panel content

- -
-

Note: This example uses the action button API, which is only available from Firefox 29 onwards.

-
- -

We've already seen that you can package HTML files in your add-on's data directory and use them to define the panel's content. We can call this "trusted" content, because unlike content loaded from a source outside the add-on, the add-on author knows exactly what it's doing. To interact with trusted content you don't need to use content scripts: you can just include a script from the HTML file in the normal way, using script tags.

- -

Like a content script, these scripts can communicate with the add-on code using the postMessage() API or the port API. The crucial difference is that these scripts access the postMessage and port objects through the addon object, whereas content scripts access them through the self object.

- -

To show the difference, we can easily convert the text-entry add-on above to use normal page scripts instead of content scripts.

- -

The main add-on code is exactly the same as the main add-on code in the previous example, except that we don't attach a content script:

- -
var data = require("sdk/self").data;
-// Construct a panel, loading its content from the "text-entry.html"
-// file in the "data" directory, and loading the "get-text.js" script
-// into it.
-var text_entry = require("sdk/panel").Panel({
-  contentURL: data.url("text-entry.html")
-});
-
-// Create a button
-require("sdk/ui/button/action").ActionButton({
-  id: "show-panel",
-  label: "Show Panel",
-  icon: {
-    "16": "./icon-16.png",
-    "32": "./icon-32.png",
-    "64": "./icon-64.png"
-  },
-  onClick: handleClick
-});
-
-// Show the panel when the user clicks the button.
-function handleClick(state) {
-  text_entry.show();
-}
-
-// When the panel is displayed it generated an event called
-// "show": we will listen for that event and when it happens,
-// send our own "show" event to the panel's script, so the
-// script can prepare the panel for display.
-text_entry.on("show", function() {
-  text_entry.port.emit("show");
-});
-
-// Listen for messages called "text-entered" coming from
-// the content script. The message payload is the text the user
-// entered.
-// In this implementation we'll just log the text to the console.
-text_entry.port.on("text-entered", function (text) {
-  console.log(text);
-  text_entry.hide();
-});
- -

The page script is exactly the same as the content script above, except that instead of self, we use addon to access the messaging APIs:

- -
// When the user hits return, send the "text-entered"
-// message to main.js.
-// The message payload is the contents of the edit box.
-var textArea = document.getElementById("edit-box");
-textArea.addEventListener('keyup', function onkeyup(event) {
-  if (event.keyCode == 13) {
-    // Remove the newline.
-    text = textArea.value.replace(/(\r\n|\n|\r)/gm,"");
-    addon.port.emit("text-entered", text);
-    textArea.value = '';
-  }
-}, false);
-// Listen for the "show" event being sent from the
-// main add-on code. It means that the panel's about
-// to be shown.
-//
-// Set the focus to the text area so the user can
-// just start typing.
-addon.port.on("show", function onShow() {
-  textArea.focus();
-});
- -

Finally, the HTML file now references "get-text.js" inside a {{HTMLElement("script")}} tag:

- -
<html>
-<head>
-    <style type="text/css" media="all">
-      textarea {
-        margin: 10px;
-      }
-      body {
-        background-color: gray;
-      }
-    </style>
-  </head>
-  <body>
-    <script src="get-text.js"></script>
-    <textarea rows="13" cols="33" id="edit-box"></textarea>
-  </body>
-</html>
-
- -

Styling panel content

- -

The panel's default style is different for each operating system:

- -

This helps to ensure that the panel's style is consistent with the dialogs displayed by Firefox and other applications, but means you need to take care when applying your own styles.

- -

If the panel's content is packaged along with your add-on and specified using an HTML file in your data directory, you can style it by embedding CSS directly in the HTML file or by referencing a CSS file stored under data:

- -
<!DOCTYPE HTML>
-<html>
-  <head>
-    <link href="panel-style.css" type="text/css" rel="stylesheet">
-  </head>
-  <body>
-    My panel content
-  </body>
-</html>
- -

From Firefox 31 onwards, you can style panel content using the contentStyle or contentStyleFile options. You can use these options even if the panel content is not packaged along with the add-on:

- -
var panel = require("sdk/panel").Panel({
-  contentURL: "https://en.wikipedia.org/w/index.php?title=Jetpack&useformat=mobile",
-  contentStyle: "body { border: 3px solid blue; }"
-});
-
-panel.show();
- -
var self = require("sdk/self");
-
-var panel = require("sdk/panel").Panel({
-  contentURL: "https://en.wikipedia.org/w/index.php?title=Jetpack&useformat=mobile",
-  contentStyleFile: self.data.url("panel-style.css")
-});
-
-panel.show();
- -

Private browsing

- -

If your add-on has not opted into private browsing, and it calls panel.show() when the currently active window is a private window, then the panel will not be shown.

- -

Panel limitations

- -

Although panels can host HTML documents, they are not implemented as browser tabs, so many things that work in normal web pages do not work inside panels:

- - - -

Globals

- -

Constructors

- -

Panel(options)

- -

Creates a panel.

- -
Parameters
- -

options : object
- Optional options:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameType 
widthnumber -

The width of the panel in pixels. Optional.

-
heightnumber -

The height of the panel in pixels. Optional.

-
position -

object, button, widget

-
-

The position of the panel. Ignored if the panel is opened by a widget.

- -

This may be one of three things:

- -
    -
  • a toggle button. If this is supplied the panel will be shown attached to the button. See the section on attaching panels to buttons.
  • -
  • a widget object. If this is supplied the panel will be shown attached to the widget.
  • -
  • an object which specifies where in the window the panel should be shown. The rest of this section describes this object.
  • -
- -

The position object has one or more of the following properties: top, right, bottom and left. Their values are expressed in pixels. Any other properties will be ignored.

- -

The default alignment along each axis is centered: so to display a panel centred along the vertical or horizontal axis, just omit that axis:

- -
-// Show the panel centered horizontally and
-// aligned to the bottom of the content area
-require("sdk/panel").Panel({
-  position: {
-   bottom: 0
-  }
-}).show();
-
-// Show the panel centered vertically and
-// aligned to the left of the content area
-require("sdk/panel").Panel({
-  position: {
-    left: 0
-  }
-}).show();
-
-// Centered panel, default behavior
-require("sdk/panel").Panel({}).show();
- -

As with the CSS top, bottom, left, and right properties, setting both top and bottom or both left and right will implicitly set the panel's height or width relative to the content window:

- -
-// Show the panel centered horizontally, with:
-// - the top edge 40px from the top
-// of the content window
-// - the bottom edge 100px from the bottom
-// of the content window
-require("sdk/panel").Panel({
-  position: {
-    top: 40,
-    bottom: 100
-  }
-}).show();
- -

If you set both top and bottom, but also set the panel's height explicitly using the height property, then the panel will ignore bottom, just as CSS does for its properties with the same name:

- -
-// Show the panel centered horizontally, with:
-// - the top edge 40px from the top
-// of the content window
-// - a height of 400px
-require("sdk/panel").Panel({
-  position: {
-    top: 40,
-    bottom: 100,
-  },
-  height: 400
-}).show();
-
-// This is equivalent to:
-
-require("panel").Panel({
-  position {
-    top: 40
-  },
-  height: 400
-}).show();
- -

The same principle is applied in the horizontal axis with width, left and right.

-
focusboolean -

Set to false to prevent taking the focus away when the panel is shown. Only turn this off if necessary, to prevent accessibility issue. Optional, default to true.

-
contentURLstring,URL -

The URL of the content to load in the panel. That is, they can't refer to remote scripts. The URLs are usually constructed using self.data.url().

- -
-

From Firefox 34, you can use "./my-file.html" as an alias for self.data.url("my-file.html").

-
-
allowobject -

An optional object describing permissions for the content. It should contain a single key named script whose value is a boolean that indicates whether or not to execute script in the content. script defaults to true.

-
contentScriptFilestring,array -

A URL or an array of URLs. The URLs point to scripts to load into the panel.

- -

The scripts must be packaged with the add-on under the add-on's data directory. That is, they can't refer to remote scripts. The URLs are usually constructed using self.data.url().

- -
-

From Firefox 34, you can use "./my-script.js" as an alias for self.data.url("my-script.js").

-
- -

Content scripts specified by this property are loaded before those specified by the contentScript property.

-
contentScriptstring,array -

A string or an array of strings containing the texts of content scripts to load. Content scripts specified by this property are loaded after those specified by the contentScriptFile property.

-
contentStyleFilestring, array -

A URL or an array of URLs. The URLs point to CSS stylesheets to load into the panel.

- -

The stylesheets must be packaged with the add-on under the add-on's data directory. That is, they can't refer to remote stylesheets. The URLs are usually constructed using self.data.url().

- -

Stylesheets specified by this property are loaded before those specified by the contentStyle property.

-
contentStylestring, array -

A string or an array of strings containing the texts of stylesheets to load. Stylesheets specified by this property are loaded after those specified by the contentStyleFile property.

-
contentScriptWhenstring -

When to load the content scripts. This may take one of the following values:

- -
    -
  • "start": load content scripts immediately after the document element for the panel is inserted into the DOM, but before the DOM content itself has been loaded
  • -
  • "ready": load content scripts once DOM content has been loaded, corresponding to the DOMContentLoaded event
  • -
  • "end": load content scripts once all the content (DOM, JS, CSS, images) for the panel has been loaded, at the time the window.onload event fires
  • -
- -

This property is optional and defaults to "end".

-
contentScriptOptionsobject -

Read-only value exposed to content scripts under addon.options property.

- -

Any kind of jsonable value (object, array, string, etc.) can be used here. Optional.

-
contextMenuboolean -
-

New in Firefox 33

-
- -

Whether to show a context menu when the user context-clicks in the panel. The context menu will be the same one that's displayed in web pages. Optional, defaults to false.

-
onMessagefunction -

Include this to listen to the panel's message event.

-
onShowfunction -

Include this to listen to the panel's show event.

-
onHidefunction -

Include this to listen to the panel's hide event.

-
- -

Panel

- -

The Panel object represents a floating modal dialog that can by an add-on to present user interface content.

- -

Once a panel object has been created it can be shown and hidden using its show() and hide() methods. Once a panel is no longer needed it can be deactivated using destroy().

- -

The content of a panel is specified using the contentURL option. An add-on can interact with the content of a panel using content scripts which it supplies in the contentScript and/or contentScriptFile options. For example, a content script could create a menu and send the user's selection to the add-on.

- -

Methods

- -

destroy()

- -

Destroys the panel, unloading any content that was loaded in it. Once destroyed, the panel can no longer be used. If you just want to hide the panel and might show it later, use hide instead.

- -

postMessage(message)

- -

Sends a message to the content scripts.

- -
Parameters
- -

message : value
- The message to send. Must be stringifiable to JSON.

- -

show(options)

- -

Displays the panel.

- -

If the options argument is given, it will be shallow merged with the options provided in the constructor: the options passed in the show method takes precedence.

- -

Passing options here is useful for making temporary changes without touching the default values.

- -
Parameters
- -

options : object
- Optional options:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameType 
widthnumber -

The width of the panel in pixels. Optional.

-
heightnumber -

The height of the panel in pixels. Optional.

-
positionobject -

The position of the panel. Optional. See Panel's options for further details.

-
focusboolean -

Set to false to prevent taking the focus away when the panel is shown.

-
- -

hide()

- -

Stops displaying the panel.

- -

resize(width, height)

- -

Resizes the panel.

- -
Parameters
- -

width : number
- The new width of the panel in pixels.

- -

height : number
- The new height of the panel in pixels.

- -

on(type, listener)

- -

Registers an event listener with the panel.

- -
Parameters
- -

type : string
- The type of event to listen for.

- -

listener : function
- The listener function that handles the event.

- -

removeListener(type, listener)

- -

Unregisters an event listener from the panel.

- -
Parameters
- -

type : string
- The type of event for which listener was registered.

- -

listener : function
- The listener function that was registered.

- -

Properties

- -

port

- -

EventEmitter object that allows you to:

- - - -

See the guide to communicating using port for details.

- -

isShowing

- -

Tells if the panel is currently shown or not. This property is read-only.

- -

height

- -

The height of the panel in pixels.

- -

width

- -

The width of the panel in pixels.

- -

focus

- -

Whether or not focus will be taken away when the panel is shown. This property is read-only.

- -

contentURL

- -

The URL of content loaded into the panel. This can point to local content loaded from your add-on's "data" directory or remote content. Setting it updates the panel's content immediately.

- -

allow

- -

An object describing permissions for the content. It contains a single key named script whose value is a boolean that indicates whether or not to execute script in the content.

- -

contentScriptFile

- -

A local file URL or an array of local file URLs of content scripts to load. Content scripts specified by this property are loaded before those specified by the contentScript property.

- -

contentScript

- -

A string or an array of strings containing the texts of content scripts to load. Content scripts specified by this property are loaded after those specified by the contentScriptFile property.

- -

contentScriptWhen

- -

When to load the content scripts. This may have one of the following values:

- - - -

contentScriptOptions

- -

Read-only value exposed to content scripts under addon.options property.

- -

Any kind of jsonable value (object, array, string, etc.) can be used here. Optional.

- -

Events

- -

show

- -

This event is emitted when the panel is shown.

- -

hide

- -

This event is emitted when the panel is hidden.

- -

message

- -

If you listen to this event you can receive message events from content scripts associated with this panel. When a content script posts a message using self.postMessage(), the message is delivered to the add-on code in the panel's message event.

- -
Arguments
- -

value : Listeners are passed a single argument which is the message posted from the content script. The message can be any JSON-serializable value.

- -

error

- -

This event is emitted when an uncaught runtime error occurs in one of the panel's content scripts.

- -
Arguments
- -

Error : Listeners are passed a single argument, the Error object.

diff --git a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/tabs/index.html b/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/tabs/index.html deleted file mode 100644 index b85bb94ab3..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/tabs/index.html +++ /dev/null @@ -1,669 +0,0 @@ ---- -title: tabs -slug: Mozilla/Add-ons/SDK/High-Level_APIs/tabs -translation_of: Archive/Add-ons/Add-on_SDK/High-Level_APIs/tabs ---- -

{{AddonSidebar}}

- -
-

Stable

-
- -

打开、操作和访问标签页,以及接收标签页事件

- -

用法

- -

打开标签页

- -

你可以注册事件监听器,以便在标签打开、关闭、完成DOM内容加载、被激活或被闲置时接收通知:

- -
var tabs = require("sdk/tabs");
-tabs.open("http://www.example.com");
- -

跟踪标签页

- -

You can register event listeners to be notified when tabs open, close, finish loading DOM content, or are made active or inactive:

- -
var tabs = require("sdk/tabs");
-
-// Listen for tab openings.
-tabs.on('open', function onOpen(tab) {
-  myOpenTabs.push(tab);
-});
-
-// Listen for tab content loads.
-tabs.on('ready', function(tab) {
-  console.log('tab is loaded', tab.title, tab.url);
-});
- -

访问标签页

- -

The module itself can be used as a list of all opened tabs across all windows. In particular, you can enumerate it:

- -
var tabs = require('sdk/tabs');
-for (let tab of tabs)
-  console.log(tab.title);
- -

You can also access individual tabs by index:

- -
var tabs = require('sdk/tabs');
-
-tabs.on('ready', function () {
-  console.log('first: ' + tabs[0].title);
-  console.log('last: ' + tabs[tabs.length-1].title);
-});
- -

You can access the currently active tab:

- -
var tabs = require('sdk/tabs');
-
-tabs.on('activate', function () {
-  console.log('active: ' + tabs.activeTab.url);
-});
- -

跟踪单个标签页

- -

Given a tab, you can register event listeners to be notified when the tab is closed, activated or deactivated, or when the page hosted by the tab is loaded or retrieved from the "back-forward cache":

- -
var tabs = require("sdk/tabs");
-
-function onOpen(tab) {
-  console.log(tab.url + " is open");
-  tab.on("pageshow", logShow);
-  tab.on("activate", logActivate);
-  tab.on("deactivate", logDeactivate);
-  tab.on("close", logClose);
-}
-
-function logShow(tab) {
-  console.log(tab.url + " is loaded");
-}
-
-function logActivate(tab) {
-  console.log(tab.url + " is activated");
-}
-
-function logDeactivate(tab) {
-  console.log(tab.url + " is deactivated");
-}
-
-function logClose(tab) {
-  console.log(tab.url + " is closed");
-}
-
-tabs.on('open', onOpen);
- -

操作标签页

- -

You can get and set various properties of tabs (but note that properties relating to the tab's content, such as the URL, will not contain valid values until after the tab's ready event fires). By setting the url property you can load a new page in the tab:

- -
var tabs = require("sdk/tabs");
-tabs.on('activate', function(tab) {
-  tab.url = "http://www.example.com";
-});
- -

在标签页中运行脚本

- -

You can attach a content script to the page hosted in a tab, and use that to access and manipulate the page's content (see the Modifying the Page Hosted by a Tab tutorial):

- -
var tabs = require("sdk/tabs");
-
-tabs.on('activate', function(tab) {
-  var worker = tab.attach({
-    contentScript: 'self.port.emit("html", document.body.innerHTML);'
-  });
-  worker.port.on("html", function(message) {
-    console.log(message)
-  })
-});
- -

Note that tab.attach is tab-centric: if the user navigates to a new page in the same tab, then the worker and content scripts will be reattached to the new page.

- -

附加样式表

- -
-

Firefox 34 新增。

-
- -

You can't attach style sheets to a tab using tab.attach(), but from Firefox 34 onwards you can attach and detach them using the low-level stylesheet/style and content/mod APIs. Here's an add-on that uses a toggle button to attach a stylesheet to the active tab, and detach it again. The stylesheet is called "style.css" and is located in the add-on's "data" directory:

- -
var tabs = require("sdk/tabs");
-var { attach, detach } = require('sdk/content/mod');
-var { Style } = require('sdk/stylesheet/style');
-var { ToggleButton } = require("sdk/ui/button/toggle");
-
-var style = Style({
-  uri: './style.css'
-});
-
-var button = ToggleButton({
-  id: "stylist",
-  label: "stylist",
-  icon: "./icon-16.png",
-  onChange: function(state) {
-    if (state.checked) {
-      attach(style, tabs.activeTab);
-    }
-    else {
-      detach(style, tabs.activeTab);
-    }
-  }
-});
- -

隐私窗口

- -

If your add-on has not opted into private browsing, then you won't see any tabs that are hosted by private browser windows.

- -

Tabs hosted by private browser windows won't be seen if you enumerate the tabs module itself, and you won't receive any events for them.

- -

To learn more about private windows, how to opt into private browsing, and how to support private browsing, refer to the documentation for the private-browsing module.

- -

转为XUL标签页

- -

To convert from the high-level Tab objects used in this API to the low-level XUL tab objects used in the tabs/utils API and by traditional add-ons, use the viewFor() function exported by the viewFor module.

- -

To convert back the other way, from a XUL tab to a high-level Tab object, use the modelFor() function, exported by the modelFor module.

- -

Here's an example converting from a high-level Tab to a XUL tab and then back the other way:

- -
var { modelFor } = require("sdk/model/core");
-var { viewFor } = require("sdk/view/core");
-
-var tabs = require("sdk/tabs");
-var tab_utils = require("sdk/tabs/utils");
-
-function mapHighLevelToLowLevel(tab) {
-  // get the XUL tab that corresponds to this high-level tab
-  var lowLevelTab = viewFor(tab);
-  // now we can, for example, access the tab's content directly
-  var browser = tab_utils.getBrowserForTab(lowLevelTab);
-  console.log(browser.contentDocument.body.innerHTML);
-  // get the high-level tab back from the XUL tab
-  var highLevelTab = modelFor(lowLevelTab);
-  console.log(highLevelTab.url);
-}
-
-tabs.on("ready", mapHighLevelToLowLevel);
-
- -

Note that directly accessing XUL objects and web content like this means you're no longer protected by the compatibility guarantees made by the SDK's high-level APIs. In particular, your code might not work with multiprocess Firefox.

- -

全局变量

- -

函数

- -

open(options)

- -

Opens a new tab. The new tab will open in the active window or in a new window, depending on the inNewWindow option.

- -

示例

- -
var tabs = require("sdk/tabs");
-
-// Open a new tab on active window and make tab active.
-tabs.open("http://www.mysite.com");
-
-// Open a new tab in a new window and make it active.
-tabs.open({
-  url: "http://www.mysite.com",
-  inNewWindow: true
-});
-
-// Open a new tab on active window in the background.
-tabs.open({
-  url: "http://www.mysite.com",
-  inBackground: true
-});
-
-// Open a new tab as an app tab and do something once it's open.
-tabs.open({
-  url: "http://www.mysite.com",
-  isPinned: true,
-  onOpen: function onOpen(tab) {
-    // do stuff like listen for content
-    // loading.
-  }
-});
- -
参数
- -

options : object
- 必选项:

- - - - - - - - - - - - - - - - -
NameType 
urlstring -

String URL to be opened in the new tab. This is a required property.

-
- -

可选项:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameType 
isPrivateboolean -

Boolean which will determine whether the new tab should be private or not. If your add-on does not support private browsing this will have no effect. See the private-browsing documentation for more information. Defaults to false.

-
inNewWindowboolean -

If present and true, a new browser window will be opened and the URL will be opened in the first tab in that window. This is an optional property.

-
inBackgroundboolean -

If present and true, the new tab will be opened to the right of the active tab and will not be active. This is an optional property.

-
isPinnedboolean -

If present and true, then the new tab will be pinned as an app tab.

-
onOpenfunction -

A callback function that will be registered for the 'open' event. This is an optional property.

-
onClosefunction -

A callback function that will be registered for the 'close' event. This is an optional property.

-
onReadyfunction -

A callback function that will be registered for the 'ready' event. This is an optional property.

-
onLoadfunction -

A callback function that will be registered for the 'load' event. This is an optional property.

-
onPageShowfunction -

A callback function that will be registered for the 'pageshow' event. This is an optional property.

-
onActivatefunction -

A callback function that will be registered for the 'activate' event. This is an optional property.

-
onDeactivatefunction -

A callback function that will be registered for the 'deactivate' event. This is an optional property.

-
- -

属性

- -

activeTab

- -

The currently active tab in the active window. This property is read-only. To activate a Tab object, call its activate method.

- -

示例

- -
// Get the active tab's title.
-var tabs = require("sdk/tabs");
-console.log("title of active tab is " + tabs.activeTab.title);
- -

length

- -

The number of open tabs across all windows.

- -

事件

- -

open

- -

This event is emitted when a new tab is opened. This does not mean that the content has loaded, only that the browser tab itself is fully visible to the user.

- -

Properties relating to the tab's content (for example: title, favicon, and url) will not be correct at this point. If you need to access these properties, listen for the ready event:

- -
var tabs = require("sdk/tabs");
-tabs.on('open', function(tab){
-  tab.on('ready', function(tab){
-    console.log(tab.url);
-  });
-});
- -
参数
- -

Tab : Listeners are passed the tab object that just opened.

- -

close

- -

This event is emitted when a tab is closed. When a window is closed this event will be emitted for each of the open tabs in that window.

- -
参数
- -

Tab : Listeners are passed the tab object that has closed.

- -

ready

- -

This event is emitted when the DOM for a tab's content is ready. It is equivalent to the DOMContentLoaded event for the given content page.

- -

A single tab will emit this event every time the DOM is loaded: so it will be emitted again if the tab's location changes or the content is reloaded.

- -

After this event has been emitted, all properties relating to the tab's content can be used.

- -
参数
- -

Tab : Listeners are passed the tab object that has loaded.

- -

activate

- -

This event is emitted when an inactive tab is made active.

- -
参数
- -

Tab : Listeners are passed the tab object that has become active.

- -

deactivate

- -

This event is emitted when the active tab is made inactive.

- -
参数
- -

Tab : Listeners are passed the tab object that has become inactive.

- -

Tab

- -

A Tab instance represents a single open tab. It contains various tab properties, several methods for manipulation, as well as per-tab event registration.

- -

Tabs emit all the events described in the Events section. Listeners are passed the Tab object that triggered the event.

- -

方法

- -

pin()

- -

Pins this tab as an app tab.

- -

unpin()

- -

Unpins this tab.

- -

close(callback)

- -

Closes this tab.

- -
参数
- -

callback : function
- A function to be called when the tab finishes its closing process. This is an optional argument.

- -

reload()

- -

Reloads this tab.

- -

activate()

- -

Makes this tab active, which will bring this tab to the foreground.

- -

getThumbnail()

- -

Returns thumbnail data URI of the page currently loaded in this tab.

- -

attach(options)

- -

Attach one or more scripts to the document loaded in the tab. Note that by attaching inside ready event, this becomes tab-centric: if the user navigates to a new page in the same tab, then the content scripts will be reattached to the new page.

- -

示例

- -
var tabs = require("sdk/tabs");
-
-tabs.on('ready', function(tab) {
-  var worker = tab.attach({
-      contentScript:
-        'document.body.style.border = "5px solid red";'
-  });
-});
- -
参数
- -

options : object
- 可选项:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameType 
contentScriptFilestring,array -

The local file URLs of content scripts to load. Content scripts specified by this option are loaded before those specified by the contentScript option. Optional.

-
contentScriptstring,array -

A string or an array of strings of code to be evaluated in the context. Content scripts specified by this option are loaded after those specified by the contentScriptFile option. Optional.

-
contentScriptOptionsobject -

You can use this option to define read-only values for your content scripts.

- -

The option consists of an object literal listing name:value pairs for the values you want to provide to the content script. For example:

- -
-// main.js
-
-const tabs = require("sdk/tabs");
-
-tabs.open({
-  url: "./page.html",
-  onReady: function(tab) {
-    tab.attach({
-      contentScriptFile: "./content-script.js",
-      contentScriptOptions: {
-        a: "blah"
-      }
-    });
-  }
-});
- -

The values are accessible to content scripts via the self.options property:

- -
-// content-script.js
-
-alert(self.options.a);
-
onMessagefunction -

A function called when the content worker receives a message from content scripts. Listeners are passed a single argument, the message posted from the content script. Optional.

-
onErrorfunctionA function called when the content worker receives an error from content scripts. Listeners are passed a single argument, error, which is the error posted from the content script and an object of type Error. Optional
- -
返回
- -

Worker : Worker 对象能够用来和内容脚本通信。查看 Content Scripts guide 了解详细信息。

- -

属性

- -

id

- -

The unique id for the tab. This property is read-only.

- -

title

- -

The title of the tab (usually the title of the page currently loaded in the tab) This property can be set to change the tab title.

- -

url

- -

The URL of the page currently loaded in the tab. This property can be set to load a different URL in the tab.

- -

favicon

- -

The URL of the favicon for the page currently loaded in the tab. This property is read-only.

- -
This property is deprecated. From version 1.15, use the favicon module's getFavicon() function instead.
- -

contentType

- -
-

This is currently an experimental API, so we might change it in future releases.

- -

Returns the MIME type that the document currently loaded in the tab is being rendered as. This may come from HTTP headers or other sources of MIME information, and might be affected by automatic type conversions performed by either the browser or extensions. This property is read-only.

-
- -

index

- -

The index of the tab relative to other tabs in the application window. This property can be set to change its relative position.

- -

isPinned

- -

Whether or not this tab is pinned as an app tab. This property is read-only.

- -

window

- -

标签页的window对象.

- -

readyState

- -
-

Firefox 33 新增。

-
- -

A string telling you the load state of the document hosted by this tab. This corresponds directly to Document.readyState. It has one of four possible values:

- - - -

Once a tab's readyState has entered "interactive", you can retrieve properties such as the document's URL.

- -

事件

- -

close

- -

This event is emitted when the tab is closed. It's also emitted when the tab's window is closed.

- -
参数
- -

Tab : Listeners are passed the tab object.

- -

ready

- -

This event is emitted when the DOM for the tab's content is ready. It is equivalent to the DOMContentLoaded event for the given content page. At this point the document itself is fully loaded and parsed, but resources such as stylesheets and images may still be loading.

- -

A single tab will emit this event every time the DOM is loaded: so it will be emitted again if the tab's location changes or the content is reloaded. After this event has been emitted, all properties relating to the tab's content can be used.

- -
参数
- -

Tab : Listeners are passed the tab object.

- -

load

- -

This event is emitted when the page for the tab's content is loaded. It is equivalent to the load event for the given content page. At this point the document and its resources, such as images and stylesheets, have finished loading.

- -

This event can be used for pages that do not have a DOMContentLoaded event, like images. For pages that have a DOMContentLoaded event, load is fired after ready.

- -

A single tab will emit this event every time the page is loaded: so it will be emitted again if the tab's location changes or the content is reloaded. After this event has been emitted, all properties relating to the tab's content can be used.

- -
参数
- -

Tab : Listeners are passed the tab object.

- -

pageshow

- -

The pageshow event is emitted when the page for a tab's content is loaded. It is equivalent to the pageshow event for the given content page.

- -

This event is similar to the load and ready events, except unlike load and ready, pageshow is triggered if the page was retrieved from the bfcache. This means that if the user loads a page, loads a new page, then moves back to the previous page using the "Back" button, the pageshow event is emitted when the user moves back to the previous page, while the load and ready events are not.

- -

This event is not emitted when the tab is made the active tab: to get notified about that, you need to listen to the activate event.

- -

After this event has been emitted, all properties relating to the tab's content can be used. It is emitted after load and ready.

- -
参数
- -

Tab : Listeners are passed the tab object.

- -

persisted : Listeners are passed a boolean value indicating whether or not the page was loaded from the bfcache.

- -

activate

- -

This event is emitted when the tab is made active.

- -

Note that you cannot guarantee that a tab's content, or even its url, are initialized at the time activate is emitted. This is because when a new tab is opened, its activate event may be emitted before the content is loaded.

- -

You can use the tab's readyState property to determine whether the tab's content and url will be available: if readyState is uninitialized or loading, then you can't access the tab's properties and must wait for the tab's ready event.

- -
参数
- -

Tab : Listeners are passed the tab object.

- -

deactivate

- -

This event is emitted when the tab is made inactive.

- -
参数
- -

Tab : Listeners are passed the tab object.

diff --git a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/url/index.html b/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/url/index.html deleted file mode 100644 index f98da9baf9..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/url/index.html +++ /dev/null @@ -1,191 +0,0 @@ ---- -title: url -slug: Mozilla/Add-ons/SDK/High-Level_APIs/url -translation_of: Archive/Add-ons/Add-on_SDK/High-Level_APIs/url ---- -
-

实验性的

-
- -

构建,验证,解析URL

- -

Globals

- -

构造函数

- -

URL(source, base)

- -

URL构造函数可以创建一个URL对象,并验证提供的字符串是否是有效的URL。SDK中,任何接受URL参数的API,除非特殊说明,均接受的是此对象而不是字符串。

- -
参数
- -

source : string
- 一个表示URL的字符串,如果接受的参数不是有效的URL字符串,此构造函数会抛出一个异常。

- -

base : string
- 一个设置的字符串,用来表示一个相对路径的源。

- -

DataURL(uri)

- -

DataURL构造函数创建一个data: URL对象, 并验证提供的字符串是否是一个有效的data: URL。

- -
参数
- -

uri : string
- 一个表示Data URL的字符串。如果它不是一个合法的URL字符串,此构造函数会抛出一个错误。

- -

函数

- -

toFilename(url)

- -

尝试将给定的URL转换成本地文件路径。这个方法会自动尝试解决非文件协议, such as the resource: protocol, to their place on the file system. 除非URL无法转换,否则,本方法会将本地路径作为字符串返回。

- -
参数
- -

url : string
- 字符串格式的URL。

- -
返回
- -

string : 转换后的本地路径字符串

- -

fromFilename(path)

- -

讲一个给定的路径转换成 file: URL.

- -
参数
- -

path : string
- 需要被转换的本地文件路径字符串。

- -
Returns
- -

string : 转换后的字符串。

- -

isValidURI(uri)

- -

检查一个URL字符串是合法。 isValidURI("http://mozilla.org") 将返回 true, 而 isValidURI("mozilla.org") 将返回 false

- -
参数
- -

uri : string
- 需要被测试的URL。

- -
Returns
- -

boolean : 代表字符串是否有效的布尔值。

- -

getTLD(url)

- -

返回给定域名的顶级域名: 内部使用的是 getPublicSuffix()

- -
var urls = require("sdk/url");
-console.log(urls.getTLD("http://www.bbc.co.uk/"));          // "co.uk"
-console.log(urls.getTLD("https://developer.mozilla.org/")); // "org"
- -
参数
- -

url : string
- 给定的URL字符串

- -
返回
- -

string : 对应的顶级域名。

- -

URL

- -

方法

- -

toString()

- -

返回URL的字符表示形式。

- -
返回
- -

string : 字符串格式的URL。

- -

属性

- -

scheme

- -

URL使用的协议

- -

userPass

- -

URL中的username:password 部分,null 表示不存在。

- -

host

- -

URL的主机部分。 null 表示无此部分。例子:

- -
var url = require("sdk/url").URL("https://developer.mozilla.org/en-US/Add-ons");
-console.log(url.host);  // developer.mozilla.org
- -

port

- -

URL使用的端口。 null 表示不存在。

- -

path

- -

URL的路径部分,例子:

- -
var url = require("sdk/url").URL("https://developer.mozilla.org/en-US/Add-ons");
-console.log(url.path);  // /en-US/Add-ons
- -

hostname

- -

表示URL的域的字符串。参见 window.location.hostname

- -

pathname

- -

'/'开始的路径字符串。参见 window.location.pathname

- -

hash

- -

'#' 开始的hash字符串,参见 window.location.hash

- -

href

- -

整个URL字符串,参见 window.location.href

- -

origin

- -

该URL的源的字符串,参见 window.location.origin

- -

protocol

- -

该URL使用的协议字符串,包括最后的':',参见 window.location.protocol

- - - -

以'?'开始的URL的参数段,包括最开始的'?'参见window.location.search.

- -

DataURL

- -

方法

- -

toString()

- -

返回数据的URL字符串形式。如果是 base64 的URL,数据会以base64编码方式编码。

- -
返回
- -

string : URL字符串

- -

属性

- -

mimeType

- -

数据的MIME类型,默认为空字符串。

- -

parameters

- -

一个HashMap的数据包含URL参数。默认情况下是一个空对象。

- -

base64

- -

定义了数据属性的编码。

- -

data

- -

包含数据的URL字符串。如果URI给构造函数包含Base64参数,这个字符串会被解码。

diff --git a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/widget/index.html b/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/widget/index.html deleted file mode 100644 index 3d374a0752..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/high-level_apis/widget/index.html +++ /dev/null @@ -1,839 +0,0 @@ ---- -title: widget -slug: Mozilla/Add-ons/SDK/High-Level_APIs/widget -tags: - - ZH -translation_of: Archive/Add-ons/Add-on_SDK/High-Level_APIs/widget ---- -

{{LegacyAddonsNotice}}{{AddonSidebar}}

- -
-

Deprecated in Firefox 29 and removed in Firefox 38.

- -

The widget API is deprecated from Firefox 29 onwards. Please see the ui module for replacements. In particular, for a simple button, try the action button or toggle button APIs, and for a more complex widget try the toolbar or sidebar APIs.

-
- -

Create a simple user interface for an add-on in Firefox's add-on bar.

- -

Usage

- -

"Widgets" are small pieces of content that live in the Firefox 4 add-on bar. They can be simple icons or complex web pages. You can attach panels to them that open when they're clicked, or you can define a custom click handler to perform some other action, like opening a web page in a tab.

- -

There are a few advantages to using widgets over an ad hoc user interface. First, your users will be accustomed to interacting with add-ons via widgets and the add-on bar. Second, it allows Firefox to treat your interface as a first-class citizen. For example, in the future Firefox may allow the user to drag widgets from the add-on bar to other toolbars. By exposing your interface as a widget, your add-on would automatically inherit such functionality.

- -

Creation and content

- -

Widgets can contain images or arbitrary web content. You can include this content inline as a string by using the content property, or point to content using a URL with the contentURL property.

- -

Upon creation, the widget is automatically added to the add-on bar. You can set the width of a widget, but the height is fixed so as to fit in the add-on bar. If the content is an image, it is automatically scaled to be 16x16 pixels.

- -

For example, this widget contains an image, so it looks like a simple icon:

- -
require("sdk/widget").Widget({
-  id: "mozilla-icon",
-  label: "My Mozilla Widget",
-  contentURL: "http://www.mozilla.org/favicon.ico"
-});
- -

You can make contentURL point to an HTML or icon file which you have packaged inside your add-on. Just save the file in your add-on's data directory, and reference it using the data.url() method of the self module:

- -
var data = require("sdk/self").data;
-
-require("sdk/widget").Widget({
-  id: "my-widget",
-  label: "My Widget",
-  contentURL: data.url("my-content.html")
-});
- -

This widget contains an entire web page:

- -
require("sdk/widget").Widget({
-  id: "hello-display",
-  label: "My Hello Widget",
-  content: "Hello!",
-  width: 50
-});
- -

Widgets are quite small by default, so this example used the width property to grow it in order to show all the text.

- -

Scripting widget content

- -

To interact with the widget's content you need to load a separate script into the panel. In the SDK these scripts are called "content scripts" because they're explicitly used for interacting with web content.

- -

While content scripts can access the content they're attached to, they can't use the SDK's APIs. So implementing a complete solution usually means you have to send messages between the content script and the main add-on code.

- - - -
-

Unless your content script is extremely simple and consists only of a static string, don't use contentScript: if you do, you may have problems getting your add-on approved on AMO.

- -

Instead, keep the script in a separate file and load it using contentScriptFile. This makes your code easier to maintain, secure, debug and review.

-
- - -

For example, suppose we want to implement a media player as an add-on. We could implement the main user interface as a widget hosting an array of buttons to control play/pause/stop functions.

- -

We can then use a content script to listen for clicks on those buttons. But because content scripts can't use the SDK's APIs, we'll want the content script to send messages to the main add-on code, which can then implement the media player functions using the SDK.

- -

The widget's content is specified using HTML like this:

- -
<html>
-  <body>
-    <img src="play.png" id="play-button">
-    <img src="pause.png" id="pause-button">
-    <img src="stop.png" id="stop-button">
-  </body>
-</html>
- -

We just include three icons, and assign an ID to each one. This HTML file, and the icon files it references, are saved in the add-on's data directory.

- -

Next, we write a content script that listens for click events on each icon and sends the corresponding message to the main add-on code:

- -
var play_button = document.getElementById("play-button");
-play_button.onclick = function() {
-  self.port.emit("play");
-}
-
-var pause_button = document.getElementById("pause-button");
-pause_button.onclick = function() {
-  self.port.emit("pause");
-}
-
-var stop_button = document.getElementById("stop-button");
-stop_button.onclick = function() {
-  self.port.emit("stop");
-}
- -

We save this file in the add-on's data directory as "button-script.js". Finally. in the add-on's "main.js" file, we create the widget, assign it the HTML file and the content script, and listen for events from the content script:

- -
const widgets = require("sdk/widget");
-const data = require("sdk/self").data;
-
-var player = widgets.Widget({
-  id: "player",
-  width: 72,
-  label: "Player",
-  contentURL: data.url("buttons.html"),
-  contentScriptFile: data.url("button-script.js")
-});
-
-player.port.on("play", function() {
-  console.log("playing");
-});
-
-player.port.on("pause", function() {
-  console.log("pausing");
-});
-
-player.port.on("stop", function() {
-  console.log("stopping");
-});
- -

To learn much more about content scripts, see the Working with Content Scripts guide.

- -

Scripting trusted widget content

- -

We've already seen that you can package HTML files in your add-on's data directory and use them to define the widget's content. We can call this "trusted" content, because unlike content loaded from a source outside the add-on, the add-on author knows exactly what it's doing. To interact with trusted content you don't need to use content scripts: you can just include a script from the HTML file in the normal way, using script tags.

- -

Like a content script, these scripts can communicate with the add-on code using the postMessage() API or the port API. The crucial difference is that these scripts access the postMessage and port objects through the addon object, whereas content scripts access them through the self object.

- -

To show the difference, convert the player add-on above to use normal page scripts instead of content scripts.

- -

First, in the content script, change self to addon, and wrap it in a function:

- -
function init() {
-  var play_button = document.getElementById("play-button");
-  play_button.onclick = function() {
-    addon.port.emit("play");
-  }
-
-  var pause_button = document.getElementById("pause-button");
-  pause_button.onclick = function() {
-    addon.port.emit("pause");
-  }
-
-  var stop_button = document.getElementById("stop-button");
-  stop_button.onclick = function() {
-    addon.port.emit("stop");
-  }
-}
- -

Next, add a script tag to reference "button-script.js", and call its init() function on load:

- -
<html>
-  <head>
-    <script src="button-script.js"></script>
-  </head>
-  <body onLoad="init()">
-    <img src="play.png" id="play-button">
-    <img src="pause.png" id="pause-button">
-    <img src="stop.png" id="stop-button">
-  </body>
-</html>
-
- -

Finally, remove the line attaching the content script from "main.js":

- -
const widgets = require("sdk/widget");
-const data = require("sdk/self").data;
-
-var player = widgets.Widget({
-  id: "player",
-  width: 72,
-  label: "Player",
-  contentURL: data.url("buttons.html")
-});
-
-player.port.emit("init");
-
-player.port.on("play", function() {
-  console.log("playing");
-});
-
-player.port.on("pause", function() {
-  console.log("pausing");
-});
-
-player.port.on("stop", function() {
-  console.log("stopping");
-});
- -

Attaching panels to widgets

- -

You can supply a panel to the widget's constructor: if you do this, the panel is automatically displayed when the user clicks the widget.

- - -

- -
data = require("sdk/self").data
-
-var clockPanel = require("sdk/panel").Panel({
-  width:215,
-  height:160,
-  contentURL: data.url("clock.html")
-});
-
-require("sdk/widget").Widget({
-  id: "open-clock-btn",
-  label: "Clock",
-  contentURL: data.url("History.png"),
-  panel: clockPanel
-});
- -

Note that this is, at the moment, the only way you can attach a panel to a widget.

- -

You must supply the panel in the widget's constructor for it to work. If you assign the panel to the widget after construction, the panel can still be shown but will not be anchored to the widget:

- -
data = require("sdk/self").data
-
-var clockPanel = require("sdk/panel").Panel({
-  width:215,
-  height:160,
-  contentURL: data.url("clock.html")
-});
-
-widget = require("sdk/widget").Widget({
-  id: "open-clock-btn",
-  label: "Clock",
-  contentURL: data.url("History.png")
-});
-
-widget.panel = clockPanel;
-
-// Will not be anchored
-widget.panel.show();
- -

Also, if you try to call panel.show() inside your widget's click event listener, the panel will not be anchored:

- -
data = require("sdk/self").data
-
-var clockPanel = require("sdk/panel").Panel({
-  width:215,
-  height:160,
-  contentURL: data.url("clock.html")
-});
-
-require("sdk/widget").Widget({
-  id: "open-clock-btn",
-  label: "Clock",
-  contentURL: data.url("History.png"),
-  panel: clockPanel,
-  onClick: function() {
-    // Will not be anchored
-    this.panel.show();
-  }
-});
- -

See bug 638142.

- -

Private windows

- -

If your add-on has not opted into private browsing, then your widget will not appear in any private browser windows.

- -

To learn more about private windows, how to opt into private browsing, and how to support private browsing, refer to the documentation for the private-browsing module.

- -

Examples

- -

For conciseness, these examples create their content scripts as strings and use the contentScript property. In your own add-ons, you will probably want to create your content scripts in separate files and pass their URLs using the contentScriptFile property. See Working with Content Scripts for more information.

- -
var widgets = require("sdk/widget");
-
-// A basic click-able image widget.
-widgets.Widget({
-  id: "google-link",
-  label: "Widget with an image and a click handler",
-  contentURL: "http://www.google.com/favicon.ico",
-  onClick: function() {
-    require("sdk/tabs").activeTab.url = "http://www.google.com/";
-  }
-});
- -
// A widget that changes display on mouseover.
-widgets.Widget({
-  id: "mouseover-effect",
-  label: "Widget with changing image on mouseover",
-  contentURL: "http://www.yahoo.com/favicon.ico",
-  onMouseover: function() {
-    this.contentURL = "http://www.bing.com/favicon.ico";
-  },
-  onMouseout: function() {
-    this.contentURL = "http://www.yahoo.com/favicon.ico";
-  }
-});
- -
// A widget that updates content on a timer.
-widgets.Widget({
-  id: "auto-update-widget",
-  label: "Widget that updates content on a timer",
-  content: "0",
-  contentScript: 'setTimeout(function() {' +
-                 '  document.body.innerHTML++;' +
-                 '}, 2000)',
-  contentScriptWhen: "ready"
-});
- -
// A widget created with a specified width, that grows.
-var myWidget = widgets.Widget({
-  id: "widget-effect",
-  label: "Wide widget that grows wider on a timer",
-  content: "I'm getting longer.",
-  width: 50,
-});
-require("sdk/timers").setInterval(function() {
-  myWidget.width += 10;
-}, 1000);
- -
// A widget communicating bi-directionally with a content script.
-var widget = widgets.Widget({
-  id: "message-test",
-  label: "Bi-directional communication!",
-  content: "<foo>bar</foo>",
-  contentScriptWhen: "ready",
-  contentScript: 'self.on("message", function(message) {' +
-                 '  alert("Got message: " + message);' +
-                 '});' +
-                 'self.postMessage("ready");',
-  onMessage: function(message) {
-    if (message == "ready")
-      widget.postMessage("me too");
-  }
-});
- -

Globals

- -

Constructors

- -

Widget(options)

- -

Creates a new widget. The widget is immediately added to the add-on bar.

- -
Parameters
- -

options : object
- Required options:

- - - - - - - - - - - - - - - - - - - - - -
NameType 
labelstring -

A string description of the widget used for accessibility, title bars, and error reporting.

-
idstring -

A string used to identify your widget in order to save its location when the user moves it in the browser. This string has to be unique and must not be changed over time.

-
- -

Optional options:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameType 
contentstring -

An optional string value containing the displayed content of the widget. It may contain HTML. Widgets must have either the content property or the contentURL property set.

- -

If the content is an image, it is automatically scaled to be 16x16 pixels.

-
contentURLstring -

An optional string URL to content to load into the widget. This can be local content or remote content, an image or web content. Widgets must have either the content property or the contentURL property set.

- -

If the content is an image, it is automatically scaled to be 16x16 pixels.

-
panelPanel -

An optional panel to open when the user clicks on the widget. Note: If you also register a "click" listener, it will be called instead of the panel being opened. However, you can show the panel from the listener by calling this.panel.show().

-
widthinteger -

Optional width in pixels of the widget. If not given, a default width is used.

-
onClickfunction -

Include this to listen to the widget's click event.

-
onMessagefunction -

Include this to listen to the widget's message event.

-
onMouseoverfunction -

Include this to listen to the widget's mouseover event.

-
onMouseoutfunction -

Include this to listen to the widget's mouseout event.

-
onAttachfunction -

Include this to listen to the widget's attach event.

-
tooltipstring -

Optional text to show when the user's mouse hovers over the widget. If not given, the label is used.

-
allowobject -

An optional object describing permissions for the content. It should contain a single key named script whose value is a boolean that indicates whether or not to execute script in the content. script defaults to true.

-
contentScriptFilestring,array -

A local file URL or an array of local file URLs of content scripts to load. Content scripts specified by this property are loaded before those specified by the contentScript property.

-
contentScriptstring,array -

A string or an array of strings containing the texts of content scripts to load. Content scripts specified by this property are loaded after those specified by the contentScriptFile property.

-
contentScriptWhenstring -

When to load the content scripts. This may take one of the following values:

- -
    -
  • "start": load content scripts immediately after the document element for the widget is inserted into the DOM, but before the DOM content itself has been loaded
  • -
  • "ready": load content scripts once DOM content has been loaded, corresponding to the DOMContentLoaded event
  • -
  • "end": load content scripts once all the content (DOM, JS, CSS, images) for the widget has been loaded, at the time the window.onload event fires
  • -
- -

This property is optional and defaults to "end".

-
contentScriptOptionsobject -

Read-only value exposed to content scripts under self.options property.

- -

Any kind of jsonable value (object, array, string, etc.) can be used here. Optional.

-
- -

Widget

- -

Represents a widget object.

- -

Methods

- -

destroy()

- -

Removes the widget from the add-on bar.

- -

postMessage(data)

- -

Sends a message to the widget's content scripts.

- -
Parameters
- -

data : value
- The message to send. The message can be any JSON-serializable value.

- -

on(type, listener)

- -

Registers an event listener with the widget.

- -
Parameters
- -

type : string
- The type of event to listen for.

- -

listener : function
- The listener function that handles the event.

- -

removeListener(type, listener)

- -

Unregisters an event listener from the widget.

- -
Parameters
- -

type : string
- The type of event for which listener was registered.

- -

listener : function
- The listener function that was registered.

- -

getView(window)

- -

Retrieve a WidgetView instance of this widget relative to a browser window.

- -
Parameters
- -

window : BrowserWindow
- The BrowserWindow instance to match.

- -
Returns
- -

WidgetView : A WidgetView instance associated with the browser window. Any changes subsequently applied to this object will only be applied to the widget attached to that window.

- -

Properties

- -

label

- -

The widget's label. Read-only.

- -

content

- -

A string containing the widget's content. It can contain HTML. Setting it updates the widget's appearance immediately. However, if the widget was created using contentURL, then this property is meaningless, and setting it has no effect.

- -

contentURL

- -

The URL of content to load into the widget. This can point to local content loaded from your add-on's "data" directory or remote content, an image or web content. Setting it updates the widget's appearance immediately. However, if the widget was created using content, then this property is meaningless, and setting it has no effect.

- -

Setting the contentURL property will break the channel of communication between this widget and any content scripts it contains. Messages sent from the content script will no longer be received by the main add-on code, and vice versa. This issue is currently tracked as bug 825434.

- -

panel

- -

A panel to open when the user clicks on the widget.

- -

width

- -

The widget's width in pixels. Setting it updates the widget's appearance immediately.

- -

tooltip

- -

The text of the tooltip that appears when the user hovers over the widget.

- -

allow

- -

A object describing permissions for the content. It contains a single key named script whose value is a boolean that indicates whether or not to execute script in the content.

- -

contentScriptFile

- -

A local file URL or an array of local file URLs of content scripts to load.

- -

contentScript

- -

A string or an array of strings containing the texts of content scripts to load.

- -

contentScriptWhen

- -

When to load the content scripts. This may have one of the following values:

- - - -

contentScriptOptions

- -

Read-only value exposed to content scripts under self.options property.

- -

Any kind of jsonable value (object, array, string, etc.) can be used here. Optional.

- -

port

- -

Object that allows you to:

- - - -

See the guide to communicating using port for details.

- -

Events

- -

attach

- -

This event is emitted when a browser window is opened and a new WidgetView object is created. If the widget has a content script, this event is fired only when the content script is applied according to the contentScriptWhen attribute.

- -
Arguments
- -

WidgetView : The related WidgetView object.

- -

click

- -

This event is emitted when the widget is clicked.

- -
Arguments
- -

WidgetView : Listeners are passed a single argument which is the WidgetView that triggered the click event.

- -

message

- -

If you listen to this event you can receive message events from content scripts associated with this widget. When a content script posts a message using self.postMessage(), the message is delivered to the add-on code in the widget's message event.

- -
Arguments
- -

value : Listeners are passed a single argument which is the message posted from the content script. The message can be any JSON-serializable value.

- -

mouseover

- -

This event is emitted when the user moves the mouse over the widget.

- -

mouseout

- -

This event is emitted when the user moves the mouse away from the widget.

- -

WidgetView

- -

Represents a widget instance specific to one browser window.

- -

Anything you do to an instance of this object will only be applied to the instance attached to its browser window: widget instances attached to other browser windows will be unaffected.

- -

By contrast, any changes you make to an instance of the normal Widget class will be applied across all browser windows.

- -

This class has all the same methods, attributes and events as the Widget class except for the getView method and the attach event.

- -

In this example WidgetView is used to display different content for http and https schemes:

- -
// A widget that update its content specifically to each window.
-var tabs = require("sdk/tabs");
-var windows = require("sdk/windows").browserWindows;
-var widget = require("sdk/widget").Widget({
-  id: "window-specific-test",
-  label: "Widget with content specific to each window",
-  content: " ",
-  width: 50
-});
-// Observe tab switch or document changes in each existing tab:
-function updateWidgetState(tab) {
-  var view = widget.getView(tab.window);
-  if (!view) return;
-  // Update widget displayed text:
-  view.content = tab.url.match(/^https/) ? "Secured" : "Unsafe";
-}
-tabs.on('ready', updateWidgetState);
-tabs.on('activate', updateWidgetState);
- -

Methods

- -

destroy()

- -

Removes the widget view from the add-on bar.

- -

postMessage(data)

- -

Sends a message to the widget view's content scripts.

- -
Parameters
- -

data : value
- The message to send. The message can be any JSON-serializable value.

- -

on(type, listener)

- -

Registers an event listener with the widget view.

- -
Parameters
- -

type : string
- The type of event to listen for.

- -

listener : function
- The listener function that handles the event.

- -

removeListener(type, listener)

- -

Unregisters an event listener from the widget view.

- -
Parameters
- -

type : string
- The type of event for which listener was registered.

- -

listener : function
- The listener function that was registered.

- -

Properties

- -

label

- -

The widget view's label. Read-only.

- -

content

- -

A string containing the widget view's content. It can contain HTML. Setting it updates the widget view's appearance immediately. However, if the widget view was created using contentURL, then this property is meaningless, and setting it has no effect.

- -

contentURL

- -

The URL of content to load into the widget. This can point to local content loaded from your add-on's "data" directory or remote content, an image or web content. Setting it updates the widget's appearance immediately. However, if the widget was created using content, then this property is meaningless, and setting it has no effect.

- -

Setting the contentURL property will break the channel of communication between this widget and any content scripts it contains. Messages sent from the content script will no longer be received by the main add-on code, and vice versa. This issue is currently tracked as bug 825434.

- -

panel

- -

A panel to open when the user clicks on the widget view.

- -

width

- -

The widget view's width in pixels. Setting it updates the widget view's appearance immediately.

- -

tooltip

- -

The text of the tooltip that appears when the user hovers over the widget view.

- -

allow

- -

A object describing permissions for the content. It contains a single key named script whose value is a boolean that indicates whether or not to execute script in the content.

- -

contentScriptFile

- -

A local file URL or an array of local file URLs of content scripts to load.

- -

contentScript

- -

A string or an array of strings containing the texts of content scripts to load.

- -

contentScriptWhen

- -

When to load the content scripts. This may have one of the following values:

- - - -

contentScriptOptions

- -

Read-only value exposed to content scripts under self.options property.

- -

Any kind of jsonable value (object, array, string, etc.) can be used here. Optional.

- -

port

- -

Object that allows you to:

- - - -

See the guide to communicating using port for details.

- -

Events

- -

detach

- -

The detach event is fired when the widget view is removed from its related window. This can occur if the window is closed, Firefox exits, or the add-on is disabled.

- -

click

- -

This event is emitted when the widget view is clicked.

- -

message

- -

If you listen to this event you can receive message events from content scripts associated with this widget view. When a content script posts a message using self.postMessage(), the message is delivered to the add-on code in the widget view's message event.

- -
Arguments
- -

value : Listeners are passed a single argument which is the message posted from the content script. The message can be any JSON-serializable value.

- -

mouseover

- -

This event is emitted when the user moves the mouse over the widget view.

- -

mouseout

- -

This event is emitted when the user moves the mouse away from the widget view.

diff --git a/files/zh-cn/mozilla/add-ons/sdk/index.html b/files/zh-cn/mozilla/add-ons/sdk/index.html deleted file mode 100644 index 3c6398ed48..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/index.html +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: 附加组件 SDK -slug: Mozilla/Add-ons/SDK -tags: - - More Example - - Need Tanslate - - TopicStub -translation_of: Archive/Add-ons/Add-on_SDK ---- -
-

Support for extensions using XUL/XPCOM or the Add-on SDK was removed in Firefox 57, released November 2017. As there is no supported version of Firefox enabling these technologies, this page will be removed by December 2020.

- -

Add-ons using the techniques described in this document are considered a legacy technology in Firefox. Don't use these techniques to develop new add-ons. Use WebExtensions instead. If you maintain an add-on which uses the techniques described here, consider migrating it to use WebExtensions.

- -

Starting from Firefox 53, no new legacy add-ons will be accepted on addons.mozilla.org (AMO) for desktop Firefox and Firefox for Android.

- -

Starting from Firefox 57, only extensions developed using WebExtensions APIs will be supported on Desktop Firefox and Firefox for Android.

- -

Even before Firefox 57, changes coming up in the Firefox platform will break many legacy extensions. These changes include multiprocess Firefox (e10s), sandboxing, and multiple content processes. Legacy extensions that are affected by these changes should migrate to use WebExtensions APIs if they can. See the "Compatibility Milestones" document for more information.

- -

A wiki page containing resources, migration paths, office hours, and more, is available to help developers transition to the new technologies.

-
- -

你可以使用Add-on SDK来开发Firefox的附加组件。你可以使用各种各样的标准Web技术:JavaScript, HTML和CSS。该SDK不仅包括一些用来创建附加组件的 JavaScript API,还提供了开发、运行、测试、打包附加组件的一些工具。

- -
-

教程

- -
-
-
-
快速入门
-
如何安装SDK使用jpm工具开发、测试、打包附加组件
-
与浏览器交互
-
打开网页监听页面加载列出打开的标签页
-
开发技术
-
学习常用开发技术,如单元测试日志创建可复用模块本地化移动开发
-
-
- -
-
-
创建用户界面组件
-
创建用户界面组件如工具条按钮, 上下文菜单菜单项对话框
-
修改网页
-
-

通过URL匹配修改页面或者动态修改某个tab选项卡

-
-
将其组合在一起
-
关于注释器的附加组件的例子演示.
-
-
-
- -
-

指南

- -
-
-
-
贡献者指南
-
学习如何开始构建 SDK和关于SDK最重要的术语, 如 模块 类和继承, 私有属性, 内容处理.
-
SDK的基础构建
-
SDK的底层技术方面: 模块,程序ID, Firefox 兼容的规则定义.
-
内容脚本
-
-
-

一个详细的指南内容脚本

-
-
-
-
- -
-
-
SDK语法
-
SDK的事件框架和插件的脚本和内容脚本之间的区别。
-
SDK的 事件框架add-on scripts 和 content scripts 的区别.
-
XUL 迁移
-
指导  移植 XUL add-ons 到 SDK. 本指南包括 两工具 和 一个 工作实例 比较 XUL 和 add-on.
-
-
-
- -
-

参考

- -
-
-
-
高级API
-
高级SDK API的参考文档.
-
工具参考
-
用于 jpm工具 开发的参考文档, 测试, 打包add-ons, 全局 控制台记录, 和package.json 文件.
-
-
- -
-
-
低级API
-
低级SDK API的参考文档.
-
-
-
diff --git a/files/zh-cn/mozilla/add-ons/sdk/low-level_apis/index.html b/files/zh-cn/mozilla/add-ons/sdk/low-level_apis/index.html deleted file mode 100644 index 673c369430..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/low-level_apis/index.html +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: 低层 API -slug: Mozilla/Add-ons/SDK/Low-Level_APIs -translation_of: Archive/Add-ons/Add-on_SDK/Low-Level_APIs ---- -

{{AddonSidebar}}

- -

本节的模块实现了低层的 API,这些模块大至分为三类:

- - - -

这些模块仍在开发中,我们预期在将来发布的版本中会做出不兼容的变更。

- -

{{ LandingPageListSubpages ("/zh-CN/Add-ons/SDK/Low-Level_APIs", 5) }}

- -

 

diff --git a/files/zh-cn/mozilla/add-ons/sdk/low-level_apis/test_assert/index.html b/files/zh-cn/mozilla/add-ons/sdk/low-level_apis/test_assert/index.html deleted file mode 100644 index 5f7537ec42..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/low-level_apis/test_assert/index.html +++ /dev/null @@ -1,283 +0,0 @@ ---- -title: test/assert -slug: Mozilla/Add-ons/SDK/Low-Level_APIs/test_assert -translation_of: Archive/Add-ons/Add-on_SDK/Low-Level_APIs/test_assert ---- -

{{LegacyAddonsNotice}}{{AddonSidebar}}

- -
-

Unstable

-
- -

实现在 CommonJS Unit Testing specification version 1.1 其中定义的断言接口。

- -

Usage

- -

To use the assert module, write a set of unit tests following the instructions in the unit testing tutorial. Each test will be passed an Assert object when you run the tests using jpm test. You can use this object to make assertions about your program's state.

- -

For example:

- -
var a = 1;
-
-exports["test value of a"] = function(assert) {
-  assert.ok(a == 1, "test that a is 1");
-}
-
-require("sdk/test").run(exports);
- -

Globals

- -

Constructors

- -

Assert(logger)

- -

Create a new Assert object. This function is only called by the unit test framework, and not by unit tests themselves.

- -
Parameters
- -

logger : object
- Object used to log the results of assertions.

- -

Assert

- -

An object used to make assertions about a program's state in order to implement unit tests.

- -

The Assert object's interface is defined by the CommonJS Unit Testing specification, version 1.1.

- -

Methods

- -

ok(guard, message)

- -

Tests whether an expression evaluates to true.

- -
assert.ok(a == 1, "test that a is equal to one");
- -

This is equivalent to:

- -
assert.equal(a == 1, true, "test that a is equal to one");
- -
Parameters
- -

guard : expression
- The expression to evaluate.

- -

message : string
- Optional message to log, providing extra information about the test.

- -

equal(actual, expected, message)

- -

Tests shallow, coercive equality with ==:

- -
assert.equal(1, 1, "test that one is one");
- -
Parameters
- -

actual : object
- The actual result.

- -

expected : object
- The expected result.

- -

message : string
- Optional message to log, providing extra information about the test.

- -

notEqual(actual, expected, message)

- -

Tests that two objects are not equal, using !=:

- -
assert.notEqual(1, 2, "test that one is not two");
- -
Parameters
- -

actual : object
- The actual result.

- -

expected : object
- The expected result.

- -

message : string
- Optional message to log, providing extra information about the test.

- -

deepEqual(actual, expected, message)

- -

Tests that two objects have a deep equality relation. Deep equality is defined in the CommonJS specification for Assert, item 7, which is quoted here:

- -
-
    -
  1. All identical values are equivalent, as determined by ===.
  2. -
  3. If the expected value is a Date object, the actual value is equivalent if it is also a Date object that refers to the same time.
  4. -
  5. Other pairs that do not both pass typeof value == "object", equivalence is determined by ==.
  6. -
  7. For all other Object pairs, including Array objects, equivalence is determined by having the same number of owned properties (as verified with Object.prototype.hasOwnProperty.call), the same set of keys (although not necessarily the same order), equivalent values for every corresponding key, and an identical "prototype" property. Note: this accounts for both named and indexed properties on Arrays.
  8. -
-
- -
assert.deepEqual({ a: "foo" }, { a: "foo" }, "equivalent objects");
- -
Parameters
- -

actual : object
- The actual result.

- -

expected : object
- The expected result.

- -

message : string
- Optional message to log, providing extra information about the test.

- -

notDeepEqual(actual, expected, message)

- -

Tests that two objects do not have a deep equality relation, using the negation of the test for deep equality:

- -
assert.notDeepEqual({ a: "foo" }, Object.create({ a: "foo" }),
-                    "object's inherit from different prototypes");
- -
Parameters
- -

actual : object
- The actual result.

- -

expected : object
- The expected result.

- -

message : string
- Optional message to log, providing extra information about the test.

- -

strictEqual(actual, expected, message)

- -

Tests that two objects are equal, using the strict equality operator ===:

- -
// This test will pass, because "==" will perform type conversion
-exports["test coercive equality"] = function(assert) {
-  assert.equal(1, "1", "test coercive equality between 1 and '1'");
-}
-
-// This test will fail, because the types are different
-exports["test strict equality"] = function(assert) {
-  assert.strictEqual(1, "1", "test strict equality between 1 and '1'");
-}
- -
Parameters
- -

actual : object
- The actual result.

- -

expected : object
- The expected result.

- -

message : string
- Optional message to log, providing extra information about the test.

- -

notStrictEqual(actual, expected, message)

- -

Tests that two objects are not equal, using the negation of the strict equality operator ===:

- -
// This test will fail, because "==" will perform type conversion
-exports["test coercive equality"] = function(assert) {
-  assert.notEqual(1, "1", "test coercive equality between 1 and '1'");
-}
-
-// This test will pass, because the types are different
-exports["test strict equality"] = function(assert) {
-  assert.notStrictEqual(1, "1", "test strict equality between 1 and '1'");
-}
- -
Parameters
- -

actual : object
- The actual result.

- -

expected : object
- The expected result.

- -

message : string
- Optional message to log, providing extra information about the test.

- -

throws(block, error, message)

- -

Assert that a block of code throws the expected exception.

- -

This method takes an optional Error argument:

- - - - -

For example, suppose we define two different custom exceptions:

- -
function MyError(message) {
-  this.name = "MyError";
-  this.message = message || "Default Message";
-}
-
-MyError.prototype = new Error();
-MyError.prototype.constructor = MyError;
-
-function AnotherError(message) {
-  this.name = "AnotherError";
-  this.message = message || "Default Message";
-    console.log(this.message);
-}
-
-AnotherError.prototype = new Error();
-AnotherError.prototype.constructor = AnotherError;
- -

We can check the type of exception by passing a function as the Error argument:

- -
exports["test exception type 1 expected to pass"] = function(assert) {
-  assert.throws(function() {
-    throw new MyError("custom message");
-  },
-  MyError,
-  "test throwing a specific exception");
-}
-
-exports["test exception type 2 expected to fail"] = function(assert) {
-  assert.throws(function() {
-    throw new MyError("custom message");
-  },
-  AnotherError,
-  "test throwing a specific exception");
-}
- -

We can check the message by passing a regular expression:

- -
exports["test exception message 1 expected to pass"] = function(assert) {
-  assert.throws(function() {
-    throw new MyError("custom message");
-  },
-  /custom message/,
-  "test throwing a specific message");
-}
-
-exports["test exception message 2 expected to pass"] = function(assert) {
-  assert.throws(function() {
-    throw new AnotherError("custom message");
-  },
-  /custom message/,
-  "test throwing a specific exception");
-}
-
-exports["test exception message 3 expected to fail"] = function(assert) {
-  assert.throws(function() {
-    throw new MyError("another message");
-  },
-  /custom message/,
-  "test throwing a specific message");
-}
- -
Parameters
- -

block : block
- The block of code to test.

- -

error : function|RegExp
- Either a constructor function returning the type of exception expected, or a regular expression expected to match the exception's message property.

- -

message : string
- Optional message to log, providing extra information about the test.

diff --git a/files/zh-cn/mozilla/add-ons/sdk/low-level_apis/ui_button_action/index.html b/files/zh-cn/mozilla/add-ons/sdk/low-level_apis/ui_button_action/index.html deleted file mode 100644 index d826b15d7f..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/low-level_apis/ui_button_action/index.html +++ /dev/null @@ -1,526 +0,0 @@ ---- -title: ui/button/action -slug: Mozilla/Add-ons/SDK/Low-Level_APIs/ui_button_action -translation_of: Archive/Add-ons/Add-on_SDK/Low-Level_APIs/ui_button_action ---- -
-

实验性的(译者备注:暂不翻译,可能会废弃)

-
-

Add a button to the Firefox user interface. With this module you can create buttons that display icons and can respond to click events.

-

Usage

-


- Creating buttons

-

To create a button you must give it an ID, an icon, and a label:

-
var { ActionButton } = require("sdk/ui/button/action");
-
-var button = ActionButton({
-    id: "my-button",
-    label: "my button",
-    icon: {
-      "16": "./firefox-16.png",
-      "32": "./firefox-32.png"
-    },
-    onClick: function(state) {
-        console.log("button '" + state.label + "' was clicked");
-    }
-  });
-

By default, the button appears in the Firefox toolbar:

-

However, users can move it to the Firefox menu panel using the toolbar customization feature:

-

-

Badged buttons

-
-

New in Firefox 36.

-
-

You can add a "badge" to a button using its badge property. This can be a number or a string, and you can update it at any time. By default the badge's color is red, but you can set your own color using the badgeColor property, specified as a CSS <color> value:

-
var { ToggleButton } = require("sdk/ui/button/toggle");
-
-var button = ToggleButton({
-    id: "my-button1",
-    label: "my button1",
-    icon: "./icon-16.png",
-    onChange: changed,
-    badge: 0,
-    badgeColor: "#00AAAA"
-  });
-
-function changed(state) {
-  button.badge = state.badge + 1;
-  if (state.checked) {
-    button.badgeColor = "#AA00AA";
-  }
-  else {
-    button.badgeColor = "#00AAAA";
-  }
-}
-

-

Specifying multiple icons

-

You can specify just one icon, or multiple icons in different sizes.

-

If you specify multiple icons, Firefox will select the best-fitting icon based on the device screen resolution and the place the icon appears. For example, in the screenshots above, Firefox uses the small icon when the button is in the toolbar and the large icon when the button is in the menu panel. Read more about specifying icons in the reference documentation for the ActionButton constructor.

-

Responding to click events

-

You can respond to click events by assigning a listener to the button's click event. You can do this in the button's constructor, by assigning the listener to the onClick option. You can also add, or change, the listener afterwards:

-
var { ActionButton } = require("sdk/ui/button/action");
-
-var button = ActionButton({
-    id: "my-button",
-    label: "my button",
-    icon: {
-      "16": "./firefox-16.png",
-      "32": "./firefox-32.png"
-    },
-    onClick: firstClick
-  });
-
-function firstClick(state) {
-  console.log("You clicked '" + state.label + "'");
-  button.removeListener("click", firstClick);
-  button.on("click", subsequentClicks);
-}
-
-function subsequentClicks(state) {
-  console.log("You clicked '" +  state.label + "' again");
-}
-

The listener is passed a state object that contains all the button's properties.

-

You can generate click events programmatically with the button's click() method.

-

Disabling buttons

-

You can disable a button by setting its disabled property to true. A disabled button will not generate click events and its icon will appear disabled:

-

-

Updating state

-

You can update all the button's properties except for its id.

-

By default, the button has global state: that is, its properties are the same across all open windows and tabs, and updating them updates the button's state across all open windows and tabs.

-

You can set state to be specific to a window or tab using the button's state() method. To set state like this, call state() with 2 parameters:

- -

Here's an add-on with a button that disables itself when you click it, but only for the currently active window:

-
var { ActionButton } = require("sdk/ui/button/action");
-
-var button = ActionButton({
-    id: "my-button",
-    label: "my button",
-    icon: {
-      "16": "./firefox-16.png",
-      "32": "./firefox-32.png"
-    },
-    onClick: disableForThisWindow
-  });
-
-function disableForThisWindow(state) {
-  button.state("window", {
-    disabled: true
-  });
-}
-

To fetch the state for a specific window or tab, call state(), passing in the window or tab you are interested in, and it will return the state:

-
var labelForActiveTab = button.state("tab").label;
-

To learn more about this, see the API documentation for state().

-

Destroying buttons

-

When you've finished with a button, destroy it by calling its destroy() method. After that, any attempts to access any of its properties or to call any of its methods will throw exceptions.

-

Globals

-

Constructors

-

ActionButton(options)

-

Creates an action button.

-
Parameters
-

options : object
- Required options:

- - - - - - - - - - - - - - - - - - - - - - - - - -
NameType 
idstring -

The button's ID. This is used internally to keep track of this button. The ID must be unique within your add-on.

-
labelstring -

The button's human-readable label. When the button is in the toolbar, this appears in a tooltip, and when the button is in the menu, it appears underneath the button as a legend.

-
iconurl, string, object -

One or more icons for the button. You can specify this in one of three ways: 

-
    -
  • as a resource:// URL pointing at an icon file in your add-on's "data" directory, typically constructed using self.data.url(iconfile)
  • -
  • as a relative path: a string in the form "./iconfile", where "iconfile" is a relative path to the icon file beginning in your add-on's "data" directory
  • -
  • as an object, or dictionary of key-value pairs. Here you can specify a range of sizes for your button's icon. Each key-value pair specifies an icon: -
      -
    • each value specifies an image file as a resource:// URL or relative path.
    • -
    • each key must be a numeric string such as "16", or "32", which represents the size in pixels of the corresponding image.
    • -
    -
  • -
-
-var { ActionButton } = require('sdk/ui/button/action');
-var self = require("sdk/self");
-
-var button1 = ActionButton({
-    id: "my-button1",
-    label: "my button1",
-    icon: self.data.url("firefox-16.png")
-  });
-
-var button2 = ActionButton({
-    id: "my-button2",
-    label: "my button2",
-    icon: "./firefox-16.png"
-  });
-
-var button3 = ActionButton({
-    id: "my-button3",
-    label: "my button3",
-    icon: {
-      "16" : "./firefox-16.png",
-      "32" : "./firefox-32.png",
-      "64" : "./firefox-64.png"
-    }
-  });
-

If you use the final form, Firefox will automatically choose the best-fit icon for your button, depending on the device screen resolution and where the button is in the UI. On a device with a "normal" screen resolution, the toolbar has space for 18 x 18 pixels and the menu panel has space for 32 x 32 pixels. On a high resolution screen (such as a HiDPI display), these are doubled to 36 x 36 and 64 x 64 pixels, respectively. So you can supply three icon files:

-
-icon: {
-  "16": "./addon16.png",
-  "32": "./addon32.png",
-  "64": "./addon64.png"
-}
-

This will look fine in both toolbar and menu panel, and for both screen resolutions. However, the icons in the toolbar will not quite fill the space available, so you can instead supply four icons:

-
-icon: {
-  "18": "./addon18.png", // toolbar icon non HiDPI
-  "32": "./addon32.png", // menu panel icon non HiDPI
-  "36": "./addon36.png", // toolbar icon HiDPI
-  "64": "./addon64.png"  // menu panel icon HiDPI
-}
-
-
-

Optional options:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameType 
disabledboolean -

Determines whether the button is disabled. Disabled buttons appear disabled in the UI, and do not respond to clicks. Defaults to false.

-
onClickfunction -

Click handler for the button.

-
badgeNumber or String -
-

New in Firefox 36.

-
-

Badge to attach to the button.

-
badgeColorCSS <color> value -
-

New in Firefox 36.

-
-

Color for the badge. If badgeColor is omitted and badge is specified, then the badge is red.

-
-

ActionButton

-

Methods

-

click()

-

Click the button. This will cause the button to generate the click event:

-
var { ActionButton } = require('sdk/ui/button/action');
-
-var button = ActionButton({
-  id: "my-button",
-  label: "my button",
-  icon: {
-    "16": "./firefox-16.png",
-    "32": "./firefox-32.png"
-  },
-  onClick: function(state) {
-      console.log("You clicked '" + state.label + "'");
-  }
-});
-
-button.click();
-
-

state()

-

Get or set the button's state for a specific window or tab.

-

By default, a button's properties are global, meaning that they are the same across all open windows and tabs, and that if you update these properties, then they are updated across all windows and tabs. But sometimes you want a button attached to one window (or tab) to have a different state to a button attached to a different window (or tab). That's what state() is for.

-

To set a button's properties for a specific window or tab, call state(), passing it the window or tab you want the property to apply to, and the property value to set. A special shortcut allows you to pass the string "window" or "tab" to select the currently active window or tab.

-

For example, if you have a button like this:

-
var { ActionButton } = require('sdk/ui/button/action');
-
-var button = ActionButton({
-  id: "my-button",
-  label: "default",
-  icon: "./firefox-16.png"
-});
-

You can change its label for only the currently active window like this:

-
button.state("window", {
-  "label" : "window-specific label"
-});
-

You can change its label for only the currently active tab like this:

-
button.state("tab", {
-  "label" : "tab-specific label"
-});
-
-

To fetch the button state for a specific window or tab, call state(), passing it the window or tab you're interested in, and it will return a state object containing all the properties for the button associated with that window or tab. Again. you can use the strings "window" or "tab" as shortcuts. For example, this add-on:

- -
var { ActionButton } = require('sdk/ui/button/action');
-var tabs = require("sdk/tabs");
-
-var button = ActionButton({
-  id: "my-button",
-  label: "default label",
-  icon: "./firefox-16.png"
-});
-
-tabs.open({
-  url: "https://mozilla.org/",
-  onOpen: onNewTab
-});
-
-function onNewTab(tab) {
-  // Modify the label only for the new tab
-  button.state(tab, {
-    "label" : "tab-specific label"
-  });
-
-  // access the global label -> "default label"
-  console.log(button.label);
-
-  // access the window's label -> "default label"
-  console.log(button.state("window").label);
-
-  // access the first tab's label -> "default label"
-  console.log(button.state(tabs[0]).label);
-
-  // access the second tab's label -> "tab-specific label"
-  console.log(button.state(tabs[1]).label);
-}
-

Setting a property won't affect a more-specific property setting. For example, if you have a window with two tabs, and you set a tab-specific label, then set the window-specific label, this will not overwrite the tab-specific label:

-
var { ActionButton } = require('sdk/ui/button/action');
-var tabs = require("sdk/tabs");
-
-var button = ActionButton({
-  id: "my-button",
-  label: "default label",
-  icon: "./firefox-16.png"
-});
-
-tabs.open({
-  url: "https://mozilla.org/",
-  onOpen: onNewTab
-});
-
-function onNewTab(tab) {
-  // Modify the label only for the new tab
-  button.state(tab, {
-    "label" : "tab-specific label"
-  });
-
-  // Modify the label for the window
-  button.state("window", {
-    "label" : "window-specific label"
-  });
-
-  // access the global label -> "default label"
-  console.log(button.label);
-
-  // access the window's label -> "window-specific label"
-  console.log(button.state("window").label);
-
-  // access the first tab's label -> "window-specific label"
-  console.log(button.state(tabs[0]).label);
-
-  // access the second tab's label -> "tab-specific label"
-  console.log(button.state(tabs[1]).label);
-}
-

The best way to think of this is as a tree: the global state is the root, followed by the state for each window, followed by the state for each tab in a window. If a property value for a node in the tree has not been set explicitly using state(), then it inherits its value from the next level up. So if you have one window containing two tabs, and have set the button's label only for tab A, then tab B will inherit label's value from the window, and changing the value for the window will implicitly change the value for tab B.

-

To delete a tab- or window-specific state, assign null to the property. After that, the property will inherit its value from the less-specific state as before:

-
var { ActionButton } = require('sdk/ui/button/action');
-var tabs = require("sdk/tabs");
-
-var button = ActionButton({
-  id: "my-button",
-  label: "default label",
-  icon: "./firefox-16.png"
-});
-
-tabs.open({
-  url: "https://mozilla.org/",
-  onOpen: onNewTab
-});
-
-function onNewTab(tab) {
-  // Modify the label only for the new tab
-  button.state(tab, {
-    "label" : "tab-specific label"
-  });
-
-  // Modify the label for the window
-  button.state("window", {
-    "label" : "window-specific label"
-  });
-
-  // access the global label -> "default label"
-  console.log(button.label);
-
-  // access the window's label -> "window-specific label"
-  console.log(button.state("window").label);
-
-  // access the first tab's label -> "window-specific label"
-  console.log(button.state(tabs[0]).label);
-
-  // access the second tab's label -> "tab-specific label"
-  console.log(button.state(tabs[1]).label);
-
-  // Reset the tab-specific state
-  button.state(tab, null);
-
-  // access the second tab's label -> "window-specific label"
-  console.log(button.state(tabs[1]).label);
-}
-

Finally, you can pass the button itself into state(). This is an alternative way to set or get the global state. The reason for using this, rather than setting properties individually, is that you can define an object with the properties to set in one place, then apply it to the global state with a single line:

-
const defaultState = {
-  "label": "default label",
-  "icon": "./default.png",
-}
-
-const differentState = {
-  "label": "different label",
-  "icon": "./different.png",
-}
-
-var { ActionButton } = require("sdk/ui/button/action");
-
-var button = ActionButton({
-    id: "default-label",
-    label: "default label",
-    icon: "./default.png",
-    onClick: function(state) {
-      if (button.label == "default label") {
-        button.state(button, differentState);
-      }
-      else {
-        button.state(button, defaultState);
-      }
-      console.log(button.state(button).label);
-      console.log(button.state(button).icon);
-    }
-  });
-
-
Parameters
-

target : button, tab, window, string

- -

state : object, null
- Include this parameter only if you are setting state. It is an object containing all the properties you wish to set. For example:

-
button.state("tab", {
-  "label" : "tab-specific label",
-  "icon": "./tab-specific-icon.ico"
-});
-

To reset state, pass null:

-
button.state("tab", null);
-
Returns
-

state : if you have passed the second state argument to make this function a setter, it returns undefined. Otherwise, it functions as a getter and returns the button's state for the specified object. This logs the state for the button associated with the currently active tab:

-
console.log(button.state("tab"));
-

This object represents a snapshot of the state at the time state() is called. It is not kept up to date with changes made to the button:

-
button.label = "foo";
-var state = button.state(button);
-button.label = "bar";
-console.log(state.label) // foo
-

on()

-

Add a listener to an event emitted by the button. The button only emits one type of event, click:

-
button.on("click", handleClick)
-
-function handleClick(state) {
-  console.log("button '" + state.label + "' was clicked");
-}
-
Parameters
-

event : string
- The event to listen for. Action buttons only emit one type of event, "click".

-

listener : function
- Function that will be called on click.

-

once()

-

Assign a listener to the first occurrence only of an event emitted by the button. The button only emits one type of event, click. The listener is automatically removed after the first time the event is emitted.

-
Parameters
-

event : string
- The event to listen for. Action buttons only emit one type of event, "click".

-

listener : function
- Function that will be called on click.

-

removeListener()

-

Removes an event listener. For example, this code is equivalent to once():

-
button.on("click", handleClick)
-
-function handleClick(state) {
-  console.log("button '" + state.label + "' was clicked");
-  button.removeListener("click", handleClick);
-} 
-
Parameters
-

event : string
- The event to listener is listening for. Action buttons only emit one type of event, "click".

-

listener : function
- The listener to remove.

-

destroy()

-

Destroy the button. After calling this function, the button will no longer appear in the UI, and accessing any of its properties or methods will throw an error.

-

Properties

-

id

-

The button's unique ID. This is read-only.

-

label

-

The button's label.

-

icon

-

The button's icon or icons, as a URL, relative path, or object containing a set of key-value pairs.

-

disabled

-

Boolean property indicating whether or not the button is disabled.

-

badge

-
-

New in Firefox 36.

-
-

Value to attach to the button as a badge. May be a number or a string.

-

badgeColor

-
-

New in Firefox 36.

-
-

Color for the badge, specified as a CSS <color> value.

-

Events

-

click

-

This event is emitted when a user clicks the button or your add-on calls the button's click() method.

-
Arguments
-

state : The button's state. This contains all the button's properties.

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tools/index.html b/files/zh-cn/mozilla/add-ons/sdk/tools/index.html deleted file mode 100644 index 8c67b4644e..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tools/index.html +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: Tools -slug: Mozilla/Add-ons/SDK/Tools -tags: - - Add-on SDK - - CFX - - JPM - - NeedsTranslation - - TopicStub -translation_of: Archive/Add-ons/Add-on_SDK/Tools ---- -

Articles listed here provide a reference for the SDK's tools:

- -

{{ LandingPageListSubpages ("/en-US/Add-ons/SDK/Tools", 7) }}

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tools/jpm/index.html b/files/zh-cn/mozilla/add-ons/sdk/tools/jpm/index.html deleted file mode 100644 index db429ef078..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tools/jpm/index.html +++ /dev/null @@ -1,652 +0,0 @@ ---- -title: jpm -slug: Mozilla/Add-ons/SDK/Tools/jpm -tags: - - Add-on SDK - - JPM -translation_of: Archive/Add-ons/Add-on_SDK/Tools/jpm ---- -

{{AddonSidebar}}

- -
-

你能在Firefox 38或更高的版本中使用jpm。

- -

本文为jpm参考。

-
- -

cfx 的Node版本允许你测试、运行以及打包扩展。

- -

你也可以阅读 jpm教程 开始学习。

- -

jpm 用法:

- -
jpm [command] [options]
-
- -

jpm支持以下全局参数:

- -
-h, --help        - 显示帮助信息并退出
--V, --version     - 打印出jpm版本号
---addon-dir       - 源代码目录,默认为当前目录
-
- -

安装

- -

jpm发布在node包管理器 npm 上。

- -

安装npm

- -

有两种方法来获取npm。

- - - -

要测试安装是否成功,运行:

- -
​/usr/bin/env node -v
- -

如果出现错误提示  /usr/bin/env: node: No such file or directory 并且你的 nodejs 是通过包管理的方式安装的,那你的 nodejs 很有可能安装为其它的名字。为了保证jpm的兼容,PATH之中必须是以node为可执行文件名的。在Debian和Ubuntu系统上,你可以通过安装兼容包nodejs-legacy来解决这个问题:

- -
sudo apt-get install nodejs-legacy
- -

在其它的发行版中,你或许必须手动创建一共本地符号链接:​

- -
sudo ln -s "$(which nodejs)" /usr/local/bin/node
- -

安装jpm

- -

在你安装好npm并且将其加入你的PATH中后,你可以像安装其他npm包一样来安装jpm。

- -

全局安装jpm

- -
npm install jpm --global
- -

取决于你的安装,你可能需要管理员权限执行:

- -
sudo npm install jpm --global
- -

局部安装jpm

- -

如果你不想,或者不能够全局安装jpm,你或许可以只为你安装它:

- -
npm install jpm
- -

在局部安装的情况下,为了在终端中运行jpm,你必须首先将目录"$HOME/node_modules/.bin/"添加到你的终端PATH中。将下行中的命令添加到$HOME/.profile的末尾来实现永久添加(.profile将在每次运行一个新终端时被执行):

- -
export PATH="$HOME/node_modules/.bin/:$PATH"
- -

通过git来安装jpm

- -

另外,你也可以通过git安装jpm的最新版本

- -
git clone https://github.com/mozilla-jetpack/jpm.git
-cd jpm
-npm install
-npm link
-
- -

jpm安装完毕后

- -

在全部搞定后,在命令行窗口中输入:

- -
jpm
- -

屏幕上显示了一系列可用的 jpm 命令。不同于 cfx,当在安装时使用了 --global 参数,你能在任何路径下启动的命令提示符中使用 jpm 命令。

- -

还有问题?

- -

如果你看不懂本文,要寻求帮助。SDK 用户和项目团队成员在项目邮件列表中讨论问题和建议。其他人也许会和你有一样的问题,所以试着搜索一下列表。也欢迎你发表一个新问题。你也可以在 Mozilla 的 IRC 网络#jetpack 房间里和其他SDK的用户聊天。

- -

命令参考

- -

有六个命令:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
jpm init创建一个基本的 add-on 作为你 add-on 的开端。
jpm run运行一个带有你的 add-on 的 Firefox 实例。
jpm test运行你插件的单元测试
jpm xpi将你的插件打包为 XPI 文件(火狐的插件扩展文件名)
jpm post把你的 add-on 打包成 XPI 文件,然后发送到某一个URL。
jpm watchpost无论是否有文件变更,把你的 add-on 打包成 XPI 文件发送到某一个URL。
jpm sign将你的插件打包为 XPI 文件并且取回一个由Mozilla签名的新XPI文件。
- -

jpm init

- -

这个命令从头开始初始化一个新的 add-on。

- -

新建一个目录,转到该目录下,然后运行 jpm init

- -
mkdir my-addon
-cd my-addon
-jpm init
- -

然后你会被要求提供关于你的 add-on 的一些信息:这会用来创建 package.json 文件。

- - - -

大部分字段都有一个默认值,显示在那些问题的后面的括号里。如果你按了回车,那么你的 add-on 就用那个默认值。

- -

一旦你提供了一个值或者接受了默认值,你会看到"package.json"的完整内容,并被询问是否接受。

- -

然后 jpm 创建一个基本的 add-on,作为你开发的起点,文件结构如下:

- - - -

jpm run

- -

此命令运行一个新的装有你的 add-on 的 Firefox实例:

- -
jpm run
- -

jpm run 有以下选项:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-b --binary BINARY -

指定二进制文件,使用该版本的火狐。可以用全路径,也可以用相对路径。

- -
-jpm run -b /path/to/Firefox/Nightly
- 参看选择浏览器版本
--binary-args CMDARGS -

传递附件参数到 Firefox。

- -

例如,为了传递 -jsconsole参数给 Firefox 并打开浏览器,试试下面命令:

- -
-jpm run --binary-args -jsconsole
- -

要传递多个参数,或者参数中间有空格,就把他们用引号括起来:

- -
-jpm run --binary-args '-url mzl.la -jsconsole'
-
--debug运行这个 add-on 的Add-on 调试器
-o --overload PATH -

不再使用 Firefox 内建的 SDK 模块,使用指定 PATH 路径下的模块。如果加了 -o 但 PATH 没有指定,jpm 会寻找 JETPACK_ROOT 环境变量用作路径

- -

参看重载内建模块以获取更多信息

-
-p --profile= PROFILE -

在你每次调用jpm run时,jpm 默认使用一个干净的临时的 Firefox 配置文件(profile)。使用--profile 选项以使得 jpm 使用已有的配置文件来打开 Firefox。

- -

PROFILE的值可以是一个profile的名字或路径。

- -

参看 使用 profile 以获取更多信息。

-
-v --verbose(查看)详细操作
--no-copy -
小心使用,因为 jpm run|test 会改变很多配置,不要和你的主配置文件一起使用。
- -
只有使用 --profile 的时候回生效
- 禁止配置文件的拷贝,允许重用配置。
 
- -

jpm test

- -

这个命令用来运行 add-on 的单元测试。命令:

- - - -
jpm test
- -

查看 单元测试教程 assert 模块参考文档获取更多具体内容。

- -

jpm test 接受一下选项:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-b --binary BINARY -

指定所用 Firefox 的版本。BINARY 可被指定为绝对路径或者基于当前路径的相对路径。

- -
-jpm test -b /path/to/Firefox/Nightly
- -

请查看选择一个浏览器版本

-
--binary-args CMDARGS -

传递附件参数给 Firefox。

- -

例如,传递 -jsconsole 参数,它会打开浏览器控制台,试试下面的命令:

- -
-jpm test --binary-args -jsconsole
- -

传递多个参数,或者参数间有空格,请将它们用引号括起来:

- -
-jpm test --binary-args '-url mzl.la -jsconsole'
-
--debug运行 add-on debugger 附件到当前 add-on 上。
-f --filter FILE[:TEST] -

只运行名字和 FILE 匹配的测试文件,且名字匹配 TEST(可选)的测试函数。

- -
-jpm test --filter base64:btoa
- -

上面的命令值会运行名字中含有"base64"的文件,在这些文件中只会运行名字中含有"btoa"的测试函数。

-
-o --overload PATH -

不使用 Firefox 内建的模块,而使用 PATH 路径下的模块。如果 -o 指定而 PATH 被忽略,jpm会查找 JETPACK_ROOT 环境变量并将其用作路径。

- -

查看重载内建模块以获取更多信息。

-
-p --profile PROFILE -

你每次运行jpm call时,默认地,jpm使用一个干净的临时 Firefox 配置文件。使用--profile 选项来让 jpm 使用一个现有配置文件来打开火狐。

- -

PROFILE 的值可以是配置文件的名称或者指向配置文件的路径。

- -

查看使用配置文件来获取更多信息。

-
--stop-on-error -

即使测试失败,jpm test 默认还会继续运行测试。指定 --stop-on-error 的话,会在第一次失败后停止运行测试

- -
-jpm test --stop-on-error
-
--tbplTreeherder 格式打印 test 的输出
--times NUMBER -

运行几遍 test:

- -
-jpm test --times 2
-
-v --verbose详细操作。
--no-copy -

小心使用,因为 jpm run|test 会修改许多首选项,这些首选项在你的主配置文件中从未用过。

- -

这仅仅在使用 --profile 时生效。

- 禁用配置未经的拷贝,允许用户重用配置文件。
- -

jpm xpi

- -

这个命令将 add-on 打包为一个 XPI 文件,这是 Mozilla 附加组件的安装文件的格式。

- -
jpm xpi
- -

它会在当前目录(或者 --addon-dir 指定的目录)查找 package.json 文件,并创建相关的 XPI 文件。它忽略任何 ZIP 或 XPI文件(译者注:OSX 上测试下来不会默认忽略这些文件,若要忽略请编辑.jpmignore文件),以及任何测试文件。它会包含其他所有文件。如果你想排除其他文件,查看 .jpmignore 文件

- -

一旦你构建了一个 XPI 文件,你可以通过提交到 addons.mozilla.org 来分发你的附加组件。

- -

jpm xpi 接受下列选项:

- - - - - - - - -
-v --verbose -

打印详细操作:

- -
-jpm xpi -v
-
- -

jpm post

- -

这个命令把附加组件打包为 XPI 后 post 到某个URL。

- -
jpm post
- -

查找当前目录(或 --addon-dir)下的package.json 文件,创建 XPI 文件,post 到 --post-url

- -

jpm post 接受以下选项:

- - - - - - - - - - - - -
--post-url URL -

创建 XPI 文件后,将扩展 post 到这个URL。

- -
-jpm post --post-url http://localhost:8888/
- -

查看使用 Post 和 Watchpost 获取更多信息。

-
-v --verbose -

打印详细操作:

- -
-jpm post --post-url http://localhost:8888/ -v
-
- -

jpm watchpost

- -

这个命令在打包附件组件为 XPI 文件后,无论文件是否改变都将其 post 到某个URL。

- -
jpm watchpost
- -

无论文件是否改变,在当前目录(或 --addon-dir)下创建一个 XPI并将其post到 --post-url

- -

jpm watchpost 接受以下选项:

- - - - - - - - - - - - -
--post-url URL -

创建 XPI 文件后,将扩展 post 到这个URL。

- -
-jpm watchpost --post-url http://localhost:8888/
- -

查看 Using Post 和 Watchpost 获取更多信息。

-
-v --verbose -

打印详细信息:

- -
-jpm watchpost --post-url http://localhost:8888/ -v
-
- -

jpm sign

- -

此特性仅从 jpm 1.0.4 起被支持。

- -

此命令为你的附加组件重新生成一个新的被Mozilla签名的 XPI 文件。这就允许你自己托管你的 add-on,这样用户可以在安装时避免 signed add-ons are required 错误。在用这个命令之前,你需要在 addons.mozilla.org 创建 API 证书

- -

你可以为你已经生成的 XPI 文件签名,就像如下,通过传递 XPI 文件给 --xpi参数:

- -
jpm sign --api-key ${AMO_API_KEY} --api-secret ${AMO_API_SECRET} --xpi <xpi file>
- -

或者,你可以省略 --xpi 参数,这样 jpm sign 会从当前目录(或者 --addon-dir)生成一个XPI文件。

- -
jpm sign --api-key ${AMO_API_KEY} --api-secret ${AMO_API_SECRET}
- -

上面提交了一个 XPIaddons.mozilla.org 签名g API,如果通过验证,然后下载一个签名后的 XPI 文件到工作目录。

- -

下面是一些运行 sign 命令的结果:

- - - -

在底层,jpm signaddons.mozilla.org里创建了一个不会被列出的附加组件,这就意味着你必须自己把XPI文件分发给你的用户来安装。如果你需要创建一个在列表中的附加组件,只要直接将它提交到 addons.mozilla.org,在那里它自动会被签名。如果你在安装一个已签名的附加组件时遇到困难,参看调试一节。

- -

jpm sign 接收以下参数:

- - - - - - - - - - - - - - - - - - - - -
--api-key=API_KEY -

addons.mozilla.org key管理页面生成的API访问key(字符串)。

-
--api-secret=API_SECRET -

addons.mozilla.org key 管理页面生成的API访问密钥(字符串)。这个值应该被小心保密并且永远不要记录到版本控制中。如果你的密钥被破解,另一个开发者就能上传附加组件到你的账号上。你应该立即撤销泄露的API证书并且重新生成一份。

-
--api-url-prefix=http://.../api -

可选的API URL前缀,如果你想使用一个试用签名的API。

- -

例如,你可以通过https://addons-dev.allizom.org/api/v3的认证来使用addons.mozilla.org的开发者版本。

-
--xpi=/path/to/file.xpi -

需要签名的XPI文件。如果没指定文件,一个新的XPI会在当前目录(或者--addon-dir)中生成。

-
- -

一些技巧

- -

选择浏览器版本

- -

默认地,jpm runjpm test 运行 release 版本的 FireFox。你可以有一两种办法来告诉 jpm 使用一个不同的版本:

- - - -

使用 .jpmignore 来忽略文件

- -

使用 .jpmignore 就像使用 git.gitignore,Mercurial 的 .hgignore,或者 npm 的 .npmignore。通过使用这个文件,你可以在使用 jpm xpi 编译 .xpi 文件时,让 jpm 知道你想要忽略哪些文件。

- -

这是个例子:

- -
# Ignore .DS_Store files created by mac
-.DS_Store
-
-# Ignore any zip or xpi files
-*.zip
-*.xpi
- -

有着以上内容的 .jpmignore 文件会忽略所有的 zip 文件和 .DS_Store 文件,这些文件不会包括在 jpm xpi 所生成的 xpi 文件中。

- -

使用配置

- -

默认地,jpm run 每次都会使用一个新的配置。这就意味着前一次运行 jpm 时的任何配置,默认都不会在下一次中使用。

- -

这其中包括,比如你安装的任何附加组件,或者你的历史记录,或者任何使用 simple-storage API 存储的数据。

- -

为了让 jpm 使用一个特定的配置,传递 --profile 选项,设定你想使用的配置文件的名字,或者是配置文件的路径。

- -
jpm run --profile boogaloo
- -
jpm run --profile path/to/boogaloo
- -

如果你提供了 --profile 但是它的参数不是一个已有配置文件的名字或路径,jpm 会打开 配置文件管理器 让你选择一个已有的配置文件或者创建一个新的配置文件:

- -
jpm run --profile i-dont-exist
- -

开发时不用重启浏览器

- -

因为每次调用 jpm run 时都会重启浏览,如果你十分频繁地修改附加组件,这就可能有点笨重了。一个替代的开发模型是使用 扩展自动安装器附加组件:它会在特定端口监听新 XPI 文件并且自动安装它们。这样,你就能测试新的改动,而不用重启浏览器:

- - - -

你甚至可以用一个简单的脚本来自动化这一工作流程。例如:

- -
jpm watchpost --post-url http://localhost:8888/
- -

注意,比起使用 jpm run 运行附加组件时的日志级别,你在使用这个方法时控制台定义的日志级别是不一样的。这意味着,如果你想看到 console.log() 消息的输出,你必须微调一下配置。查看 logging levels 文档以获取这方面的详细信息。

- -

重载内建模块

- -

你用来实现你的附加组件的SDK模快是 Firefox 内建的。当你使用 jpm runjpm xpi 来运行或者打包附加组件时,附加组件使用其所在的 Firefox 版本中的模块版本。

- -

作为附件组件开发者,这一般就是你想要的。但是如果你在开发 SDK 模块本身,这就不合适了。这时你需要:

- - - -
jpm run -o
- -

这会通知 jpm 去使用 SDK 模块的本地拷贝,而不是 Firefox 内部的模块。如果你不想设置 JETPACK_ROOT 环境变量,你可以使用 -o 传递SDK模块本地拷贝的位置:

- -
jpm run -o "/path/to/addon-sdk/"
- -

路径必须是一个绝对路径并且指向 SDK 的根目录(不是 addon-sdk/sdk 或 addon-sdk/sdk/lib)。

- -

支持自托管附加组件的更新

- -

此特性仅被 jpm 1.0.3 及之后版本支持,

- -

当你给你的附加组件来添加特性或者修复 bug 时,你想让之前安装好的附加组件将自己从老版本更新到新版本。

- -

如果你在 addons.mozilla.org 上列出你的附加组件,那么你要做的只是提交一个新的版本;附加组件默认会检查它们在 addons.mozilla.org 上的新版本。好了,你不用继续往下看这一节了。

- -

如果你没有在 addons.mozilla.org 上列出你的附加组件,你需要生成一个 Mozilla 签名的 XPI 文件并告诉 Firefox 哪里可以找到这个附加组件的新版本。方法就是:

- - - -

为了达到这个目的,package.json中需要包含两个额外的key :

- - - -

- -

如果你设置了 updateURLupdateLink(如果 updateKey 不是 HTTPS 的,那也要包括 updateKey),那么 jpm xpi 会:

- - - -

然后你将更新清单托管到 updateURL,并且将新版 XPI 托管到 updateLink

- -

获取更多这方面的详细信息,参看自动检查附件组件更新

- -
 
- -
 
diff --git a/files/zh-cn/mozilla/add-ons/sdk/tools/package_json/index.html b/files/zh-cn/mozilla/add-ons/sdk/tools/package_json/index.html deleted file mode 100644 index cd08ff2b64..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tools/package_json/index.html +++ /dev/null @@ -1,312 +0,0 @@ ---- -title: package.json -slug: Mozilla/Add-ons/SDK/Tools/package_json -translation_of: Archive/Add-ons/Add-on_SDK/Tools/package_json ---- -

{{AddonSidebar}}

- -

The package.json file contains manifest data for your add-on, providing not only descriptive information about the add-on for presentation in the Add-ons Manager, but other metadata required of add-ons.

- -

一些条目, 比如icon, namedescription, 有类似install manifest的格式, 并且package.json会写入install manifest, 当使用jpm xpi的时候.

- -

Others, such as lib, permissions, and preferences, represent instructions to the jpm tool itself to generate and include particular code and data structures in your add-on.

- -

其他如lib, permissionspreferences表示使用jpm工具的步骤, 生成你扩展包含的特殊代码和数据结构.

- -

创建manifest

- -

package.json起初是通过运行jpm init生成的,通常在扩展的根目录.比如下面(假设扩展目录是"my-addon")

- -
{
-  "name": "my-addon",
-  "title": "my-addon",
-  "id": "jid1-1FERGV45e4f4f",
-  "description": "a basic add-on",
-  "author": "",
-  "license": "MPL-2.0",
-  "version": "0.1"
-}
- -

如果你使用新的jpm tool话,可以方便的从package.json获取manifest数据, 通过require其他模块的方式:

- -
var title = require("./package.json").title;
- -

Key reference

- -

package.json may contain the following keys:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
author -

The name of the package's original author; this could be the name of a person or a company. Defaults to an empty string. It may include a optional URL in parentheses and an email address in angle brackets.

- -

This value will be used as the add-on's em:creator element in the install.rdf file generated by cfx.

- -
Note: jpm supports NodeJS people fields.
-
contributors -

An array of additional author strings, identifying other contributors to the add-on.

- -

These values will be used as the add-on's em:contributor elements in its install.rdf.

- -
Note: This is deprecated along with cfx; it's not available when using jpm.
-
dependencies -

A string or an array of strings specifying the names of packages that this add-on requires in order to function properly.

-
description -

The add-on's description; this is a human-readable message describing what the add-on does. This defaults to the text "a basic add-on".

- -

This value will be used as the add-on's em:description element in its install.rdf.

-
engines -

Object with supported applications (key) and required version numbers (value).

- -
    -
  • firefox: Firefox Desktop
  • -
  • fennec: Firefox for Android
  • -
- -

Example:

- -
-  "engines": {
-    "firefox": ">=38.0a1",
-    "fennec": ">=38.0a1"
-  }
-
fullName {{deprecated_inline}} -
Note: This is deprecated along with cfx; it's not available when using jpm.
- -

The full name of the package. It can contain spaces.

- -

If this key is present its value will be used as the add-on's em:name element in its install.rdf.

-
harnessClassID {{deprecated_inline}} -
Note: This is deprecated along with cfx; it's not available when using jpm.
- -

String in the GUID format.

- -

This is used as a classID of the "harness service" XPCOM component. Defaults to a random GUID generated by cfx.

-
homepage -

The URL of the add-on's website.

- -

This value will be used as the add-on's em:homepageURL element in its install.rdf.

-
icon -

The path to an image file containing the icon for the add-on. Defaults to icon.png. If no icon is specified, the standard add-on icon will be used by default.

- -
-

When using jpm, relative path to the data directory (to make it re-usable for add-on HTML content) does not currently work. Instead you have to use following syntax:

- -

resource://ID/data/icon-name.png

- -

ID is the value from the id field. If it does not begin with the @-character, then @ has to be escaped as -at- and . as -dot-. If the ID is a GUID, the curly braces used in the id field are not included.

-
- -

This value will be used as the add-on's em:iconURL element in its install.rdf.

- -

The icon may be up to 48x48 pixels in size (although a bigger icon is tolerated here too)

-
icon64 {{deprecated_inline}} -
-

Note: This is deprecated along with cfx; it's not available when using jpm.

-
- -

The path to an image containing the large icon for the add-on. Defaults to icon64.png. If you don't provide an icon here, the same icon as specified by icon will be used.

- -

This value will be used as the add-on's em:icon64URL element in its install.rdf.

- -

The icon may be up to 64x64 pixels in size.

-
id -

A globally unique identifier for the add-on.

- -

This value will be used as the add-on's em:id element in its install.rdf.

- -

See the Program ID documentation.

-
lib -

String representing the top-level module directory provided in this add-on. Defaults to "lib".

- -
-

Note: This is deprecated along with cfx and is not available when using jpm.

-
-
license -

The name of the license under which the add-on is distributed, with an optional URL in parentheses. Defaults to "MPL-2.0".

- -
-

Note: It is recommend that you use an SPDX license ID.

-
-
main -

A string representing the name of a program module that is located in one of the top-level module directories specified by lib. Defaults to "main".

-
name -

The add-on's name. This name cannot contain spaces or periods, and defaults to the name of the parent directory.

- -

When the add-on is built as an XPI, if the fullName and title keys are not present, name is used as the add-on's em:name element in its install.rdf.

-
packages -
-

Note: This is deprecated along with cfx and is not available when using jpm.

-
- -

A string pointing to a directory containing additional packages. Defaults to "packages".

-
permissions -

A set of permissions that the add-on needs.

- -

private-browsing: a boolean indicating whether or not the add-on supports private browsing. If this value is not true or is omitted, then the add-on will not see any private windows or objects, such as tabs, that are associated with private windows. See the documentation for the private-browsing module.

- -

cross-domain-content: a list of domains for which content scripts are given cross-domain privileges to access content in iframes or to make XMLHTTPRequests. See the documentation for enabling cross-domain content scripts.

- -

multiprocess: a Boolean value declaring whether this add-on is, or is not, compatible with multiprocess Firefox.

- -
-

Note the multiprocess permission is not supported by cfx.

-
-
preferences -

An array of JSON objects that use the following keys: name,type, value, title, and description. These JSON objects will be used to create a preferences interface for the add-on in the Add-ons Manager.

- -

See the documentation for the simple-prefs module.

-
preferences-branchUse this to specify an alternative branch for your add-on's simple-prefs. See "Simple-prefs in the preferences system" for more details.
title -

The human-readable title of the package; this can contain spaces.

- -

If this key is present its value will be used as the add-on's em:name element in its install.rdf.

-
translators -

An array of strings listing the people who contributed to the localization of this add-on.

- -

These values will be used as the add-on's em:translator elements in its install.rdf.

- -
Note: jpm supports NodeJS people fields.
-
unpack -

Same as the unpack in an install.rdf file.

- -

Useful when the extension contains binaries.

-
updateKey -

Same as the updateKey in an install.rdf file.

- -

See Supporting updates for self-hosted add-ons.

- -
-

Note: This key is only available with jpm.

-
-
-

Same as the updateLink for an update.rdf file. Previously was --update-link in cfx.

- -

See Supporting updates for self-hosted add-ons.

- -
-

Note: This key is only available with jpm.

-
-
updateURL -

Same as the updateURL for an install.rdf file.

- -

See Supporting updates for self-hosted add-ons.

- -
-

Note: This key is only available with jpm.

-
-
version -

String representing the version of the add-on. Defaults to "0.0.1".

- -

This value is used as the add-on's em:version element in its install.rdf.

- -
-

Note: For jpm the version must be a valid semver.

-
-
- -

 

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/add_a_menu_item_to_firefox/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/add_a_menu_item_to_firefox/index.html deleted file mode 100644 index 29348bbabb..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/add_a_menu_item_to_firefox/index.html +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: Add a Menu Item to Firefox -slug: Mozilla/Add-ons/SDK/Tutorials/Add_a_Menu_Item_to_Firefox -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Add_a_Menu_Item_to_Firefox ---- -
-

学习本模块你需要 安装SDK 学习基础工具cfx.

-
-
-

如果你使用 jpm 替代cfx, 使用第三方模块的方式是不同的, 你应该阅读 jpm的相应版本替代本教程.

-

给予Python可能未来废弃,使用JPM基于nodejs(译者备注).

-
-

SDK还不能为火狐浏览器提供一个API添加新的菜单项。但它是可扩展的设计,所以任何人都可以建立和发布模块,使用插件开发者。幸运的是埃里克沃尔德写的MenuItems模块,能够使我们添加菜单项

-

本教程有双重的责任。它描述的一般方法,使用一个外部的在你的插件的第三方模块描述了如何使用特别的MenuItems模块添加一个菜单项

-

首先,创建一个新的扩展程序。创建一个目录名称为clickme(名称随意)找到它并运行cfx init初始化

-
mkdir clickme
-cd clickme
-cfx init
-
-

通常将创建目录结构:

- -
-  
-

安装 menuitems

-

在 "clickme"下创建一个名称为"packages"的目录. 从 https://github.com/mykmelez/menuitems-jplib  下载 menuitems 并展开到刚才创建的"packages" 目录下:

-
mkdir packages
-cd packages
-tar -xf ../erikvold-menuitems-jplib-d80630c.zip
-
-

模块依赖

-

如果第三方模块取决于SDK模块可以马上使用它们但如果他们依赖于其他第三方模块你需要安装依赖以及

-

在软件包的主目录,你会发现一个叫做 "package.json"的文件.  打开它,看看一个名称"dependencies"的入口.  menuitems 包的入口:

-
"dependencies": ["vold-utils"]
-
-

这告诉我们需要安装 vold-utils 包, 我们可以从https://github.com/mykmelez/vold-utils-jplib 下载,并添加到 packages 目录下的旁边的menuitems.

-

使用menuitems

-

 Menuitems模块文档 告诉使用MenuItem()创建一个新的菜单项. MenuItem()可接受的附加选项, 我们将使用最迷你的配置:

- -
-
-
var menuitem = require("menuitems").Menuitem({
-  id: "clickme",
-  menuid: "menu_ToolsPopup",
-  label: "Click Me!",
-  onCommand: function() {
-    console.log("clicked");
-  },
-  insertbefore: "menu_pageInfo"
-});
-
-  
-
-
-

接下来, 我们将声明menuitems的依赖包. 在你的add-on's package.json文件添加一行:

-
"dependencies": "menuitems"
-
-

Note that due to bug 663480, if you add a dependencies line to package.json, and you use any modules from the SDK, then you must also declare your dependency on that built-in package, like this:

-
"dependencies": ["menuitems", "addon-sdk"]
-
-

现在我们要做的。运行插件你会看到新的项目出现在工具菜单:选择它,你会看到info: clicked 出现在控制台

-

Caveats

-

第三方模块使用不直接支持的SDK功能的好方法,但由于第三方模块通常使用低级别的API它们可以通过Firefox的新版本

-

 

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/adding_a_button_to_the_toolbar/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/adding_a_button_to_the_toolbar/index.html deleted file mode 100644 index 8e4438f818..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/adding_a_button_to_the_toolbar/index.html +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: 在工具栏上添加按钮 -slug: Mozilla/Add-ons/SDK/Tutorials/Adding_a_Button_to_the_Toolbar -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Adding_a_Button_to_the_Toolbar ---- -
-

动手之前,必须先安装SDK并学习cfx基础.

- -

这篇教程使用动作按钮API,需要Firefox 29或更新版本。

-
- -

如果要给工具栏添加一个按钮,需要使用动作按钮切换按钮模块。

- -

新建一个目录,打开它,执行cfx init

- -

然后,把这三个图标保存到data文件夹:

- - - - - - - - - - - - - - - - -
icon-16.png
icon-32.png
icon-64.png
- -

随后打开lib目录下的main.js文件,添加如下代码:

- -
var buttons = require('sdk/ui/button/action');
-var tabs = require("sdk/tabs");
-
-var button = buttons.ActionButton({
-  id: "mozilla-link",
-  label: "Visit Mozilla",
-  icon: {
-    "16": "./icon-16.png",
-    "32": "./icon-32.png",
-    "64": "./icon-64.png"
-  },
-  onClick: handleClick
-});
-
-function handleClick(state) {
-  tabs.open("https://www.mozilla.org/");
-}
- -

现在输入cfx run来执行附加组件。按钮添加到了浏览器顶部的工具栏上:

- -

你无法设置按钮的初始位置,但是用回可以使用浏览器的自定义功能移动它。其中的id属性是必需的,用来记录按钮的位置,因此,你最好不要在后续版本中修改它。

- -

单击按钮,https://www.mozilla.org/将会在新的标签页中加载。

- -

设定图标

- -

icon属性可以设定单个或是一组不同大小图标。如果你用的是一组不同大小的图标,浏览器将会自动选择最适合当前屏幕分辨率的,然后显示在浏览器界面的按钮上。更多内容,参考设定多个图标

- -

图标文件必须打包在附加组件内:它不可以指向一个远程文件。

- -

你只要正确地设置了按钮的icon属性,它就会立刻生效。你可以改变全局的,在特定窗口的或者是特定标签页中显示的图标或者是其他状态属性。更多内容,参考更新状态

- -

附加一个面板

- -

如果你想把一个面板附加到按钮上,使用切换按钮API。这就和动作按钮API类似,只不过多了一个boolean值属性,表示按钮是否被checked。附加面板,要把按钮传递给面板的show()方法。更多细节,参考切换按钮文档

- -

显示更多样的内容

- -

添加按钮做不到的复杂界面功能,需要使用工具栏API。 使用工具栏API你可以得到一个用户界面内容的水平条。可以添加按钮或者是可以包含HTML,CSS,javaScript的frame到工具栏上。

- -

进一步学习

- - diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/annotator/implementing_the_widget/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/annotator/implementing_the_widget/index.html deleted file mode 100644 index 04e4a75d23..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/annotator/implementing_the_widget/index.html +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: 实现控件 -slug: Mozilla/Add-ons/SDK/Tutorials/Annotator/Implementing_the_widget -tags: - - 附加组件 -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Annotator/Implementing_the_widget ---- -

我们想要控件做两件事:

- - - -

因为控件无法区分鼠标左右键的点击,我们应当使用内容脚本来捕获单击事件并发送相应的消息到附加组件。

- -

控件将有两个图标:一个在注释器启用时显示,一个在禁用时显示。

- -

因此,我们需要创建三个文件:控件的内容脚本和两个图标。

- -

在data子目录创建一个widget子目录,我们将把控件的文件保存在这里(注意,这个不是强制性的:你可以仅仅把它们放在data里,但分类放置会更加整洁)。

- -

控件的内容脚本

- -

控件的内容脚本仅仅监听鼠标的左右单击并发送相应的消息到附加组件代码:

- -
this.addEventListener('click', function(event) {
-  if(event.button == 0 && event.shiftKey == false)
-    self.port.emit('left-click');
-
-  if(event.button == 2 || (event.button == 0 && event.shiftKey == true))
-    self.port.emit('right-click');
-    event.preventDefault();
-}, true);
- -

把它保存在data/widget并命名为widget.js。

- -

控件图标

- -

你可以从这里复制图标:

- -

- -

或者自己动手做你觉得有创造性的图标。把它们保存在data/widget目录。

- -

main.js

- -

现在在lib目录创建main.js并添加下列内容:

- -
var widgets = require('sdk/widget');
-var data = require('sdk/self').data;
-
-var annotatorIsOn = false;
-
-function toggleActivation() {
-  annotatorIsOn = !annotatorIsOn;
-  return annotatorIsOn;
-}
-
-exports.main = function() {
-
-  var widget = widgets.Widget({
-    id: 'toggle-switch',
-    label: 'Annotator',
-    contentURL: data.url('widget/pencil-off.png'),
-    contentScriptWhen: 'ready',
-    contentScriptFile: data.url('widget/widget.js')
-  });
-
-  widget.port.on('left-click', function() {
-    console.log('activate/deactivate');
-    widget.contentURL = toggleActivation() ?
-              data.url('widget/pencil-on.png') :
-              data.url('widget/pencil-off.png');
-  });
-
-  widget.port.on('right-click', function() {
-      console.log('show annotation list');
-  });
-}
- -

注释器默认禁用。它创建控件并通过切换注释器的活动状态来回应来自控件内容脚本的消息。注意,由于bug 626326,附加组件状态栏的环境菜单会显示,尽管在控件的内容脚本中调用了event.preventDefault()。由于我们没有任何代码来显示注释,所以我们们仅仅记录右击事件到控制台。

- -

现在在注释器目录输入cfx run,你应该看见在附加组件状态栏的控件:

- -

- -

左击和右击应当产生合适的调试输出,同时左击应当改变控件的图标为启用状态。

- -

 

- -

下一步,我们将添加代码来创建注释器

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/annotator/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/annotator/index.html deleted file mode 100644 index 4f76d67802..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/annotator/index.html +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: 注释器(Annotator) -slug: Mozilla/Add-ons/SDK/Tutorials/Annotator -tags: - - 附加组件 -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Annotator ---- -
-

请注意教程中Widget API适合的浏览器版本。(译者注)

-
- -

在这个教程中,我们将构建一个使用许多SDK高级API的附加组件.

- -

这个附加组件是一个注释器:它可以让用户选择网页的元素并输入有关的笔记(注释).注释器储存笔记.无论用户何时载入包含被注释元素的页面,这些元素都将会高亮显示,并且用户若把鼠标移动到被注释元素的上面,将会显示它的注释.

- -

接着我们将给出这个注释器设计的快速简介,然后一步步的讨论如何实现.

- -

如果你想参阅完整的附加组件,你可以在SDK例子目录找到它.

- - diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/annotator/overview/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/annotator/overview/index.html deleted file mode 100644 index da94f8142a..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/annotator/overview/index.html +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: 概述 -slug: Mozilla/Add-ons/SDK/Tutorials/Annotator/Overview -tags: - - addon sdk example - - annotator example - - 附加组件 -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Annotator/Overview ---- -

注释器使用内容脚本(content scripts)来构建用户界面,得到用户输入,并检查用户载入页面的DOM。

- -

同时,主要模块包括程序逻辑和调节不同SDK对象的交互。

- -

我们可以描述在主要模块和不同内容脚本的交互,像这样:

- -

- -

用户界面

- -

注释器的主要用户界面由一个控件和三个面板组成。

- - - -

除此之外,我们使用 notifications 模块来告知用户附加组件的储存限额已满。

- -

用DOM工作

- -

我们将使用 page-mods 来和用户打开的网页的DOM进行交互。

- - - -

处理数据

- -

我们将使用simple-storage模块来储存数据。

- -

由于我们将记录潜在的敏感信息,我们想阻止用户在隐私浏览模式下创建注释,最简单的方式是删除附加组件中“package.json“文件的”private-browsing"键。这样,附加组件就不能看见任何隐私浏览窗口,同时注释器的控件也将不再出现。

- -

开始行动

- -

现在让我们来创建叫“注释器”的目录。Navigate to it and type cfx init.

- -

下一步,我们将实现控件

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/display_a_popup/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/display_a_popup/index.html deleted file mode 100644 index 9bec4966d4..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/display_a_popup/index.html +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: 显示弹出对话框 -slug: Mozilla/Add-ons/SDK/Tutorials/Display_a_Popup -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Display_a_Popup ---- -
-

动手之前,必须先安装SDK并学习cfx基础知识.

-

T这篇教程使用动作按钮API需要Firefox 29或更新版本。

-
-

可以使用面板(panel)模块来显示弹出对话框。面板的内容通过HTML编写。你可以在面板上运行content script:尽管在面板里的脚本无法直接访问插件代码,但是你可以在面板脚本和插件代码间交换信息。

-

这里,我们做了一个会在单击时显示面板的动作按钮。面板上有一个<textarea>元素:用户按下return键时,<textarea>的内容会被发送给插件代码主程序。插件代码主程序会在控制台输出日志。.

-

The add-o插件由六个文件组成n consists of six files:

- -

"main.js"像这样:

-
var data = require("sdk/self").data;
-// 构造面板,从"data"目录的"text-entry.html"加载
-// 内容,然后加载"get-text.js"脚本。
-var text_entry = require("sdk/panel").Panel({
-  contentURL: data.url("text-entry.html"),
-  contentScriptFile: data.url("get-text.js")
-});
-
-// 创建按钮
-require("sdk/ui/button/action").ActionButton({
-  id: "show-panel",
-  label: "Show Panel",
-  icon: {
-    "16": "./icon-16.png",
-    "32": "./icon-32.png",
-    "64": "./icon-64.png"
-  },
-  onClick: handleClick
-});
-
-// 在用户点击按钮时显示面板。
-function handleClick(state) {
-  text_entry.show();
-}
-
-// When the panel is displayed it generated an event called
-// "show": we will listen for that event and when it happens,
-// send our own "show" event to the panel's script, so the
-// script can prepare the panel for display.
-text_entry.on("show", function() {
-  text_entry.port.emit("show");
-});
-
-// 监听来自content脚本的text-entered消息。消息主体L是用户输入的文本。
-// 此实现,我们只在控制台显示日志。
-text_entry.port.on("text-entered", function (text) {
-  console.log(text);
-  text_entry.hide();
-});
-

content脚本"get-text.js"像这样:

-
-
// 用户按下回车,发送text-entered消息给main.js。
-// 消息主体是编辑框的内容。
-var textArea = document.getElementById("edit-box");
-textArea.addEventListener('keyup', function onkeyup(event) {
-  if (event.keyCode == 13) {
-    // Remove the newline.
-    text = textArea.value.replace(/(\r\n|\n|\r)/gm,"");
-    self.port.emit("text-entered", text);
-    textArea.value = '';
-  }
-}, false);
-// 监听由插件主程序发送的show事件。表示面板将要显示。
-//
-// 焦点放在textarea上,这样用户可以直接开始输入。
-self.port.on("show", function onShow() {
-  textArea.focus();
-});
-
-  
-
-

最后,"text-entry.html"文件定义了<textarea>元素:

-
-
-
<html>
-<head>
-    <style type="text/css" media="all">
-      textarea {
-        margin: 10px;
-      }
-      body {
-        background-color: gray;
-      }
-    </style>
-  </head>
-<body>
-    <textarea rows="13" cols="33" id="edit-box"></textarea>
-  </body>
-</html>
-
-  
-
-
-

最后,把这三个图标文件保存在"data"目录:

- - - - - - - - - - - - - - - -
icon-16.png
icon-32.png
icon-64.png
-

试用以下:保存在lib目录,其他五个文件存放在插件的data目录:

-
my-addon/
-         data/
-              get-text.js
-              icon-16.png
-              icon-32.png
-              icon-64.png
-              text-entry.html
-         lib/
-             main.js
-
-

运行插件,点击按钮,你就会看见一个面板。输入几行文本,然后按下回车,你就会看见控制台里的输出。

-

自Firefox 30起,如果你使用切换按钮,就可以给它附加一个面板

-

进一步学习

-

学习panel模块的更多内容,见panel API参考

-

学习关于按钮的更多内容,见动作按钮切换按钮API参考。

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/getting_started/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/getting_started/index.html deleted file mode 100644 index 225739de76..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/getting_started/index.html +++ /dev/null @@ -1,172 +0,0 @@ ---- -title: 快速入门 -slug: Mozilla/Add-ons/SDK/Tutorials/Getting_started -tags: - - add-on sdk开发 - - cfx工具基础使用教程 - - 火狐扩展程序 -translation_of: Mozilla/Add-ons/SDK/Tutorials/Getting_Started_%28jpm%29 ---- -

{{AddonSidebar}}

- -
-

Add-on SDK 里包含了一个命令行工具,你可以用此工具来初始化、运行、测试以及打包 add on。 这个工具称为 jpm,基于 Node.js 。它替代了以前的cfx工具。

- -

你可以在 Firefox 38或之后的版本中使用。

- -

本文阐述如何使用 jpm 开发。

-
- -

本教程会过一遍使用 SDK 创建一个简单 add-on 的过程。

- -

准备

- -

要使用 SDK 创建 add-on,你需要:

- - - -

初始化空的 add-on

- -

在命令行提示符下,创建一个新目录。进入新文件夹,键入 jpm init,然后敲回车

- -
mkdir my-addon
-cd my-addon
-jpm init
-
- -

接着你会被要求提供一些关于你的 add-on 的信息:这会用来创建 package.json 文件。如果光按回车的话,就表示接受属性的默认值。关于 jpm init 的更多信息,参看 jpm command reference.

- -

一旦你设置了这些属性的值或者接受默认值,你会看到 "package.json" 的完整内容并被询问是否接受这些设置。

- -

实现 add-on

- -

现在你可以写 add-on 的代码了。除非你修改了"entry point"的值(package.json 中的 "main"),一般情况将从你的 add-on 的根目录下的"index.js"文件开始。这个文件就是在之前步骤中创建的。打开这个文件并且添加以下代码:

- -
var buttons = require('sdk/ui/button/action');
-var tabs = require("sdk/tabs");
-
-var button = buttons.ActionButton({
-  id: "mozilla-link",
-  label: "Visit Mozilla",
-  icon: {
-    "16": "./icon-16.png",
-    "32": "./icon-32.png",
-    "64": "./icon-64.png"
-  },
-  onClick: handleClick
-});
-
-function handleClick(state) {
-  tabs.open("http://www.mozilla.org/");
-}
-
- -
-

注意在jpm中"entry point"的默认值为"index.js",意思是你的主文件是"index.js",且在你的 add-on的根目录下。

- -

cfx中,入口默认是"main.js",并且在"lib"目录下

-
- -

保存文件

- -

接下来,在根目录下创建目录"data"

- -
mkdir data
-
- -

并保存这三个图标文件到"data"目录:

- - - - - - - - - - - - - - - - -
icon-16.png
icon-32.png
icon-64.png
- -

返回命令行,键入:

- -
jpm run
- -

这个 jpm 命令会运行一个带有你的 add-on 的 Firefox 的新实例。

- -

如果找不到 Firefox,你可能要为它提供一个路径(如在Ubuntu中):

- - -
jpm run -b /usr/bin/firefox
- -

Firefox 启动以后,在浏览器右上角你能看到一个 Firefox logo 的图标。点击该图标,就会打开一个新标签页 http://www.mozilla.org/

- -

这就是这个 add-on 的全部功能了。它用到了 SDK 的两个模块:action button 模块,使你能加个按钮到浏览器上,以及 tabs 模块,使你能完成对标签页的基本操作。本例中,我们以及创建了一个图标是Firefox图标的按钮,并添加一个点击处理程序,可以在新标签页中打开 Mozilla 页面。

- -

试着编辑这个文件。例如,我们可以改变加载的页面:

- -
var buttons = require('sdk/ui/button/action');
-var tabs = require("sdk/tabs");
-
-var button = buttons.ActionButton({
-  id: "mozilla-link",
-  label: "Visit Mozilla",
-  icon: {
-    "16": "./icon-16.png",
-    "32": "./icon-32.png",
-    "64": "./icon-64.png"
-  },
-  onClick: handleClick
-});
-
-function handleClick(state) {
-  tabs.open("https://developer.mozilla.org/");
-}
- -

在命令行提示符下,再次执行 jpm run。这次点击按钮,它会带你到 https://developer.mozilla.org/ 页面。

- -

打包 add-on

- -

当你完成了 add-on 并准备发布它,你会需要把它打包为 XPI 文件。你能自己分发 XPI 文件,也可以把它们发布到 https://addons.mozilla.org,这样其他用户就能下载并按照它们。

- -

要构建 XPI,只要在 add-on 的根目录下运行命令 jpm xpi

- -
jpm xpi
-
- -

你应该看到像这样的信息:

- -
JPM info Successfully created xpi at /path/to/my-addon/@my-addon-0.0.1.xpi
-
- -

要测试附加组件是否能正常运行,可以尝试在你自己的火狐中安装 XPI 文件。你可以在 Firefox 中按 Ctrl+O 组合键(Mac 中是 Cmd+O),或者选择"文件"菜单里的“打开”。这样会弹出一个文件选择对话框:转到"@my-addon.xpi"文件,打开并按照提示安装 add-on。

- -

注意 Firefox 默认需要 add-on 有签名,即使是本地开发的 add-on。安装完后他们会在已安装的 add-on 列表中出现,只因没有签名而被禁用。开发的时候,又或者你不准备发布,你可以打开 about:config 设置 xpinstall.signatures.requiredfalse 来运行未经签名的组件。这个设置会应用到所有的 add-on,所以要十分小心,不要一不当心从别的地方安装了恶意组件。

- -

要发布你的 add-on,请提交 XPI 文件到 addons.mozilla.org 或者如果你想在你自己的服务器上发布,运行 jpm sign

- -

总结

- -

本教程中我们使用了下面三个命令来构建和打包 add-on :

- - - -

这是你在开发SDK add-on会用到的三个主要命令。完全的参考文档包含了所以你能使用的命令,以及这些命令的可选项。

- -

这次开发的add-on 的代码用到了两个 SDK 模块,action buttontabs。这儿有参考文档,描述 SDK 中所有高层次低层次的 API。

- -

下一步?

- -

要了解你能用 SDK API 做些什么,试着继续阅读教程

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/getting_started_(jpm)/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/getting_started_(jpm)/index.html deleted file mode 100644 index e09d6d4e55..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/getting_started_(jpm)/index.html +++ /dev/null @@ -1,162 +0,0 @@ ---- -title: JPM 入门! -slug: Mozilla/Add-ons/SDK/Tutorials/Getting_Started_(jpm) -tags: - - JPM - - add-on -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Getting_Started_(jpm) ---- -
-

该附加SDK包含一个用于初始化,运行,测试和打包加载项的命令行工具。当前工具称为jpm,并且基于  Node.js .它替代了旧的cfx工具。

- -

Firefox 38 以上的版本才可以使用jpm。

- -

本文介绍如何使用jpm开发。

-
- -

本教程将介绍使用SDK创建一个简单的附加组件。

- -

先决条件

- -

要使用SDK为Firefox创建附加组件,您需要:

- - - -

初始化一个空的附加组件

- -

在命令提示符下,创建一个新目录。导航到它,键入 jpm init, 然后按Enter键

- -
mkdir my-addon
-cd my-addon
-jpm init
-
- -

You'll then be asked to supply some information about your add-on: this will be used to create your add-on's package.json file. For now, just press Enter to accept the default for each property. For more information on jpm init, see the jpm command reference.

- -

Once you've supplied a value or accepted the default for these properties, you'll be shown the complete contents of "package.json" and asked to accept it.

- -

实现附加组件

- -

Now you can write the add-on's code. Unless you've changed the value of "entry point" ("main" in package.json), this goes in "index.js" file in the root of your add-on. This file was created for you in the previous step. Open it and add the following code:

- -
var buttons = require('sdk/ui/button/action');
-var tabs = require("sdk/tabs");
-
-var button = buttons.ActionButton({
-  id: "mozilla-link",
-  label: "Visit Mozilla",
-  icon: {
-    "16": "./icon-16.png",
-    "32": "./icon-32.png",
-    "64": "./icon-64.png"
-  },
-  onClick: handleClick
-});
-
-function handleClick(state) {
-  tabs.open("http://www.mozilla.org/");
-}
-
- -
-

Note that "entry point" defaults to "index.js" in jpm, meaning that your main file is "index.js", and it is found directly in your add-on's root.

- -

In cfx, the entry point defaults to "main.js", and is located in the "lib" directory under the add-on's root.

-
- -

Save the file.

- -

Next, create a directory called "data" in your add-on's root, and save these three icon files to the "data" directory:

- - - - - - - - - - - - - - - - -
icon-16.png
icon-32.png
icon-64.png
- -

Back at the command prompt, type:

- -
jpm run
- -

This is the jpm command to run a new instance of Firefox with your add-on installed.

- -

If Firefox can not be located, you may need to provide the path to it (example in Ubuntu):

- - -
jpm run -b /usr/bin/firefox
- -

When Firefox launches, in the top-right corner of the browser you'll see an icon with the Firefox logo. Click the icon, and a new tab will open with http://www.mozilla.org/ loaded into it.

- -

That's all this add-on does. It uses two SDK modules: the action button module, which enables you to add buttons to the browser, and the tabs module, which enables you to perform basic operations with tabs. In this case, we've created a button whose icon is the Firefox icon, and added a click handler that loads the Mozilla home page in a new tab.

- -

Try editing this file. For example, we could change the page that gets loaded:

- -
var buttons = require('sdk/ui/button/action');
-var tabs = require("sdk/tabs");
-
-var button = buttons.ActionButton({
-  id: "mozilla-link",
-  label: "Visit Mozilla",
-  icon: {
-    "16": "./icon-16.png",
-    "32": "./icon-32.png",
-    "64": "./icon-64.png"
-  },
-  onClick: handleClick
-});
-
-function handleClick(state) {
-  tabs.open("https://developer.mozilla.org/");
-}
- -

At the command prompt, execute jpm run again. This time clicking it takes you to https://developer.mozilla.org/.

- -

Packaging the add-on

- -

When you've finished the add-on and are ready to distribute it, you'll need to package it as an XPI file. This is the installable file format for Firefox add-ons. You can distribute XPI files yourself or publish them to https://addons.mozilla.org so other users can download and install them.

- -

To build an XPI, just execute the command jpm xpi from the add-on's directory:

- -
jpm xpi
-
- -

You should see a message like:

- -
JPM info Successfully created xpi at /path/to/getting-started/@getting-started.xpi
-
- -

To test that this worked, try installing the XPI file in your own Firefox installation. You can do this by pressing the Ctrl+O key combination (Cmd+O on Mac) from within Firefox, or selecting the "Open" item from Firefox's "File" menu. This will bring up a file selection dialog: navigate to the "@getting-started.xpi" file, open it and follow the prompts to install the add-on.

- -

Summary

- -

In this tutorial we've built and packaged an add-on using three commands:

- - - -

These are the three main commands you'll use when developing SDK add-ons. There's comprehensive reference documentation covering all the commands you can use and all the options they take.

- -

The add-on code itself uses two SDK modules, action button and tabs. There's reference documentation for all the high-level and low-level APIs in the SDK.

- -

What's next?

- -

To get a feel for some of the things you can do with the SDK APIs, try working through some of the tutorials.

- -

 

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/index.html deleted file mode 100644 index 03173c3219..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/index.html +++ /dev/null @@ -1,144 +0,0 @@ ---- -title: 教程 -slug: Mozilla/Add-ons/SDK/Tutorials -tags: - - 插件SDK -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials ---- -

{{LegacyAddonsNotice}}{{AddonSidebar}}

- -

本文列出了许多关于如何通过SDK完成特定任务要求的实际动手的文章。

- -
-

开发之旅

- -
-
-
-
安装
-
在Windows, OS X和Linux上下载,安装,初始化SDK工具。
-
- -
-
常见问题
-
解决常见问题的建议和获取更多帮助。
-
-
- -
-
-
快速开始
-
走马观花地使用SDK开发一个简单的扩展
-
-
-
- -
-

创建用户交互界面

- -
-
-
-
添加一个工具按钮
-
添加一个按钮到火狐Add-on工具栏。
-
添加一个菜单选项到火狐
-
添加多个菜单选项到火狐主菜单。
-
-
- -
-
-
显示一个弹出对话框
-
通过HTML和JavaScript实现并显示一个弹窗对话框。
-
添加一个上下文菜单
-
添加一个上下文菜单(一般都是右键菜单)到火狐浏览器
-
-
-
- -
-

与浏览器交互

- -
-
-
-
打开Web页面
-
在一个新的浏览器选项卡里打开一个Web页面或窗口使用tabs模块并获取内容。
-
监听页面加载
-
当新页面载入时使用tabs模块得到通知并获取页面内容。
-
-
- -
-
-
获取打开的选项卡(Tab)列表
-
使用tabs模块遍历当前打开的tab,并获取其内容。
-
-
-
- -
-

更改网页

- -
-
-
-
更改网页通过URL
-
基于URL过滤网页:当载入的页面的URL与过滤器匹配时执行特定的脚本。
-
-
- -
-
-
修改页面内容
-
动态加载脚本到当前页面。
-
-
-
- -
-

开发技术

- -
-
-
-
日志
-
在终端中记录日志以便调试。
-
创建可复用的模块
-
拆分扩展程序为多个分离的模块,可以使开发调试和维护更加简单。封装你的模块使其成为可复用的包,以便其他开发者可以再次使用。
-
单元测试
-
使用SDK的测试框架书写和进行单元测试。
-
Chrome授权
-
获得Components对象,使你的扩展程序能够加载和使用任何XPCOM对象。
-
创建事件目标
-
使你定义的对象能够响应相关事件。
-
-
- -
-
-
监听载入和卸载
-
当你的扩展程序被加载和卸载时获得通知,并从终端传递参数给扩展程序。
-
使用第三方模块
-
安装和使用与SDK无关额外的模块
-
本地化
-
书写本地化代码.
-
移动开发
-
为Andriod上的火狐浏览器开发扩展程序。
-
扩展调试
-
调试扩展应用的JavaScript。
-
-
-
- -
-

打包

- -
-
-
-
扩展应用:Annotator
-
一起开发一个相对复杂的扩展应用。
-
-
-
diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/installation/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/installation/index.html deleted file mode 100644 index 4313836979..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/installation/index.html +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: 安装 -slug: Mozilla/Add-ons/SDK/Tutorials/Installation -tags: - - cfx安装 - - 配置cfx环境 -translation_of: Mozilla/Add-ons/SDK/Tools/jpm#Installation ---- -

先决条件

- -

请不要把任何相关的开发工具和扩展程序(命名推荐小写英文和数字,不推荐特殊符号等),放到有空格的目录(如Progaram Files\Python),会导致意想不到的错误,无法进行后续操作。(最新开发SDK可能修复了该错误,参见https://github.com/mozilla/addon-sdk/pull/1738)

- -

开发 Add-on SDK,你需要:

- - - -

另外,可以从它GitHub repository库中得到最新的开发版本

- -

为AMO开发扩展

- -

如果提交到AMO只有最新发布或许使用。

- -

git archive 需要扩展一些Git属性占位符

- -
git checkout 1.16
-
-git archive 1.16 python-lib/cuddlefish/_version.py | tar -xvf -
- -

通过Homebrew自动安装到Mac OS X

- -

使用以下命令通过 homebrew来安装SDK插件工具:

- -
brew install mozilla-addon-sdk
- -

安装到Mac OS X/Linux

- -

无论你选择哪个方式都要解压缩文件的内容作为根路径,并通过shell/命令提示符切换到SDK的根目录下例如:

- -
tar -xf addon-sdk.tar.gz
-cd addon-sdk
-
- -

如果你是Bash的用户,则继续运行(大多数人都是的):

- -
source bin/activate
-
- -

如果你是一个非Bash的用户你应该运行

- -
bash bin/activate
-
- -

命令提示符现在应该有一个包含SDK的目录名称的新的前缀

- -
(addon-sdk)~/mozilla/addon-sdk >
-
- -

安装到Windows

- -

同样解压缩文件,并通过命令符进入到SDK根目录下,例如:

- -
7z.exe x addon-sdk.zip
-cd addon-sdk
-
- -

接着运行激活命令:

- -
bin\activate
-
- -

同样可以看到命令提示符现在应该有一个包含SDK的目录名称新的前缀

- -
(C:\Users\mozilla\sdk\addon-sdk) C:\Users\Work\sdk\addon-sdk>
-
- -

SDK 的虚拟环境

- -

当命令提示符出现新的前缀表明你的已经搭建好了SDK的运行环境,那么你就可以使用Add-on SDK来开发命令行工具

- -

任何时候,你都可以通过运行 deactivate 命令停用虚拟环境.

- -

配置好的虚拟环境是特定于这个特定的命令提示符。如果您关闭命令提示符, 它会关闭运行环境,你需要source bin/activate bin\activate 在一个新的命令提示符重新激活它。如果你打开一个新命令提示符SDK将不会被激活在新的提示

- -

可以将SDK的多个副本拷贝在磁盘上的不同位置,并在它们之间切换,甚至可以让他们同时激活运行在不同的命令提示

- -

制作启动项

- -

所有 activate 的作用是通过设置环境变量,使位于顶层 bin 目录下的脚本 位于当前命令符下,制作的启动项 ,通过永久环境中的这些变量设置,以便每一个新的命令提示符下都能读取它们那么就不需要每次都去打开新的命令提示符来激活 activate

- -

因为变量精确设置可能随SDK发布新版本的变化,所以最好是指激活脚本来确定哪些变量需要设置。激活使用不同的脚本设置bash环境不同的变量LinuxMAC OS X和Windows环境

- -

Windows

- -

在Windows上,使用 bin\activate\activate.bat批处理脚本,也可以使用命令行setx工具或控制面板激活永久使用

- -

Linux/Mac OS X

- -

在 Linux 和 Mac OS X,使用source bin/activate/activate bash 脚本, 你可以 ~/.bashrc ( Linux) 或~/.bashprofile (Mac OS X) 来激活。

- -

作为替代,你可以在 ~/bin 目录中创建到cfx 程序的符号链接

- -
ln -s PATH_TO_SDK/bin/cfx ~/bin/cfx
-
- -

完整性检查

- -

在shell提示符运行:

- -
cfx
-
- -

它会产生下面信息,这里是第一行内容,后面大量的使用信息

- -
Usage: cfx [options] [command]
-
- -

这是 CFX命令行程序界面加载项的SDK可以使用它来启动Firefox和测试插件,打包附加分发,查看​​文档和运行单元测试

- -

出现问题?

- -

尝试通过故障排除页面来解决遇到的问题。

- -

下一步

- -

接下来, 开始学习 cfx 教程, 其中介绍了如何使用CFX的工具来创建附加组件

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/l10n/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/l10n/index.html deleted file mode 100644 index 5083be5b5c..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/l10n/index.html +++ /dev/null @@ -1,381 +0,0 @@ ---- -title: Localization -slug: Mozilla/Add-ons/SDK/Tutorials/l10n -tags: - - Add-on SDK - - 本地化 -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/l10n ---- -

该SDK支持本地化字符串出现在:

- - - -

目前为止还不支持本地化CSS和content scripts。

- -

本地化字符串

- -

翻译后的字符串都保存在你的add-on扩展目录下一个名为 "locale"的目录 ,每个本地化地域对应一个文件。这些文件:

- - - -

假设你的附加组件包含一个单一的本地化字符串,用英语表示为“Hello!”,你想提供英语和法语的本地化支持。

- -

你需要添加两个文件到"locale"目录:

- -
my-addon/
-         data
-         lib
-         locale/
-                en-US.properties
-                fr-FR.properties
-
- -

"en-US.properties" 文件中内容:

- -
hello_id= Hello!
-
- -

"fr-FR.properties" 文件中内容:

- -
hello_id= Bonjour !
-
- -

现在,每当你的JavaScript或HTML向本地化系统请求hello_id标识的翻译,它将获得与当前区域语言一致的翻译。

- -

在HTML中使用本地化字符串

- -
-

本例使用的 action button API需要 Firefox 29 或者更高版本。

-
- -

要从HTML中引用本地化字符串,需要添加一个 data-l10n-id 的属性,到你想本地化的字符串所属的HTML标签中,然后为该属性指定一个ID值(To reference localized strings from HTML, add a data-l10n-id attribute to the HTML tag where you want the localized string to appear, and assign the identifier to it):

- -
<html>
-  <body>
-    <h1 data-l10n-id="hello_id"></h1>
-  </body>
-</html>
-
- -

然后你就可以使用这个HTML文件来建立你的界面, 比如插入一个 panel 面板:

- -
var button = require("sdk/ui/button/action").ActionButton({
-  id: "localized-hello",
-  label: "Localized hello",
-  icon: "./icon-16.png",
-  onClick: function() {
-    hello.show();
-  }
-});
-
-var hello = require("sdk/panel").Panel({
-  height: 75,
-  width: 150,
-  contentURL: require("sdk/self").data.url("my-panel.html")
-});
- -

“en-US”和“fr-FR”提供了翻译标识为hello_id字符串的本地化文件,面板将根据当前区域语言设置,显示“Hello!”或者“Bonjour!”:

- -

- -

翻译文本会插入到具有data-l10n-id属性集的节点中。任何之前存在的内容只是被替换掉了。(The translation is inserted into the node which has the data-l10n-id attribute set. Any previously existing content is just replaced.)

- -

本地化字符串只能作为text文本插入, 所以你不能使用下面的语句插入HTML:

- -
hello_id= <blink>Hello!</blink>
-
- -

Localizing Element Attributes

- -
这是 Firefox 39 上的新功能
- -


- 你可以在properties文件中,通过设置 l10n-id.attributeName 的值,本地化某些具有 l10n-id属性的元素的属性值。像这样(You can localize certain attributes of elements with an l10n-id by setting its value with l10n-id.attributeName in the properties file like):
-  

- -
hello_id.accesskey= H
- -

可以支持以下几个属性:

- - - -

更多的 ARIA 属性aria-label, aria-valuetextaria-moz-hint 的本地化将通过在Firefox OS上同样的别名被支持(Further the localization of the ARIA attributes aria-label, aria-valuetext and aria-moz-hint are supported with the same aliases as on Firefox OS):

- - - -

在JavaScript代码中使用本地化字符串

- -

为了在主附加组件代码中引用本地化字符串,你需要这样做:

- -
var _ = require("sdk/l10n").get;
-console.log(_("hello_id!"));
- -

指定的 "_" 并不是必需的,但是作为 gettext 工具的默认约定,这能更好的配合其他默认使用 "_" 来表示本地化字符串的现有工具。

- -
    -
  1. 导入 l10n 模块,然后指定 "_" (下划线)为模块的 get 函数。
  2. -
  3. 把所有涉及本地化的字符串放到 _() 函数中包括起来。
  4. -
- -

如果你运行它,你会看到输出为预期的当前设置的区域语言:

- -
info: Hello!
-
- -
info: Bonjour !
-
- -

注意你不能在content scripts中 require() 一个模块,所以目前还不能在content script 中引用本地化字符串。

- -

复数

- -

 l10n 模快支持复数形式,不同的语言有不同的复数形态。例如,英语有两种形式:相对于"one"的单数形式,和对于"everything else, including zero"的复数形式:

- -
one tomato
-no tomatoes
-two tomatoes
-
- -

但是俄罗斯语对于以 1 结尾(除了11)的数字、以 2-4 结尾(除了12-14)的数字和其他数字,有着不同的复数形态:

- -
один помидор     // one tomato
-два помидора     // two tomatoes
-пять помидоров   // five tomatoes
-
- -

SDK使用 Unicode CLDR 数据描述由不同的语言使用的不同复数形式。

- -

Unicode CLDR 复数形式

- -

Unicode CLDR项目定义了用于描述一个特定语言的多个规则的一种方案。在这个方案中一种语言对应最多有六种不同的范围的数字,有以下类别区分:zero(零个),one(一个),two(两个),few(几个),many(很多),other(其他)。(The Unicode CLDR project defines a scheme for describing a particular language's plural rules. In this scheme a language maps each distinct range of numbers on to one of up to six forms, identified by the following categories: zero, one, two, few, many, and other.)

- -

英语有两种复数形式,可以表示为 "1" 映射到 "one" 和 "everything else" 映射到 "other"的形式(English has two forms, which can be described by mapping "1" to "one" and "everything else" to "other"):

- -
one   → n is 1;
-other → everything else
-
- -

俄罗斯语有四种形式,可以使用以下方式表示:

- -
one   → n mod 10 is 1 and n mod 100 is not 11;
-few   → n mod 10 in 2..4 and n mod 100 not in 12..14;
-many  → n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14;
-other → everything else
-
- -

所有语言的多个规则可以在CLDR的 语言复数规则 页面查到 (即使这个规则表相对于 CLDR XML source 已经过时了).

- -

SDK中的复数形式

- -

代码中,在 _()函数中的本地化ID参数之后提供一个额外的参数,用来表示代表多少个项的本地化字符串(In the code, you supply an extra parameter alongside the identifier, describing how many items there are):

- -
var _ = require("sdk/l10n").get;
-console.log(_("tomato_id"));
-console.log(_("tomato_id", 1));
-console.log(_("tomato_id", 2));
-console.log(_("tomato_id", 5));
-console.log(_("tomato_id", .5));
- -

.properties 文件中通过使用 CLDR 关键字,对于每种语言可能的复数形式你可以自定义不同的本地化字符串。所以对于英语可以有两种本地化(注意"other" 分类不是 CDLR 关键字)。(In the .properties file for each language you can define a different localization for each plural form possible in that language, using the CLDR keywords. So in English we could have two plural localizations (note that the "other" category does not take the CLDR keyword))

- -
# en-US translations
-tomato_id[one]= %d tomato
-tomato_id= %d tomatoes
-
- -

俄罗斯语中可以定义四种本地化的复数形式:

- -
# ru-RU translations
-tomato_id[one]= %d помидор
-tomato_id[few]= %d помидора
-tomato_id[many]= %d помидоров
-tomato_id= %d помидоры
-
- -

The localization module itself understands the CLDR definitions for each language, enabling it to map between, for example, "2" in the code and "few" in the ru-RU.properties file. Then it retrieves and returns the localization appropriate for the count you supplied.

- -

Placeholders

- -

The l10n module supports placeholders, allowing you to insert a string which should not be localized into one which is. The following "en-US" and "fr-FR" ".properties" files include placeholders:

- -
# en-US translations
-hello_id= Hello %s!
-
- -
# fr-FR translations
-hello_id= Bonjour %s !
-
- -

To use placeholders, supply the placeholder string after the identifier:

- -
var _ = require("sdk/l10n").get;
-console.log(_("hello_id", "Bob"));
-console.log(_("hello_id", "Alice"));
- -

In the "en-US" locale, this gives us:

- -
info: Hello Bob!
-info: Hello Alice!
-
- -

In "fr-FR" we get:

- -
info: Bonjour Bob !
-info: Bonjour Alice !
-
- -

Ordering Placeholders

- -

When a localizable string can take two or more placeholders, translators can define the order in which placeholders are inserted, without affecting the code.

- -

Primarily, this is important because different languages have different rules for word order. Even within the same language, though, translators should have the freedom to define word order.

- -

For example, suppose we want to include a localized string naming a person's home town. There are two placeholders: the name of the person and the name of the home town:

- -
var _ = require("sdk/l10n").get;
-console.log(_("home_town_id", "Bob", "London"));
- -

An English translator might want to choose between the following:

- -
"<town_name> is <person_name>'s home town."
-
- -
"<person_name>'s home town is <town_name>"
-
- -

To choose the first option, the .properties file can order the placeholders as follows:

- -
home_town_id= %2s is %1s's home town.
-
- -

This gives us the following output:

- -
info: London is Bob's home town.
-
- -

在首选项设置中的本地化字符串

- -

通过加入一个 "preferences" 字段的结构到你的附加组件的 "package.json" 文件中,你可以为你的附加组件定义首选项选项,用户可以在Firefox的 Add-ons Manager 看到和编辑它。

- -

Preferences (首选项)有一个必需的title标题项和一个可选的description描述项 这些字符串将出现在 Add-ons Manager中,来帮助向用户解释各个首选项设置的意义。

- - - -

例如, 假设你的 "package.json" 中只定义了一个设置选项:

- -
{
-    "preferences": [
-        {
-            "type": "string",
-            "name": "monster_name",
-            "value": "Gerald",
-            "title": "Name"
-        }
-    ],
-    "name": "monster-builder",
-    "license": "MPL 2.0",
-    "author": "me",
-    "version": "0.1",
-    "fullName": "Monster Builder",
-    "id": "monster-builder@me.org",
-    "description": "Build your own monster"
-}
-
- -

在你的"en-US.properties"文件中, 应该包括下面两个项:

- -
monster_name_title= Name
-monster_name_description= What is the monster's name?
-
- -

在你的"fr-FR.properties"文件中, 应该包括下面两个法语的翻译项:

- -
monster_name_title= Nom
-monster_name_description= Quel est le nom du monstre ?
-
- -

现在,当浏览器的区域设置为 "en-US", 用户会在 Add-ons Manager看到这样:

- -

- -

当浏览器区域设置为 "fr-FR", 用户会看到:

- -

- -

下拉菜单menulist和单选按钮radio的类型有多个选项,每一个选项的标签属性都会展示给用户。如果本地化文件中有一项是以前缀是"{name} _options" 为键的键值对,其中"{name}"是选项的标签名字,该键值对的值就是一个选项标签的本地化字符串。(The menulist and the radio preference types have options. The label attribute of each option is displayed to the user. If the locale file has a entry with the value of the label attribute prefixed with "{name}_options." as its key, where {name} is the name of the preference, its value is used as a localized label.)

- -

Using Identifiers

- -

If the localization system can't find an entry for a particular identifier using the current locale, then it just returns the identifier itself.

- -

This has the nice property that you can write localizable, fully functional add-ons without having to write any locale files. You can just use the default language strings as your identifier, and subsequently supply .properties files for all the additional locales you want to support.

- -

For example, in the case above you could use "Hello!" as the identifier, and just have one .properties file for the "fr-FR" locale:

- -
Hello!= Bonjour !
-
- -

Then when the locale is "en-US", the system would fail to find a .properties file, and return "Hello!".

- -

However, this approach makes it difficult to maintain an add-on which has many localizations, because you're using the default language strings both as user interface strings and as keys to look up your translations. This means that if you want to change the wording of a string in the default language, or fix a typo, then you break all your locale files.

- -

Locale Updater

- -

The locale updater add-on makes it easier to update locale files. Once you've installed it, open the Add-on Manager, and you'll see a see a new button labeled "Update l10n" next to each add-on you've installed:

- -

- -

Click the button and you'll be prompted for a new .properties file for that add-on. If you provide a new file, the add-on's locale data will be updated with the new file.

- -

Limitations

- -

The current localization support is a first step towards full support, and contains a number of limitations.

- - - -

See Also - for developers looking to localize non-SDK add-ons

- - diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/list_open_tabs/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/list_open_tabs/index.html deleted file mode 100644 index 8a4985806e..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/list_open_tabs/index.html +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: 列出打开的标签页 -slug: Mozilla/Add-ons/SDK/Tutorials/List_Open_Tabs -tags: - - Add-on SDK -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/List_Open_Tabs ---- -

{{AddonSidebar}}

- -
-

学习本教程之前你需要学习 jpm 基础

-
- -

列出打开的标签页,你可以遍历 tabs 对象本身。

- -

下面的 add-on 添加一个 action button 当用户单击该按钮时,该日志将在打开的标签页中记录:

- -
require("sdk/ui/button/action").ActionButton({
-  id: "list-tabs",
-  label: "List Tabs",
-  icon: "./icon-16.png",
-  onClick: listTabs
-});
-
-function listTabs() {
-  var tabs = require("sdk/tabs");
-  for (let tab of tabs)
-    console.log(tab.url);
-}
-
- -
-

注意:为此你需要一个按钮图标,以"icon-16.png"的文件名保存到你的 add-on 的"data"目录下。你可以从这里下载图标:

-
- -

运行该 add-on,加载一对标签页,并点击按钮,你会看到在控制台输出如下的内容:

- -
info: http://www.mozilla.org/en-US/about/
-info: http://www.bbc.co.uk/
-
- -
-

你不能直接访问到标签页中的任何宿主内容(具体概念请查阅相关内容:JavaScript 本地对象、内置对象、宿主对象 )。

- -

为了访问标签页的内容,你需要使用 tab.attach() 添加一个脚本,此 add-on 加载加载一个页面,然后将一个脚本附加到所有打开的标签页,该脚本将向标签页的文档添加红色边框:

-
- -
require("sdk/ui/button/action").ActionButton({
-  id: "list-tabs",
-  label: "List Tabs",
-  icon: "./icon-16.png",
-  onClick: listTabs
-});
-
-function listTabs() {
-  var tabs = require("sdk/tabs");
-  for (let tab of tabs)
-    runScript(tab);
-}
-
-function runScript(tab) {
-  tab.attach({
-    contentScript: "document.body.style.border = '5px solid red';"
-  });
-}
-
- -

学习更多

- -

要了解更多关于SDK中标签如何工作, 查看 tabs API reference

- -

要了解更多关于在标签中运行脚本, 查看 tutorial on using tab.attach()

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/listen_for_page_load/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/listen_for_page_load/index.html deleted file mode 100644 index 815cfd42c5..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/listen_for_page_load/index.html +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: 监听页面加载 -slug: Mozilla/Add-ons/SDK/Tutorials/Listen_for_Page_Load -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Listen_for_Page_Load ---- -

{{AddonSidebar}}

- -
学习本教程之前你需要了解 jpm 基础
- -

你可以使用 tabs 模块来获取关于新页面加载的通知。下面的附加组件监听标签页内建的 ready 事件,并且记录下每一个标签加载时的URL:

- -
require("sdk/tabs").on("ready", logURL);
-
-function logURL(tab) {
-  console.log(tab.url);
-}
-
- -
-

你会在浏览器控制台,而非 Web 控制台中,找到这些输出的内容。

-
- -

你不能直接访问标签页里面的内容。

- -

为了访问标签页内容,你需要使用 tab.attach() 把一个脚本附到标签页上。这个示例给每一个打开后的标签页附上了一个脚本。这个脚本给标签页的 document 加上了一个红色边框:

- -
require("sdk/tabs").on("ready", runScript);
-
-function runScript(tab) {
-  tab.attach({
-    contentScript: "if (document.body) document.body.style.border = '5px solid red';"
-  });
-}
-
- -

(本示例仅仅表示:可以像这样实现一些功能,而你应当使用 page-mod,并且指定匹配模式为 "*"。)

- -

了解更多

- -

想要了解更多关于如何在SDK中处理标签页的内容,请看 tabs API 参考。你能够监听其他一些标签页事件,包括 openclose、和 activate

- -

想要了解更多关于在标签页中运行脚本的事情,请看 tab.attach() 使用教程

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/modifying_the_page_hosted_by_a_tab/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/modifying_the_page_hosted_by_a_tab/index.html deleted file mode 100644 index 5fd51fd8f7..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/modifying_the_page_hosted_by_a_tab/index.html +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: 修改标签页中页面 -slug: Mozilla/Add-ons/SDK/Tutorials/Modifying_the_Page_Hosted_by_a_Tab -tags: - - Add-on SDK -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Modifying_the_Page_Hosted_by_a_Tab ---- -
-

为了进一步学习本教程,你需要安装 Add-on SDK 和学习 cfx的基本使用

- -

这篇教程使用动作按钮API,需要Firefox 29或更新版本。

-
- -

为了修改特定标签页中的页面, 可以使用 tab对象的attach() 方法加载一个script脚本到页面中。因为他们的工作是和Web内容进行交互,所以这些脚本被称为content scripts(内容脚本)。

- -

这是个简单的示例:

- -
var button = require("sdk/ui/button/action").ActionButton({
-  id: "style-tab",
-  label: "Style Tab",
-  icon: "./icon-16.png",
-  onClick: function() {
-    require("sdk/tabs").activeTab.attach({
-      contentScript: 'document.body.style.border = "5px solid red";'
-    });
-  }
-});
- -

要运行这个示例你必须保存一个名为”icon-16.png“的图标文件在你的Add-on目录下的”data”目录下。你可以下载这个图标:

- -

这个插件创建一个按钮,其中包含Mozilla的图标作为一个图标。这个按钮产生一个点击事件处理程序,处理事件中将获取当前活动标签页和加载一个脚本到该标签页中的页面。使用contentscript选项指定加载的脚本,该脚本只绘制一个红色边框页。

- -

然后在浏览器窗口中打开任何网页,点击按钮 。你会看到一个红色的边界出现在页面中, 就像这样:

- -

- -

保持Content Script在一个单独的文件中

- -

在上面的例子中我们的content script作为一个字符串来直接使用.除非脚本非常简单,你应该保持脚本作为一个单独的文件。这使得代码更容易维护、调试和审查。

- -

比如,我们把上面的脚本代码保存在Add-on目录下的data目录中并取名为my-script.js,在代码中可以这样加载脚本:

- -
var self = require("sdk/self");
-
-var button = require("sdk/ui/button/action").ActionButton({
-  id: "style-tab",
-  label: "Style Tab",
-  icon: "./icon-16.png",
-  onClick: function() {
-    require("sdk/tabs").activeTab.attach({
-      contentScriptFile: self.data.url("my-script.js")
-    });
-  }
-});
-
- -

你可以加载多个脚本,同时这些脚本可以直接相互作用。所以你可以加载 jQuery, 然后在你的其他 content script使用它。

- -

与Content Script传递信息

- -

你的扩展插件脚本Add-on script和内容脚本content script 不能直接访问对方的变量和函数,但他们之间可以互相发送消息。

- -

从一方发送消息到另外一方, 发送方需要调用 port.emit()发送消息, 同时接收方使用port.on()接收消息。

- - - -

让我们重写上面的例子来从附加内容脚本 content script 传递一个消息。现在content script 需要像下面这样:

- -
// "self" is a global object in content scripts
-// Listen for a "drawBorder"
-self.port.on("drawBorder", function(color) {
-  document.body.style.border = "5px solid " + color;
-});
-
- -

在 add-on script 扩展脚本中,我们使用 attach()方法返回的对象向 content script 中发送一个“drawBorder”消息:

- -
var self = require("sdk/self");
-var tabs = require("sdk/tabs");
-
-var button = require("sdk/ui/button/action").ActionButton({
-  id: "style-tab",
-  label: "Style Tab",
-  icon: "./icon-16.png",
-  onClick: function() {
-    var worker = tabs.activeTab.attach({
-      contentScriptFile: self.data.url("my-script.js")
-    });
-    worker.port.emit("drawBorder", "red");
-  }
-});
-
- -

名为 drawBorder 的消息并不是一个内置的消息, 而是通过 port.emit()方法自定义的。

- -

注入 CSS

- -

不像 page-mod API, tab.attach() 不允许你直接注入CSS到页面中。

- -

你需要使用 JavaScript 来修改页面的样式,就像前面的示例那样。

- -

学习更多

- -

要了解更多关于在SDK中标签页的使用, 可以查看打开一个网页教程,  列出打开的标签页教程, 和tabs API 参考手册.

- -

要学习更多关于content scripts, 查看 content scripts guide.

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/modifying_web_pages_based_on_url/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/modifying_web_pages_based_on_url/index.html deleted file mode 100644 index 6e5e46c532..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/modifying_web_pages_based_on_url/index.html +++ /dev/null @@ -1,210 +0,0 @@ ---- -title: Modifying Web Pages Based on URL -slug: Mozilla/Add-ons/SDK/Tutorials/Modifying_Web_Pages_Based_on_URL -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Modifying_Web_Pages_Based_on_URL ---- -
开始本教程之前,您必须安装好 SDK,并且学习 cfx 的基本的使用方法。
- -

要修改任何页面匹配特定的模式(比如,“http://example.org/”)当它们加载后,使用page-mod模块。

- -

要创建 page-mod,您必须指定两件事:

- - - -
-

content scripts为内容脚本,只能使用普通浏览器支持的 JS,不能使用 add-on 的API

-
- -

这里有一个范例。内容脚本提供contentScript选项,地址样本提供include选项:

- -
// Import the page-mod API
-var pageMod = require("sdk/page-mod");
-
-// Create a page mod
-// It will run a script whenever a ".org" URL is loaded
-// The script replaces the page contents with a message
-pageMod.PageMod({
-  include: "*.org",
-  contentScript: 'document.body.innerHTML = ' +
-                 ' "<h1>Page matches ruleset</h1>";'
-});
-
- -

试试吧:

- - - -

您将看到:

- -

- -

指定匹配模式

- -

匹配模式使用 match-pattern 语法。您可以通过单一的匹配字符串,或者数组。

- -

把内容脚本放在独立的文件中

- -

在上面的范例中我们通过字符串来实现内容脚本。除非是用作简单的例子,通常情况下您应该将内容脚本放在独立文件中,这将使您的代码更易维护、调式和查看。

- -

要这样做,您需要:

- - - -

例如,如果我们将内容脚本保存在 data 目录下,命名为 my-script.js,在main.js中,我们应该这么写:

- -
// Import the page-mod API
-var pageMod = require("sdk/page-mod");
-// Import the self API
-var self = require("sdk/self");
-
-// Create a page mod
-// It will run a script whenever a ".org" URL is loaded
-// The script replaces the page contents with a message
-pageMod.PageMod({
-  include: "*.org",
-  contentScriptFile: self.data.url("my-script.js")
-});
- -

加载多个Content Scripts

- -

您可以加载更多脚本,且脚本可以相互交互。所以,您可以使用jQuery重写 my-script.js:

- -
$("body").html("<h1>Page matches ruleset</h1>");
-
- -

然后下载 jQuery 库到您的扩展开发目录的 data 目录下,并且将 jQuery 和 my-script 一起加载(确保先加载 jQuery 库):

- -
// Import the page-mod API,加载 add-on 的 page-mod API
-var pageMod = require("sdk/page-mod");
-// Import the self API, 加载 add-on 的 self API
-var self = require("sdk/self");
-
-// Create a page mod
-// It will run a script whenever a ".org" URL is loaded
-// The script replaces the page contents with a message
-// 创建 page mod,匹配 “.org” URL
-pageMod.PageMod({
-  include: "*.org",
-  contentScriptFile: [self.data.url("jquery-1.7.min.js"), self.data.url("my-script.js")]
-});
-
- -

您也可以在同一 page-mod 中同时使用 contentScriptcontentScriptFile 。如果您这么做的话,contentScript的脚本将会先加载。(应该是contentScriptFile的先加载吧?)

- -
// Import the page-mod API
-var pageMod = require("sdk/page-mod");
-// Import the self API
-var self = require("sdk/self");
-
-// Create a page mod
-// It will run a script whenever a ".org" URL is loaded
-// The script replaces the page contents with a message
-pageMod.PageMod({
-  include: "*.org",
-  contentScriptFile: self.data.url("jquery-1.7.min.js"),
-  contentScript: '$("body").html("<h1>Page matches ruleset</h1>");'
-});
-
- -

注意,您不能直接加载网站上的脚本。脚本必须从 data 目录中加载。

- -

与 Content Script 通信

- -

Your add-on script and the content script can't directly access each other's variables or call each other's functions, but they can send each other messages.

- -

从 Content Script 与 main.js 通信,发送方使用 port.emit() ,接收方使用 port.on() 监听.

- - - -

Let's rewrite the example above to pass a message from the add-on to the content script. The message will contain the new content to insert into the document. The content script now needs to look like this:

- -
// "self" is a global object in content scripts
-// Listen for a message, and replace the document's
-// contents with the message payload.
-self.port.on("replacePage", function(message) {
-  document.body.innerHTML = "<h1>" + message + "</h1>";
-});
-
- -

In the add-on script, we'll send the content script a message inside onAttach:

- -
// Import the page-mod API
-var pageMod = require("sdk/page-mod");
-// Import the self API
-var self = require("sdk/self");
-
-// Create a page mod
-// It will run a script whenever a ".org" URL is loaded
-// The script replaces the page contents with a message
-pageMod.PageMod({
-  include: "*.org",
-  contentScriptFile: self.data.url("my-script.js"),
-  // Send the content script a message inside onAttach
-  onAttach: function(worker) {
-    worker.port.emit("replacePage", "Page matches ruleset");
-  }
-});
-
- -

The replacePage message isn't a built-in message: it's a message defined by the add-on in the port.emit() call.

- -

注入 CSS

- -
-

请注意,本节中描述的功能是实验性的:我们很可能继续支持的功能,但可能需要改变的细节。

-
- -

Rather than injecting JavaScript into a page, you can inject CSS by setting the page-mod's contentStyle option:

- -
var pageMod = require("sdk/page-mod").PageMod({
-  include: "*",
-  contentStyle: "body {" +
-                "  border: 5px solid green;" +
-                "}"
-});
-
- -

As with contentScript, there's a corresponding contentStyleFile option that's given the URL of a CSS file in your "data" directory, and it is good practice to use this option in preference to contentStyle if the CSS is at all complex:

- -
var pageMod = require("sdk/page-mod").PageMod({
-  include: "*",
-  contentStyleFile: require("sdk/self").data.url("my-style.css")
-});
-
- -

You can't currently use relative URLs in style sheets loaded with contentStyle or contentStyleFile. If you do, the files referenced by the relative URLs will not be found.

- -

To learn more about this, and read about a workaround, see the relevant section in the page-mod API documentation.

- -

Learning More

- -

To learn more about page-mod, see its API reference page. In particular, the PageMod constructor takes several additional options to control its behavior:

- - - -

To learn more about content scripts in general, see the content scripts guide.

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/open_a_web_page/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/open_a_web_page/index.html deleted file mode 100644 index 7ff9ba7883..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/open_a_web_page/index.html +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: 打开Web页面 -slug: Mozilla/Add-ons/SDK/Tutorials/Open_a_Web_Page -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Open_a_Web_Page ---- -{{AddonSidebar}} - -
学习本教程之前你需要学习 jpm 基础
- -

打开一个新的网页,你可以使用 tabs 模块:

- -
var tabs = require("sdk/tabs");
-tabs.open({
-"http://www.example.com");
-
- -

这个函数是异步的,所以你不能立即获取一个可以检查的标签对象。要做到这一点,通过一个回调函数为open()。将回调函数赋值给 onready 属性,并将通过标签作为参数:

- -
var tabs = require("sdk/tabs");
-tabs.open({
-  url: "http://www.example.com",
-  onReady: function onReady(tab) {
-    console.log(tab.title);
-  }
-});
-
- -
-

尽管这样,你还是不能直接访问到标签页中的任何宿主内容(具体概念请查阅相关内容:JavaScript 本地对象、内置对象、宿主对象 )。

-
- -

-要访问标签页的内容,你需要使用 tab.attach()把一个脚本添加到该标签页。此add-on加载加载一个页面,然后将一个脚本附加到该页,该将向页面添加红色边框:

- -
var tabs = require("sdk/tabs");
-tabs.open({
-  url: "http://www.example.com",
-  onReady: runScript
-});
-
-function runScript(tab) {
-  tab.attach({
-    contentScript: "document.body.style.border = '5px solid red';"
-  });
-}
-
- -

学习更多

- -

要了解更多关于SDK中标签如何工作, 查看 tabs API reference.

- -

要了解更多关于在标签中运行脚本, 查看 tutorial on using tab.attach().

diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/troubleshooting/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/troubleshooting/index.html deleted file mode 100644 index afa3cc0cd3..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/troubleshooting/index.html +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Troubleshooting -slug: Mozilla/Add-ons/SDK/Tutorials/Troubleshooting -tags: - - add-on sdk 安装指南 - - add-on sdk安装解惑 -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Troubleshooting ---- -

{{AddonSidebar}}

- -

如果你的SDK安装和运行遇到了问题,不要慌!本页面列出了一些基本点,来帮助你追踪你的问题。

- -

检查你的 Firefox

- -

jpm 会搜索你系统中 Firefox 常见的地址,jpm 也许不能找到火狐安装在哪,或者你有多个地方安装了火狐,jpm 也许找错了地方。这种情况下,你需要使用 jpm--binary 选项。参看 jpm 指南以获取更多信息

- -

当你运行 jpm 来测试你的 add-on 或者运行单元测试时,它会打印出 Firefox 或 XULRunner 二进制文件的地址,所有你可以检查一下它的输出内容来做确认。

- -

检查你的文本控制台

- -

当你的代码代码和SKD的API产生错误时,他们会被记录到文本控制台。这应该和你运行 jpm 命令的是同一控制台或shell

- -

搜索已知的问题

- -

也许有人已经遇到过和你一样的问题了。其他用户经常发布问题到 项目邮件列表。你也可以浏览已知问题列表或者搜索特定的关键词。

- -

与项目团队和用户组交流

- -

SDK的用户和项目团队成员对问题和建议在 项目的邮件列表.  别人可能有与你相同的问题,所以试着搜索列表。也欢迎你发表问题.

- -

你也可以与其他SDK用户在 Mozilla的 IRC 网络#jetpack 聊天室聊天.

- -

如果你想报告SDK的bug,我们非常欢迎!您将需要创建一个 Bugzilla 的帐号,Bugzilla 是 Mozilla 的 bug 追踪系统。

- -
 
- -
 
- -
 
diff --git a/files/zh-cn/mozilla/add-ons/sdk/tutorials/unit_testing/index.html b/files/zh-cn/mozilla/add-ons/sdk/tutorials/unit_testing/index.html deleted file mode 100644 index 63cd86da13..0000000000 --- a/files/zh-cn/mozilla/add-ons/sdk/tutorials/unit_testing/index.html +++ /dev/null @@ -1,102 +0,0 @@ ---- -title: Unit Testing -slug: Mozilla/Add-ons/SDK/Tutorials/Unit_testing -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Unit_testing ---- -
-

学习本教程你将需要安装SDK, 学习 基本操作cfx,和学习过编写可重复模块(writing reusable modules).

-
-
-

如果你在使用 jpm 而不是 cfx, 请看关于cfx, 而且重点看加载测试模块(loading modules from test code).

-
-

SDK提供了一个框架,为你的代码创建和运行单元测试.接下来我们将演示如何写一个关于Base64 模块的单元测试.

-

一个Base64模块例子

-

在一个网页中, 你可以进行Base64的加密和解密,通过使用函数btoa() and atob() .不幸的是这些函数依附在window对象: 由于这个对象在你的add-on(插件) main 的代码里不是有效对象,所以 atob() and btoa() 也不是有效的. 因此我们将展示如何在这个平台上创建一个base64模块 .

-

To begin with, create a new directory, navigate to it, and run cfx init. Now create a new file in "lib" called "base64.js", and give it the following contents:

-
const { atob, btoa } = require("chrome").Cu.import("resource://gre/modules/Services.jsm", {});
-
-exports.atob = a => atob(a);
-exports.btoa = b => btoa(b);
-
-

This code exports two functions, which just call the platform's btoa() and atob() functions. To show the module in use, edit the "main.js" file as follows:

-
var base64 = require("./base64");
-
-var button = require("sdk/ui/button/action").ActionButton({
-  id: "base64",
-  label: "base64",
-  icon: "./icon-16.png",
-  onClick: function() {
-    encoded = base64.btoa("hello");
-    console.log(encoded);
-    decoded = base64.atob(encoded);
-    console.log(decoded);
-  }
-});
-

To run this example you'll also have to have an icon file named "icon-16.png" saved in your add-ons "data" directory. You could download this icon: .

-

Now "main.js" imports the base64 module and calls its two exported functions. If we run the add-on and click the button, we should see the following logging output:

-
info: aGVsbG8=
-info: hello
-
-

Testing the Base64 Module

-

Navigate to the add-on's test directory and delete the test-main.js file. In its place create a file called test-base64.js with the following contents:

-
var base64 = require("./base64");
-
-exports["test atob"] = function(assert) {
-      assert.ok(base64.atob("aGVsbG8=") == "hello", "atob works");
-}
-
-exports["test btoa"] = function(assert) {
-  assert.ok(base64.btoa("hello") == "aGVsbG8=", "btoa works");
-}
-
-exports["test empty string"] = function(assert) {
-  assert.throws(function() {
-                  base64.atob();
-                },
-                "empty string check works");
-}
-
-require("sdk/test").run(exports);
-
-

This file: exports three functions, each of which expects to receive a single argument which is an assert object. assert is supplied by the test/assert module and implements the CommonJS Unit Testing specification.

- -

At this point your add-on ought to look like this:

-
  /base64
-      package.json
-      README.md
-      /doc
-          main.md
-      /lib
-          main.js
-          base64.js
-      /test
-          test-base64.js
-
-

Now execute cfx --verbose test from the add-on's root directory. You should see something like this:

-
Running tests on Firefox 13.0/Gecko 13.0 ({ec8030f7-c20a-464f-9b0e-13a3a9e97384}) under darwin/x86.
-info: executing 'test-base64.test atob'
-info: pass: atob works
-info: executing 'test-base64.test btoa'
-info: pass: btoa works
-info: executing 'test-base64.test empty string'
-info: pass: empty string check works
-
-3 of 3 tests passed.
-Total time: 5.172589 seconds
-Program terminated successfully.
-
-

What happens here is that cfx test:

-

Note the hyphen after "test" in the module name. cfx test will include a module called "test-myCode.js", but will exclude modules called "test_myCode.js" or "testMyCode.js".

- -

Obviously, you don't have to pass the --verbose option to cfx if you don't want to; doing so just makes the output easier to read.

diff --git "a/files/zh-cn/mozilla/add-ons/sdk/tutorials/\346\227\245\345\277\227/index.html" "b/files/zh-cn/mozilla/add-ons/sdk/tutorials/\346\227\245\345\277\227/index.html" deleted file mode 100644 index e581a0811c..0000000000 --- "a/files/zh-cn/mozilla/add-ons/sdk/tutorials/\346\227\245\345\277\227/index.html" +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: 日志 -slug: Mozilla/Add-ons/SDK/Tutorials/日志 -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Logging ---- -

{{AddonSidebar}}

- -
学习本教程之前你需要学习 jpm 基础.
- -

DOM console 对象对调试 Javascript 非常有帮助。但是由于扩展程序无法访问 DOM 对象,sdk 提供了一个拥有大部分 DOM console 对象方法的全局 console 对象,包括打印错误日车、警告和数据信息的方法。你无需 require() 任何模块,就可以直接使用 console 对象。

- -

使用 console.log() 方法来打印信息:

- -
console.log("Hello World");
-
- -

尝试:

- - - -

Firefox 将会启动,并在你执行 jpm run 的命令行窗口显示下面的信息:

- -
console.log: console: Hello world
-
- -

在内容脚本(conent script)中使用 console

- -

与 addon 主代码一样,你可以在内容脚本中直接使用 console 对象。下面这个扩展在内容脚本中调用了 console.log() 方法,作用是在控制台打印出每个打开的标签页内的 HTML 内容:

- -
require("sdk/tabs").on("ready", function(tab) {
-  tab.attach({
-    contentScript: "console.log(document.body.innerHTML);"
-  });
-});
-
- -

控制台输出

- -

如果你是在命令行启动你的扩展(例如:执行 jpm runjpm test),那么控制台信息将在你使用的命令行界面中显示。

- -

如果你将扩展安装到了 Firefox 中,控制台信息将显示在 Firefox 浏览器控制台中。

- -

但请注意,默认情况下,任何已经安装的扩展不会在错误控制台中输出任何信息,包括使用扩展构建程序安装的扩展或者使用其它工具例如:Extension Auto-installer

- -

关于此项内容的更多信息请参阅控制台参考文档 “日志等级”。

- -

更多

- -

完整的 console API,请看 API 参考文档

diff --git "a/files/zh-cn/mozilla/add-ons/sdk/tutorials/\346\267\273\345\212\240\344\270\200\344\270\252\350\217\234\345\215\225\351\241\271/index.html" "b/files/zh-cn/mozilla/add-ons/sdk/tutorials/\346\267\273\345\212\240\344\270\200\344\270\252\350\217\234\345\215\225\351\241\271/index.html" deleted file mode 100644 index 77d743e806..0000000000 --- "a/files/zh-cn/mozilla/add-ons/sdk/tutorials/\346\267\273\345\212\240\344\270\200\344\270\252\350\217\234\345\215\225\351\241\271/index.html" +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: 添加菜单项 -slug: Mozilla/Add-ons/SDK/Tutorials/添加一个菜单项 -translation_of: Archive/Add-ons/Add-on_SDK/Tutorials/Add_a_Context_Menu_Item ---- -
-

学习本章前,您要先 安装SDK 和学习 cfx的基本用法

-
-

右键菜单模块添加右键菜单项或子菜单

-

下面的例子是增加了一个新的上下文菜单项。当页面被选中时才会显示该菜单项,选择的部分会被发送到main.js的add-on代码中,它只是记录:

-
var contextMenu = require("sdk/context-menu");
- var menuItem = contextMenu.Item({
-  label: "Log Selection",
-  context: contextMenu.SelectionContext(),
-  contentScript: 'self.on("click", function () {' +
-                 '  var text = window.getSelection().toString();' +
-                 '  self.postMessage(text);' +
-                 '});',
-  onMessage: function (selectionText) {
-    console.log(selectionText);
-  }
-});
-

Try it: run the add-on, load a web page, select some text and right-click. You should see the new item appear:

-

试一试:运行该扩展,加载一个网页,选中一些文本并右键单击。你应该能看到新的项目出现:

-

-

点击,选中的文本记录到控制台:

-
info: elephantine lizard
-
-

细节

-


- 这个add-on所有的操作是构建一个上下文菜单项。你不需要添加它:一旦你已经建立了项目,它会自动添加在正确的上下文。在这种情况下,构造函数接受四个选项:labelcontext,和contentscript,onMessage。

-

label

-


- 标签是字符串的显示。

-

context

-


- 上下文应该在不同的情境中显示它该做的显示。上下文菜单模块提供了一些简单的内置的上下文,包括selectioncontext(),这意味着:当页面被选中的时候将会显示菜单项。
- 如果这些简单的背景是不够的,你可以使用脚本定义更复杂的环境。

-

contentScript

-

这将一个脚本项目。在这种情况下,脚本侦听用户点击该项目,然后选定文本用消息发送到add-on。

-

onMessage

-

onMessage属性提供附加的代码来响应来自连接到上下文菜单项脚本报文的一种方法。在这种情况下,它只是记录选定的文本。

-

所以:
- 用户点击项目
- 内容脚本的点击事件触发,和内容脚本检索选定的文本和发送邮件的附件
- 附加的消息事件触发,并附加代码的处理函数是通过选定的文本,它的日志
-  

-

获取更多

-

如果想获取更多信息关于context-menu模块,查看context-menu API reference.

diff --git a/files/zh-cn/mozilla/add-ons/setting_up_extension_development_environment/index.html b/files/zh-cn/mozilla/add-ons/setting_up_extension_development_environment/index.html deleted file mode 100644 index 9790442e3c..0000000000 --- a/files/zh-cn/mozilla/add-ons/setting_up_extension_development_environment/index.html +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: 扩展开发环境设置 -slug: Mozilla/Add-ons/Setting_up_extension_development_environment -tags: - - Extensions -translation_of: Archive/Add-ons/Setting_up_extension_development_environment ---- -

本文给出了关于如何为扩展开发配置Mozilla应用程序的建议.

-

开发配置

-

为了避免由于设置了开发相关的预定义选项导致的性能上的问题,以及避免破坏你的个人数据,建议你可以创建一个新的Profile,而不是使用默认的进行开发工作.

-

如果你使用-no-remote参数启动Firefox,你可以用不同的Profile运行两个Firefox实例.例如,不管是否"正常"的Firefox是否运行,下面的命令将运行你的开发Profile(假设你的开发Profile命名为"dev").

-
start "" "%ProgramFiles%\Mozilla Firefox\firefox.exe" -no-remote -P dev
-
-

用默认的Profile允许Firefox通常仅仅是"firefox"或者"firefox -P default".

-

你可以使用Firefox稳定版本和开发版本来检查扩展的兼容性(Installing Firefox 3 or Minefield while keeping Firefox 2).

-

开发预定义选项

-

这些已定义参数使在低性能的情况下使调试更容易.

-

查看编辑配置文件关于设置预定义选项的信息.注意某些设置默认不存在与abount:config中.所以你需要创建一个新的(boolean)的项.

-

要这样做, 添加下面的代码行到你的Profile目录的 user.js 文件中,如果文件不存在,创建之:

-
user_pref("nglayout.debug.disable_xul_cache",true);
-user_pref("browser.dom.window.dump.enabled",true);
-
-

注意: 对于Firefox 版本 3.0"user.js" 已被 "prefs.js" 替换.

-

See below under "Development Profile" to setup a separate development profile before you make these changes.

- -

开发扩展

-

这些扩展可以帮组你进行扩展开发.

- -

扩展开发目录设定

-

每次因遇到某些变更而不得不重新添加扩展部分的时候,以及,为了保护您的"扩展源文件"不受到卸载过程中被意外删除的风险,其实您可以把"扩展插件目录"从"标准用户配置目录"中移出到你自己想要的文件目录中进行开发。具体操作步骤如下:

-
    -
  1. 找到扩展ID:从install.rdf中找到你的扩展ID号,install.rdf就安装在扩展插件的根目录中;
  2. -
  3. 建立文件:在“用户配置目录/extensions/”目录下,用你的扩展插件ID号作为文件名新建一个文件。 (比如: `用户配置目录/extensions/{46D1B3C0-DB7A-4b1a-863A-6EE6F77ECB58}`) (找到你的用户配置目录所在位置),记得没有文件扩展名。(为了方便说明暂把这个文件称作“扩展外链定位文件” )
  4. -
  5. 设定文件内容:“扩展外链定位文件”里要包含一个路径,这个路径是指向扩展程序的install.rdf所在目录的路径。(例如:`/full/path/to/yourExtension`. Windows用户注意,用大写书写驱动器名以及反斜杠而不是正斜杠,比如:`C:\full\path\to\yourExtension` Here is an example 'C:\sam\workspace\toolbar\helloWorldtoolbar\'). 在Firefox3中, 如果你是通过XPI包安装的扩展,`用户配置目录`下部分或者所有extensions.*的文件可能会被重新设置。虽然这些文件系统会自动重新生成的,还是备份一下先。
  6. -
  7. 把“扩展外链定位文件”放在你的用户配置目录中的扩展目录(`用户配置目录/extension`)下,重启Firefox。
  8. -
-

使用目录而非JAR

-

无论你是否选择将你的扩展 chrome打包成JAR或是目录,在目录下开发会更简单。如果你选择了一个用于分发的JAR,你仍然可以通过编辑chrome.manifest工作在目录形式下。比如下面的例子

-
content	myExtension	jar:chrome/myExtension.jar!/content/
-
-

不如

-
content	myExtension	chrome/content/
-
diff --git a/files/zh-cn/mozilla/add-ons/submitting_an_add-on_to_amo/index.html b/files/zh-cn/mozilla/add-ons/submitting_an_add-on_to_amo/index.html deleted file mode 100644 index 5ffb14d889..0000000000 --- a/files/zh-cn/mozilla/add-ons/submitting_an_add-on_to_amo/index.html +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: 向AMO提交一个附加组件 -slug: Mozilla/Add-ons/Submitting_an_add-on_to_AMO -translation_of: Mozilla/Add-ons/Distribution ---- -

当你为基于Mozilla的软件(如Firefox,Thunderbird等)制作出了一个全新的附加组件时,你一定希望其他人能够找,到下载并使用它。

-

Mozilla provides the http://addons.mozilla.org (AMO) web site to provide a repository for add-ons for Mozilla software. When users click the "Get Extensions" link in the Add-ons window in Firefox, for example, they are directed to this site.

-

That makes AMO a great way to get your add-ons to the public. This article provides details on how to submit your article to AMO for distribution.

-
- Note: Attaching your add-on to articles on the Mozilla Developer Center web site won't do you a lot of good, as we delete them.  This is not the right place to post your add-ons; please follow the instructions here instead.
-

第一步:编写你的附加组件

-

This is important. It's hard to get an add-on accepted into AMO if you don't write it first. Really hard.

-

第二步:测试你的附加组件

-

Make sure it works before you submit it. You should try it out on every product you claim to support. In other words, you don't want to advertise that it works in both Firefox and Thunderbird if you haven't tested it in both. Make sure it works in every version you claim to support, too.

-

第三步:打包你的附加组件

-

Add-ons distributed by AMO need to be packaged properly as XPI files. See Extension Packaging for information on how to do this.

-

第四部:注册一个AMO账户

-

You'll need to have an AMO account so that you can make submissions. To get one, visit the Register link at the top of any page on the AMO website. Fill out the form and follow the instructions to activate your account.

-

Obviously, you can skip this step if you already have an AMO account.

-

第五步:提交你的附加组件

-

To submit an add-on, go to the Developer Control Panel.

-

You will then be asked to supply a file, as well as information about the add-on.

-

Once the add-on has been reviewed, it will be made available for downloading. Reviews can take a varying amount of time depending on how many pending submissions there are and the availability of people to perform the reviews.

-

{{ languages( { "fr": "fr/Soumettre_un_module_sur_AMO" } ) }}

diff --git a/files/zh-cn/mozilla/add-ons/themes/index.html b/files/zh-cn/mozilla/add-ons/themes/index.html deleted file mode 100644 index e7c28ba50c..0000000000 --- a/files/zh-cn/mozilla/add-ons/themes/index.html +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: 主题 -slug: Mozilla/Add-ons/Themes -tags: - - Themes -translation_of: Mozilla/Add-ons/Themes ---- -

-

-
Getting Started
-介绍如何为Firefox开发主题。
-
主题指的是程序的皮肤,通过它可以改变程序的外观,满足不同人的不同需要。一个主题可以只改变界面的颜色,也可以改变界面相关的所有元素。
- - -
-

Documentation

-
创建一套 Firefox 皮肤 -
介绍如何为Firefox创建新的主题。 -
-

一般style翻译成样式 -

-
主题打包 -
如何将Firefox和Thunderbird的主题打包。 -
-
Firefox 2.0 和 3.0 间的主题变更 -
-
Firefox 1.5 和 2.0 间的主题变更 -
Firefox 发行版1.5和2.0之间的主题全部变更清单。 -
-
Firefox 1.5 和 2.0 间的主题变更 (forum post) -
A forum post at MozillaZine outlining the basic theme-related changes between Firefox 1.0 and 1.5. -
-
主题设计的第一步 -
A somewhat aged article discussing theme design for Firefox. -
-

View All... -

-
-

Community

-
  • View Mozilla forums... -
-

{{ DiscussionList("dev-themes", "mozilla.dev.themes") }} -

- -

Tools

- -

View All... -

- -
CSS -
-
-

Categories -

Interwiki Language Links -


-


-

-
-
-{{ languages( { "de": "de/Themes", "en": "en/Themes", "es": "es/Temas", "fr": "fr/Th\u00e8mes", "ja": "ja/Themes", "pl": "pl/Motywy", "zh-tw": "zh_tw/\u4f48\u666f\u4e3b\u984c" } ) }} diff --git a/files/zh-cn/mozilla/add-ons/themes/obsolete/creating_a_skin_for_firefox/index.html b/files/zh-cn/mozilla/add-ons/themes/obsolete/creating_a_skin_for_firefox/index.html deleted file mode 100644 index 2301b757e7..0000000000 --- a/files/zh-cn/mozilla/add-ons/themes/obsolete/creating_a_skin_for_firefox/index.html +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: 创建一套_Firefox_皮肤 -slug: Mozilla/Add-ons/Themes/Obsolete/Creating_a_Skin_for_Firefox -tags: - - Themes -translation_of: Archive/Themes/Creating_a_Skin_for_Firefox ---- -

 

-

说明

-

为了为 Firefox 创建一套皮肤, 你必须知道三件事:如何编辑图像、如何释放zip文件、以及如何更改CSS。Firefox 的按钮图标使用标准的gif、png、和 jpeg 图像并使用 CSS 来定义界面上的一切。

-

什么是皮肤?

-

皮肤不会改版总体的界面;相反的,它仅仅定义了界面看上去的样子。你无法改版用户右击一个图像时发生什么事情,但你可以改版右键菜单的外观(例如使其变为带有粉色圆点装饰)。如果你想更改Firefox的功能,你不得不去改变chrome,这不在本文讨论的范围之内。

-

内容

- -
-

文章原始信息

- -
-
-  
-

{{ languages( { "de": "de/Theme_erstellen", "es": "es/Creando_un_tema_para_Firefox", "fr": "fr/Cr\u00e9er_un_th\u00e8me_pour_Firefox", "ja": "ja/Creating_a_Skin_for_Firefox", "pl": "pl/Tworzenie_sk\u00f3rek_dla_Firefoksa" } ) }}

diff --git a/files/zh-cn/mozilla/add-ons/themes/obsolete/creating_a_skin_for_firefox/uuid/index.html b/files/zh-cn/mozilla/add-ons/themes/obsolete/creating_a_skin_for_firefox/uuid/index.html deleted file mode 100644 index 37280321a1..0000000000 --- a/files/zh-cn/mozilla/add-ons/themes/obsolete/creating_a_skin_for_firefox/uuid/index.html +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: 创建一套Firefox皮肤 -slug: Mozilla/Add-ons/Themes/Obsolete/Creating_a_Skin_for_Firefox/UUID -translation_of: Archive/Themes/Creating_a_Skin_for_Firefox/UUID ---- -

{{wiki.localize('System.API.page-generated-for-subpage')}}

diff --git a/files/zh-cn/mozilla/add-ons/themes/obsolete/index.html b/files/zh-cn/mozilla/add-ons/themes/obsolete/index.html deleted file mode 100644 index d420b6ebf0..0000000000 --- a/files/zh-cn/mozilla/add-ons/themes/obsolete/index.html +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Obsolete -slug: Mozilla/Add-ons/Themes/Obsolete -tags: - - NeedsTranslation - - TopicStub -translation_of: Mozilla/Add-ons/Themes/Obsolete ---- -

This page collects theme docs that we don't expect will ever be updated, but which we're keeping for the time being as potential source material for updated docs.

-

{{ ListSubPages ("/en-US/Add-ons/Themes/Obsolete", 5) }}

diff --git a/files/zh-cn/mozilla/add-ons/themes/obsolete/theme_changes_in_firefox_3/index.html b/files/zh-cn/mozilla/add-ons/themes/obsolete/theme_changes_in_firefox_3/index.html deleted file mode 100644 index 595058f253..0000000000 --- a/files/zh-cn/mozilla/add-ons/themes/obsolete/theme_changes_in_firefox_3/index.html +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: Firefox 3 的界面改动 -slug: Mozilla/Add-ons/Themes/Obsolete/Theme_changes_in_Firefox_3 -tags: - - Themes -translation_of: Archive/Themes/Theme_changes_in_Firefox_3 ---- -

{{ Fx_minversion_header(3) }} {{ Draft() }}

-

本文包含了更新FireFox主题以使其可以在Firefox 3下良好表现所需进行的一些改动。

-
- Note: We could use an article called Updating themes for Firefox 3 that would serve as a how-to guide for updating themes. If anyone with theming experience would like to write one, please do!
-

默认主题的改动

-

下表列出了Firefox 3默认主题的一些改动。你可以对照此表,确认你所需要做出的改动。

-

所有文件

-

所有平台

- - - - - - - - - - - -
文件变更
<tt>browser/themes/*/browser/browser.css</tt>The width of the drag and drop indicator is no longer calculated during the drag (tabbrowser.xml). Instead a '-moz-margin-start' property must be added to .tab-drop-indicator-bar, with a value that is half of the width of the indicator image. Also, the visibility of the indicator is now controlled by setting collapsed in tabbrowser.xml. As a result, the 'display' property should be removed from .tab-drop-indicator-bar (including for dragging="true").
-

Mac OS X

- - - - - - - - - - - - - - - -
文件变动信息
<tt>browser/themes/pinstripe/browser/tabbrowser/tabDragIndicator.png</tt>删除了图片边缘多余的空白,现在图片尺寸变小。也许会对其他使用此图片的Mac平台下的主题产生影响。
<tt>browser/themes/pinstripe/browser/browser.css</tt>.tabbrowser-tab{{ mediawiki.external('first-tab=\"true\"') }} > .tab-image-left不再具有margin-left属性,现在使用定义了相同宽度的.tabs-left元素来替代。在FireFox 2的默认皮肤Winstripe中已经作此处理。
-

<tt>browser</tt>的改动

-

<tt>global</tt>的改动

-

所有平台

-

“跳转到”按钮现在被放置在地址栏内部,所以此按钮所用的图片(<tt>chrome://browser/skin/Go-arrow.png</tt>)需要设计的小一些。控制“跳转到”及其他地址栏中所用到的按钮的显示及隐藏的CSS规则为:

-
#urlbar[pageproxystate="invalid"] > #urlbar-icons > :not(#go-button) ,
-#urlbar[pageproxystate="valid"] > #urlbar-icons > #go-button {
-  visibility: collapse;
-}
-
-
增加的图片
-

增加了以下图片:

-
-
- <tt>chrome://global/skin/icons/information-16.png</tt>
-
- Used when presenting information notices。
-
- <tt>chrome://global/skin/icons/warning-16.png</tt>
-
- 用作显示警告窗口。
-
-
移除的图片
-

以下图片被移除:

-
-
- <tt>chrome://mozapps/skin/extensions/question.png</tt>
-
- 不再使用。
-
-

Mac OS X

-

为Mac OS X平台上的Firefox 3制作的皮肤需要在<tt>chrome://global/skin/wizard.css</tt>末尾增加两条CSS规则:

-
.wizard-buttons-btm {
-  padding:Xpx;
-}
-
-.wizard-label-box {
-  display: none;
-}
-
-

此处的数字 - - X - ,即<tt>.wizard-buttons-btm</tt>中的padding值,需要和<tt>.wizard-buttons-box-2</tt>中的margin值相同。

-
图片变动
-

chrome://global/skin/icons/loading_16.gif 被chrome://global/skin/icons/loading_16.png 替代。

-

<tt>mozapps</tt>的改动

-

参考文章

-

Theme changes in Firefox 2

diff --git a/files/zh-cn/mozilla/add-ons/webextensions/embedded_webextensions/index.html b/files/zh-cn/mozilla/add-ons/webextensions/embedded_webextensions/index.html deleted file mode 100644 index 834125bb32..0000000000 --- a/files/zh-cn/mozilla/add-ons/webextensions/embedded_webextensions/index.html +++ /dev/null @@ -1,205 +0,0 @@ ---- -title: Embedded WebExtensions -slug: Mozilla/Add-ons/WebExtensions/Embedded_WebExtensions -translation_of: Archive/Add-ons/Embedded_WebExtensions ---- -
{{AddonSidebar}}
- -
-

嵌入一个 WebExtension 需要使用 Firefox 51 或更高版本。在 SDK 附加组件中嵌入一个 WebExtension 还需要 jpm 1.2.0

-
- -

从 Firefox 51 开始,你可以在传统附加组件类型中嵌入一个 WebExtension。

- -

传统附加组件可以是经典的自举扩展或者Add-on SDK 附加组件。嵌入式 WebExtension 的文件打包在传统附加组件中。嵌入式 WebExtension 并不直接与嵌入的附加组件共享范围,但可以使用 {{WebExtAPIRef("runtime")}} API 中定义的消息函数交换消息。

- -

- -

这意味着您可以一次性迁移传统附加组件到 WebExtensions,并且在此期间附加组件的功能完全保留。尤其是它可以让您从旧版附加组件迁移存储数据到 WebExtension,通过撰写一个中间的混合式附加组件,使用旧版 API 读取数据(例如 simple-prefs 或 preferences 服务)并使用 WebExtension API 写入它(例如 {{WebExtAPIRef("storage")}})。

- -

连同本指南,我们撰写了两个例子展示如何使用嵌入式 WebExtensions 来帮助从传统附加组件迁移。如何从自举式附加组件迁移以及如何从 SDK 附加组件迁移

- -

嵌入 WebExtension

- -

如果传统附加组件是一个带有install.rdf 的自举式扩展,在该 RDF 中加入 "hasEmbeddedWebExtension" 并设为 "true":

- -
<em:hasEmbeddedWebExtension>true</em:hasEmbeddedWebExtension>
- -
如果旧式附加组件是一个 SDK 附加组件,在 package.json 中包含 "hasEmbeddedWebExtension" 并设为 true
- -
 
- -
"hasEmbeddedWebExtension": true
-
- -
WebExtension 本身放在附加组件中的 "webextension" 顶层目录。例如:
- -
 
- -
my-boostrapped-addon/
-    chrome/
-    webextension/
-        manifest.json
-        background.js
-        ...
-    bootstrap.js
-    chrome.manifest
-    install.rdf
- -
 
- -
-
my-sdk-addon/
-    index.js
-    package.json
-    webextension/
-        manifest.json
-        background.js
-        ...
-
- -

Firefox 不将嵌入式 WebExtension 视为一个独立的附加组件。因此,您不应该为它指定一个附加组件 ID。如果你这样做,那只会被忽略。

- -

但是,在您完成附加组件的迁移并移除旧式嵌入代码后,您必须添加一个 applications 键,设置 ID 为旧式附加组件的 ID。通过此方式,addons.mozilla.org 可以识别 WebExtension 是旧式附加组件的一个更新。

- -

启动 WebExtension

- -

嵌入式 WebExtension 必须由被嵌入的附加组件明确启动。

- -

如果被嵌入的附加组件是一个自举式附加组件,那么传递到自举式扩展的 startup() 函数的 data 将获得一个明确的 webExtension

- -
// bootstrapped add-on
-
-function startup({webExtension}) {
-
-...
- -

如果被嵌入的附加组件是一个 SDK 附加组件,它可以使用 sdk/webextension 模块访问一个 WebExtension 对象:

- -
// SDK add-on
-
-const webExtension = require("sdk/webextension");
- -

无论哪种方式,此对象都有一个 startup() 函数,它返回一个 Promise。该 promise 使用一个 browser 属性解决一个对象:这包括 {{WebExtAPIRef("runtime")}} API,被嵌入的附加组件可以用它来与嵌入式 WebExtension 交换消息:

- - - -

例如:

- -
// bootstrapped add-on
-
-function startup({webExtension}) {
-  webExtension.startup().then(api => {
-    const {browser} = api;
-    browser.runtime.onMessage.addListener(handleMessage);
-  });
-}
- -
// SDK add-on
-
-const webExtension = require("sdk/webextension");
-
-webExtension.startup().then(api => {
-  const {browser} = api;
-  browser.runtime.onMessage.addListener(handleMessage);
-});
-
- -

应注意的是,嵌入的附加组件不能启动通信,它可以使用 onMessage 接收(并可选响应)一次性消息,并可以使用 onConnect 接受连接请求。

- -

如果嵌入式 WebExtension 缺少一个 manifest,或者如果 manifest 无效,该 promise 会被拒绝。这种情况下,您可以在浏览器工具箱的控制台中看到更多细节。

- -

交换消息

- -

一旦嵌入式 WebExtension 处在运行,它可以使用 {{WebExtAPIRef("runtime")}} API 的子集与旧式附加组件交换消息:

- - - -

无需连接的消息

- -

要发送一条消息,WebExtension 可以使用 {{WebExtAPIRef("runtime.sendMessage()")}}。您可以省略 extensionId 参数,因为浏览器认为嵌入式 WebExtension 是被嵌入附加组件的一部分:

- -
browser.runtime.sendMessage("message-from-webextension").then(reply => {
-  if (reply) {
-    console.log("response from legacy add-on: " + reply.content);
-  }
-});
- -

被嵌入的附加组件可以使用 {{WebExtAPIRef("runtime.onMessage")}} 对象接收消息(并可选响应):

- -
// bootstrapped add-on
-
-function startup({webExtension}) {
-  // Start the embedded webextension.
-  webExtension.startup().then(api => {
-    const {browser} = api;
-    browser.runtime.onMessage.addListener((msg, sender, sendReply) => {
-      if (msg == "message-from-webextension") {
-        sendReply({
-          content: "reply from legacy add-on"
-        });
-      }
-    });
-  });
-}
- -

基于连接的消息

- -

要在 WebExtension 与传统附加组件间设置一个长寿命连接,WebExtension 可以使用 {{WebExtAPIRef("runtime.connect()")}}。

- -
var port = browser.runtime.connect({name: "connection-to-legacy"});
-
-port.onMessage.addListener(function(message) {
-  console.log("Message from legacy add-on: " + message.content);
-});
-
- -

旧式附加组件可以使用 {{WebExtAPIRef("runtime.onConnect")}} 监听连接尝试,双方可以使用得到的 {{webExtAPIRef("runtime.Port")}} 来交换消息:

- -
function startup({webExtension}) {
-  // Start the embedded webextension.
-  webExtension.startup().then(api => {
-    const {browser} = api;
-    browser.runtime.onConnect.addListener((port) => {
-      port.postMessage({
-        content: "content from legacy add-on"
-      });
-    });
-  });
-}
- -

从传统附加组件迁移数据

- -

嵌入式 WebExtensions 的一项主要用途是迁移附加组件的存储数据。

- -

人们从旧式附加组件类型迁移的一个主要问题是存储数据,因为旧式附加组件不能使用 WebExtension 存储 API,WebExtensions 也不能使用旧式存储 API。例如,如果一个 SDK 附加组件使用了 SDK 的 simple-prefs API 来存储首选项,WebExtension 版本不可能访问这项数据。

- -

使用嵌入式 WebExtensions,您可以创建一个嵌入了 WebExtension 的附加组件中间版本来迁移数据。中间版本使用旧式 API 读取存储的数据,然后使用 WebExtension API 写入数据。

- - - -

我们提供了两个例子说明此模式:"embedded-webextension-bootstrapped" 展示了从一个自举式附加组件迁移,而 "embedded-webextension-sdk" 展示了从一个 SDK 附加组件迁移。

- -

限制

- -

调试

- -

如果您有一个嵌入了 WebExtension 的旧式附加组件,您不能使用新的附加组件调试器来调试它。您必须使用基于浏览器工具箱的旧版调试工具

diff --git a/files/zh-cn/mozilla/add-ons/working_with_multiprocess_firefox/index.html b/files/zh-cn/mozilla/add-ons/working_with_multiprocess_firefox/index.html deleted file mode 100644 index 152a15de20..0000000000 --- a/files/zh-cn/mozilla/add-ons/working_with_multiprocess_firefox/index.html +++ /dev/null @@ -1,296 +0,0 @@ ---- -title: 编写适合多进程 Firefox 的扩展 -slug: Mozilla/Add-ons/Working_with_multiprocess_Firefox -translation_of: Archive/Add-ons/Working_with_multiprocess_Firefox ---- -
-

致 Firefox 开发者:本文描述如何使你开发的扩展能在多进程 Firefox 中运行。

-
- -

目前,在桌面版 Firefox 中,Chrome 代码(Chrome Code)和内容(Content)运行在同一个进程里。因此扩展可以直接访问网页内容:

- -
gBrowser.selectedBrowser.contentDocument.body.innerHTML = "replaced by chrome code";
- -

不过呢,在多进程 Firefox(又称 Electrolysis 或 E10S)中,扩展代码(Add-on Code)和内容则在不同的进程中运行,所以上述直接访问就不一定可行了。

- -

在多进程 Firefox 中,扩展需要将触及内容的代码分解成单独分离的脚本,也就是所谓的框架脚本(Frame Scripts)。框架脚本在内容进程中运行,可以直接访问内容。框架脚本通过消息传递接口(Message-passing API)与扩展的剩余部分进行通讯。

- -

运行在 Chrome 进程中的扩展代码必须向框架脚本发送异步消息。这样做可以确保 Firefox 的用户界面不会被内容进程卡死。

- -

内容进程则可以向 Chrome 进程发送同步或异步消息,不过使用异步消息是再好不过了。

- -

关于使用消息管理器的更多细节,请参阅:消息管理器指南。接下来,本文将告诉你如何判断你开发的扩展是否会受到这方面的影响,同时简要说明需要如何进行修改。最后,通过对一些简单的样板扩展进行修改,让它们能在多进程 Firefox 中运行。

- -

检查你的扩展是否受到影响

- -

总体规则如下:

- - - -

为了证实是否受到影响,你还需要进一步测试,这个测试过程由两步过程构成:

- - - -

现在,你可以在多进程 Firefox 中禁用兼容性管理工具来测试你的扩展的兼容性了。可惜你还不能在开启多进程功能的时候安装新扩展,因此你必须先安装好扩展再开启多进程功能。关于这个问题,详见 bug 1055808

- -

更新你的代码

- -

更新代码的一般方法是:

- - - -

更多细节,请参见 message manager 文档。

- -

新应用程序接口的向前兼容能力

- -

新的多进程 Firefox 的消息接口在多进程模式没有开启的情况下仍然可用。实际上它们从 Firefox 4开始就在某种程度上可用了。不过呢,最初的应用程序接口和现在的并不相同。一些已知的差异如下:

- - - -

你不仅应该在开启了多进程支持的每夜版Firefox上测试你的扩展的变化,而且应该在你打算支持的没有开启多进程支持的发行版(Release Build)中测试。

- -

举几个例子

- -

这部分将演示修改几种不同的扩展的过程。这些扩展都是很简易的,意在展示基础的扩展模式在多进程Firefox中需要的不同处理方式。

- -

你可以在 e10s-example-addons GitHub repository 中找到这些例子的所有源代码。

- -

在所有页面运行一个脚本

- -
-

查看这个例子的源代码

-
- -

第一个扩展在每一个页面加载的时候运行一些代码。这些代码不和扩展的其他部分交互,它们只是对页面进行一些预设的修改。在这个例子中,扩展向文档的主体(body)添加了一个边界。

- -

这个扩展通过将一种“页面加载中”代码碎片("On page load" code snippet)附加于可扩展用户界面语言层来实现此修改。

- -
var myExtension = {
-    init: function() {
-        // The event can be DOMContentLoaded, pageshow, pagehide, load or unload.
-        if(gBrowser) gBrowser.addEventListener("DOMContentLoaded", this.onPageLoad, false);
-    },
-    onPageLoad: function(aEvent) {
-        var doc = aEvent.originalTarget; // doc is document that triggered the event
-        if (doc.nodeName != "#document") return; // only documents
-        // make whatever modifications you want to doc
-        doc.body.style.border = "5px solid blue";
-    }
-}
-
-window.addEventListener("load", function load(event){
-    window.removeEventListener("load", load, false); //remove listener, no longer needed
-    myExtension.init();
-},false);
- -

因为这段代码直接访问网络内容,所以它不能在多进程 Firefox 中运行。
-

- -

移植到消息管理器

- -

为了使用消息管理器移植这个例子,我们可将这个扩展全部的主体部分放入一个框架脚本:

- -
// frame-script.js
-// will run in the content process
-
-addEventListener("DOMContentLoaded", function(event) {
-  var doc = event.originalTarget;
-  if (doc.nodeName != "#document") return; // only documents
-  doc.body.style.border = "5px solid red";
-});
-
- -

我们将为这个框架脚本注册一个 chrome:// URL :

- -
// chrome.manifest
-
-content    modify-all-pages    chrome/content/
-
- -

我们附加到XUL overlay的主体脚本,只是一个使用全局消息管理器来在每个标签页中加载框架脚本的 stub。

- -
// chrome script
-// will run in the chrome process
-
-var globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
-  .getService(Ci.nsIMessageListenerManager);
-
-globalMM.loadFrameScript("chrome://modify-all-pages/content/frame-script.js", true);
- -

- -

移植到 Add-on SDK

- -

一个好的替代这样的一个扩展的思路是将其移植到 Add-on SDK。Add-on SDK 包括一个名为 page-mod 的设计为在网页中加载脚本的模块。Add-on SDK 称这些脚本为内容脚本。

- -

这种情况下扩展的主要代码创建一个 page-mod 来加载内容脚本到用户载入的每个页面:

- -
// main.js
-
-var pageMod = require("sdk/page-mod");
-var self = require("sdk/self");
-
-pageMod.PageMod({
-  include: "*",
-  contentScriptFile: self.data.url("modify-all-pages.js")
-});
- -

内容脚本可以直接修改页面:

- -
// modify-all-pages.js - content script
-
-document.body.style.border = "5px solid green";
- -

在活动标签中运行一个脚本

- -
-

查看这个例子的代码。

-
- -

这个例子说明了一个扩展如何:

- - - -

这个例子是一个无需重启的扩展,它使用 CustomizableUI 模块添加了一个按钮。当用户点击这个按钮,这个扩展运行一些代码来改变当前标签。其基础构造取自 Jorge Villalobos 的 Australis "Hello World" 扩展 .
-
- 代码实际做的事是:找到任意 <img> 元素并将其 src 替换为从硬编码于扩展中的列表中随机抽取的无意义的 GIF 图像。 无意义的 gifs 从Whimsy extension 获取。

- -

第一个版本直接访问页面,因此其不是多进程兼容的:

- -
// bootstrap.js
-
-let Gifinate = {
-  init : function() {
-    let io =
-      Cc["@mozilla.org/network/io-service;1"].
-        getService(Ci.nsIIOService);
-
-    // the 'style' directive isn't supported in chrome.manifest for bootstrapped
-    // extensions, so this is the manual way of doing the same.
-    this._ss =
-      Cc["@mozilla.org/content/style-sheet-service;1"].
-        getService(Ci.nsIStyleSheetService);
-    this._uri = io.newURI("chrome://gifinate/skin/toolbar.css", null, null);
-    this._ss.loadAndRegisterSheet(this._uri, this._ss.USER_SHEET);
-
-    // create widget and add it to the main toolbar.
-    CustomizableUI.createWidget(
-      { id : "gifinate-button",
-        defaultArea : CustomizableUI.AREA_NAVBAR,
-        label : "Gifinate",
-        tooltiptext : "Gifinate!",
-        onCommand : function(aEvent) {
-          Gifinate.replaceImages(aEvent.target.ownerDocument.defaultView.content.document);
-        }
-      });
-  },
-
-  replaceImages : function(contentDocument) {
-      let images = contentDocument.getElementsByTagName("img");
-      for (var i = 0; i < images.length; ++i) {
-        let gif = this.gifs[Math.floor(Math.random() * this.gifs.length)];
-        images[i].src = gif;
-      }
-    },
- -

- -

移植到消息管理器

- -

为了移植这个例子到消息管理器,我们将使 onCommand 加载一个框架脚本到当前的 <browser>,然后监听来自框架脚本的 "request-gifs" 信息。这些 "request-gifs" 信息应当包含我们在此页面上需要的 GIFs :信息监听器取回并返回这个数量的 GIFs。

- -
// bootstrap.js
-// will run in the chrome process
-
-let Gifinate = {
-  init : function() {
-    let io =
-      Cc["@mozilla.org/network/io-service;1"].
-        getService(Ci.nsIIOService);
-
-    // the 'style' directive isn't supported in chrome.manifest for bootstrapped
-    // extensions, so this is the manual way of doing the same.
-    this._ss =
-      Cc["@mozilla.org/content/style-sheet-service;1"].
-        getService(Ci.nsIStyleSheetService);
-    this._uri = io.newURI("chrome://gifinate/skin/toolbar.css", null, null);
-    this._ss.loadAndRegisterSheet(this._uri, this._ss.USER_SHEET);
-
-    // create widget and add it to the main toolbar.
-    CustomizableUI.createWidget(
-      { id : "gifinate-button",
-        defaultArea : CustomizableUI.AREA_NAVBAR,
-        label : "Gifinate Button",
-        tooltiptext : "Gifinate!",
-        onCommand : function(aEvent) {
-          Gifinate.replaceImages(aEvent.target.ownerDocument);
-        }
-      });
-  },
-
-  replaceImages : function(xulDocument) {
-    var browserMM = xulDocument.defaultView.gBrowser.selectedBrowser.messageManager;
-    browserMM.loadFrameScript("chrome://gifinate/content/frame-script.js", false);
-    browserMM.addMessageListener("request-gifs", Gifinate.getGifs);
-  },
-
-  getGifs : function(message) {
-    var gifsToReturn = new Array(message.data);
-    for (var i = 0; i < gifsToReturn.length; i++) {
-      let gif = this.gifs[Math.floor(Math.random() * this.gifs.length)];
-      gifsToReturn[i] = gif;
-    }
-    return gifsToReturn;
-  },
-
- -

再次地,我们需要为这个框架脚本注册一个 chrome:// URL:

- -
// chrome.manifest
-
-content gifinate frame-script.js
- -

在框架脚本中,我们获取所有的 <img> 元素并发送 "request-gifs" 信息给扩展主体代码。 由于这是框架脚本我们可以将其变为一个同步信息,并使用其返回值更新 src 属性:

- -
// frame-script.js
-// will run in the content process
-
-var images = content.document.getElementsByTagName("img");
-var response = sendSyncMessage("request-gifs", images.length);
-var gifs = response[0];
-
-for (var i = 0; i < images.length; ++i) {
-  images[i].src = gifs[i];
-}
- -

整个扩展的流程现在像这样:
-

- -

已知问题

- -

这里是可能影响扩展开发者移植到多进程firefox的开放的bug列表:

- - diff --git "a/files/zh-cn/mozilla/add-ons/\351\233\267\351\270\237/index.html" "b/files/zh-cn/mozilla/add-ons/\351\233\267\351\270\237/index.html" deleted file mode 100644 index c46b242f7e..0000000000 --- "a/files/zh-cn/mozilla/add-ons/\351\233\267\351\270\237/index.html" +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: 雷鸟扩展 -slug: Mozilla/Add-ons/雷鸟 -translation_of: Mozilla/Thunderbird/Thunderbird_extensions ---- -
Building a Thunderbird extension
-Step-by-step explanation on how to build an extension for Thunderbird.
- -
-

{{AddonSidebar}}

-本文档是为Mozilla公司的雷鸟邮件客户端开发扩展的教程。Although there are many similarities with Firefox extensions there are also some differences that may confound the starting developer.
- -

-Please help! You can add a how-to (a question or an answer or a code snippet), summarize and link to a relevant newsgroup discussion, or create a tutorial. Need help? Contact jenzed.
- - - - - - - - -
-

Documentation

- -

Getting started with Thunderbird

- -

A brave, young developer wants to develop an add-on for Thunderbird. Here's a few links to help them through this journey.

- -
    -
  • Start by reading the tutorial and learn how to build a Thunderbird extension (Outdated, still talks about overlays and the add-on builder is no longer available but the tutorial has not been updated.)
  • -
  • Read about the main windows so that you know what one means when they say « thread pane », « preview pane », and « folder pane ».
  • -
  • Read an overview of how the various parts of Thunderbird fit together, this really helps get a better understanding of Thunderbird.
  • -
  • Want to do some real stuff? See how to inspect a message (demo add-on included!)
  • -
  • Play with our other demo add-on that exercises some more advanced Thunderbird-specific features
  • -
  • Want to do even more stuff? Don't reinvent the wheel: steal functions from the thunderbird-stdlib project (doc here). Functions for dealing with messages (delete them, archive them, change their tags, etc.) are included.
  • -
  • Haven't found what you're looking for? Read the Thunderbird how-tos; they contain a lot of recipes for things extensions want to do.
  • -
  • Still haven't managed to do what you wanted? See the list of all Thunderbird communication channels so that you know where to ask when you get stuck :-).
  • -
  • Feeling really brave? Read the source using a fancy interface; you can often find tests that demonstrate how to do what you're trying to achieve.
  • -
- -

The Gloda database

- -

Thunderbird has a subsystem called Gloda. Gloda stands for « Global Database », and creates Thunderbird-wide relations between objects. Gloda provides concepts such as Conversations, Messages, Identities, Contacts. All these concepts are related together: a Conversation contains Messages which are linked to Identities (from field, to field) which are themselves part of a Contact: indeed, a contact has multiple identities.

- -

Typical use cases for Gloda: find all messages whose subject matches [search term], find all messages from [person], find all messages in the same thread as [a given message], find all messages involving [person], etc. etc.

- -

Gloda is extremely powerful and is used heavily by add-ons such as Thunderbird Conversations. Learn more about Gloda:

- - - - - -

Some of these links may be wildly out of date, but they still provide valuable information on the codebase.

- - - - - - -
-

Community

- - - -

{{ DiscussionList("dev-extensions", "mozilla.dev.extensions") }}

- - - -

Tools

- - - -

... more tools ...

- -

View All...

- - - -
-
XUL, JavaScript, XPCOM, Themes, Developing Mozilla
-
-
- -

Categories

- -

{{ languages( { "ja": "ja/Extensions/Thunderbird" } ) }}

-- cgit v1.2.3-54-g00ecf