diff --git a/addon-sdk/source/doc/dev-guide-source/cfx-tool.md b/addon-sdk/source/doc/dev-guide-source/cfx-tool.md deleted file mode 100644 index b3cd28ed9fde..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/cfx-tool.md +++ /dev/null @@ -1,932 +0,0 @@ - - -# cfx # - -The `cfx` command-line tool gives you access to the SDK documentation and -development servers as well as testing, running, and building add-ons. -`cfx` usage is: - -
-  cfx [options] command [command-specific options]
-
- -"Options" are global options applicable to the tool itself or to all -commands (for example `--help`). `cfx` supports the following global options: - -
-  -h, --help        - show a help message and exit
-  -v, --verbose     - enable lots of output
-
- -"Command-specific options" are documented alongside the commands. - -There are four supported cfx commands: - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- cfx init - - Create a skeleton add-on as a starting point for your own add-on. -
- cfx run - - Launch an instance of Firefox with your add-on installed. -
- cfx test - - Runs your add-on's unit tests. -
- cfx xpi - - Package your add-on as an XPI - file, which is the install file format for Firefox add-ons. -
- -There are also a number of -[internal commands](dev-guide/cfx-tool.html#internal-commands), -which are more likely to be useful to SDK developers than to add-on developers. - -## cfx init ## - -Create a new directory called "my-addon", change into it, and run `cfx init`. - -This command will create an skeleton add-on, as a starting point for your -own add-on development, with the following file structure: - - - -
- -## cfx run ## -This command is used to run the add-on. Called with no options it looks for a -file called `package.json` in the current directory, loads the corresponding -add-on, and runs it under the version of Firefox it finds in the platform's -default install path. - -### Supported Options #### - -You can point `cfx run` at a different `package.json` file using the -`--pkgdir` option, and pass arguments to your add-on using the -`--static-args` option. - -You can specify a different version of the -host application -using the `--binary` option, passing in the path to the application binary to -run. The path may be specified as a full path or may be relative to the current -directory. But note that the version must be 4.0b7 or later. - -`cfx run` runs the host application with a new -[profile](http://support.mozilla.com/en-US/kb/profiles). You can specify an -existing profile using the `--profiledir` option, and this gives you access to -that profile's history, bookmarks, and other add-ons. This enables you to run -your add-on alongside debuggers like [Firebug](http://getfirebug.com/). -See -"Using --profiledir" for more information. - - ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -b BINARY, --binary=BINARY - - Use the host application binary specified in BINARY. BINARY may be specified as - a full path or as a path relative to the current directory. -
- --binary-args=CMDARGS - -

Pass extra - arguments to the binary being executed (for example, Firefox).

-

For example, to pass the - -jsconsole argument to Firefox, which will launch the - JavaScript - Error Console, try the following:

-
cfx run --binary-args -jsconsole
-

To pass multiple arguments, or arguments containing spaces, quote them:

-
cfx run --binary-args '-url "www.mozilla.org" -jsconsole'
-
- --extra-packages=EXTRA_PACKAGES - - Extra packages to include, specified as a comma-separated list of package - names. -
- -g CONFIG, --use-config=CONFIG - - Pass a set of options by - referencing a named configuration. -
- -p PROFILEDIR, --profiledir=PROFILEDIR - -

Use an existing - profile - located in PROFILEDIR. PROFILEDIR may be specified as - a full path or as a path relative to the current directory.

- -

See - "Using --profiledir" for more information. -

- --pkgdir=PKGDIR - - Use an add-on located in PKGDIR. PKGDIR may be specified as - a full path or as a path relative to the current directory. -
- --static-args=STATIC_ARGS - - Pass arguments to your add-on, - in JSON format. -
- -### Experimental Options ### - - ---- - - - - - - - - - - - - - - - - - - - - - -
- -a APP, --app=APP - - By default, cfx run uses Firefox as the - host application. - This option enables you to select a different host. You can specify - "firefox", "xulrunner", "fennec", or "thunderbird". But note that at - present only Firefox is supported. -
- --no-run - -

With this option cfx will not execute the command, but - will print out the command that it would have used to execute the - command.

-

For example, if you type:

-
-cfx run ---no-run
-

you will see something like:

-
-To launch the application, enter the following command:
- /path/to/firefox/firefox-bin -profile
- /path/to/profile/tmpJDNlP6.mozrunner -foreground -no-remote
-

This enables you to run the add-on without going through - cfx, which might be useful if you want to run it - inside a debugger like GDB.

-
- -o, --overload-modules - -

In early versions of the SDK, the SDK modules used by an add-on - were themselves included in the add-on. The SDK modules now ship as - part of Firefox. From Firefox 21 onwards, SDK add-ons built with - SDK 1.14 or higher will use the SDK modules that are built into Firefox, - even if the add-on includes its own copies of the SDK modules.

-

Use this flag to reverse that behavior: if this flag is set and - the add-on includes its own copies of the SDK modules, then the add-on - will use the SDK modules in the add-on, not the ones built into Firefox.

-

This flag is particularly useful for SDK developers or people working with - the development version of the SDK, who may want to run an add-on using newer - versions of the modules than than those shipping in Firefox.

-
- --templatedir=TEMPLATEDIR - - The cfx run command constructs the add-on using a extension - template which you can find under the SDK root, in - app-extension. - Use the --templatedir option to specify a different template. - TEMPLATEDIR may be specified as a full path or as a path relative to the - current directory. -
- -### Internal Options ### - - ---- - - - - - - - - - - - - - - - - -
- --addons=ADDONS - - Paths of add-ons to install, comma-separated. ADDONS may be specified as - a full path or as a path relative to the current directory. -
- --e10s - - If this option is set then the add-on runs in a separate process. - This option is currently not implemented. -
- --keydir=KEYDIR - - Supply a different location for - signing keys. - KEYDIR may be specified as a full path or as a path relative to the - current directory. -
- -## cfx test ## -Run available tests for the specified package. - -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". - -Called with no options this command will look for a file called `package.json` -in the current directory. If `package.json` exists, `cfx` will load the -corresponding add-on, load from the `tests` directory -any modules that start with the word `test-` and run the unit tests -they contain. - -See the -[tutorial on unit testing](dev-guide/tutorials/unit-testing.html) and the -[reference documentation for the `assert` module](modules/sdk/test/assert.html) -for details. - -### Supported Options ### - -As with `cfx run` you can use options to control which host application binary -version to use, and to select a profile. - -You can also control which tests are run: you -can test dependent packages, filter the tests by name and run tests multiple -times. - - ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -b BINARY, --binary=BINARY - - Use the host application binary specified in BINARY. BINARY may be specified as - a full path or as a path relative to the current directory. -
- --binary-args=CMDARGS - -

Pass extra - arguments to the binary being executed (for example, Firefox).

-

For example, to pass the - -jsconsole argument to Firefox, which will launch the - JavaScript - Error Console, try the following:

-
cfx run --binary-args -jsconsole
-

To pass multiple arguments, or arguments containing spaces, quote them:

-
cfx run --binary-args '-url "www.mozilla.org" -jsconsole'
-
- --dependencies - - Load and run any tests that are included with modules that your package - depends on. -
- For example: if your add-on depends on modules from the SDK, then - cfx will run the unit tests for the SDK's modules as well - as yours. -
- -f FILENAME[:TESTNAME], --filter=FILENAME[:TESTNAME] - - Only run tests whose filenames match FILENAME and - optionally match TESTNAME, both regexps (test, testall, testex, testpkgs) -
- For example: if you specify --filter data, then - cfx will only run tests in those modules whose name contain - the string "data". -
- -g CONFIG, --use-config=CONFIG - - Pass a set of options by - referencing a named configuration. -
- -p PROFILEDIR, --profiledir=PROFILEDIR - -

Use an existing - profile - located in PROFILEDIR. PROFILEDIR may be specified as - a full path or as a path relative to the current directory.

- -

See - "Using --profiledir" for more information. -

- --times=ITERATIONS - - Execute tests ITERATIONS number of times. -
- -### Experimental Options ### - - ---- - - - - - - - - - - - - - - - - -
- -a APP, --app=APP - - By default, cfx test uses Firefox as the - host application. - This option enables you to select a different host. You can specify - "firefox", "xulrunner", "fennec", or "thunderbird". But note that at - present only Firefox is supported. -
- --no-run - -

With this option cfx will not execute the command, but - will print out the command that it would have used to execute the - command.

-

For example, if you type:

-
-cfx run ---no-run
-

you will see something like:

-
-To launch the application, enter the following command:
- /path/to/firefox/firefox-bin -profile
- /path/to/profile/tmpJDNlP6.mozrunner -foreground -no-remote
-

This enables you to run the add-on without going through - cfx, which might be useful if you want to run it - inside a debugger like GDB.

-
- -o, --overload-modules - -

In early versions of the SDK, the SDK modules used by an add-on - were themselves included in the add-on. The SDK modules now ship as - part of Firefox. From Firefox 21 onwards, SDK add-ons built with - SDK 1.14 or higher will use the SDK modules that are built into Firefox, - even if the add-on includes its own copies of the SDK modules.

-

Use this flag to reverse that behavior: if this flag is set and - the add-on includes its own copies of the SDK modules, then the add-on - will use the SDK modules in the add-on, not the ones built into Firefox.

-

This flag is particularly useful for SDK developers or people working with - the development version of the SDK, who may want to run an add-on using newer - versions of the modules than than those shipping in Firefox.

-
- -### Internal Options ### - - ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- --addons=ADDONS - - Paths of add-ons to install, comma-separated. - ADDONS may be specified as full paths or relative to the - current directory. -
- --e10s - - If this option is set then the add-on runs in a separate process. - This option is currently not implemented. -
- --keydir=KEYDIR - - Supply a different location for - signing keys. - KEYDIR may be specified as a full path or as a path relative to the - current directory. -
- --logfile=LOGFILE - - Log console output to the file specified by LOGFILE. - LOGFILE may be specified as a full path or as a path relative to the - current directory. -
- --profile-memory=PROFILEMEMORY - - If this option is given and PROFILEMEMORY is any non-zero integer, then - cfx dumps detailed memory usage information to the console - when the tests finish. -
- --test-runner-pkg=TEST_RUNNER_PKG - - Name of package containing test runner program. Defaults to - test-harness. -
- -## cfx xpi ## -This tool is used to package your add-on as an -[XPI](https://developer.mozilla.org/en/XPI) file, which is the install file -format for Mozilla add-ons. - -Called with no options, this command looks for a file called `package.json` in -the current directory and creates the corresponding XPI file. - -Once you have built an XPI file you can distribute your add-on by submitting -it to [addons.mozilla.org](http://addons.mozilla.org). - -### updateURL and updateLink ### - -If you choose to host the XPI yourself you should enable the host application -to find new versions of your add-on. - -To do this, include a URL in the XPI called the -[updateURL](https://developer.mozilla.org/en/install_manifests#updateURL): the -host application will go here to get information about updates. At the -`updateURL` you host a file in the -[update RDF](https://developer.mozilla.org/en/extension_versioning,_update_and_compatibility#Update_RDF_Format) -format: among other things, this includes another URL called `updateLink` which -points to the updated XPI itself. - -The `--update-link` and `--update-url` options simplify this process. -Both options take a URL as an argument. - -The `--update-link` option builds an update RDF alongside the XPI, and embeds -the supplied URL in the update RDF as the value of `updateLink`. - -The `--update-url` option embeds the supplied URL in the XPI file, as the value -of `updateURL`. - -Note that as the [add-on documentation](https://developer.mozilla.org/en/extension_versioning,_update_and_compatibility#Securing_Updates) -explains, you should make sure the update procedure for your add-on is secure, -and this usually involves using HTTPS for the links. - -So if we run the following command: - -
-  cfx xpi --update-link https://example.com/addon/latest/pluginName.xpi --update-url https://example.com/addon/update_rdf/pluginName.update.rdf
-
- -`cfx` will create two files: - -* an XPI file which embeds -`https://example.com/addon/update_rdf/pluginName.update.rdf` as the value of `updateURL` -* an RDF file which embeds `https://example.com/addon/latest/pluginName.xpi` as the value of -`updateLink`. - -### Supported Options ### - -As with `cfx run` you can point `cfx` at a different `package.json` file using -the `--pkgdir` option. You can also embed arguments in the XPI using the -`--static-args` option: if you do this the arguments will be passed to your -add-on whenever it is run. - - ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- --extra-packages=EXTRA_PACKAGES - - Extra packages to include, specified as a comma-separated list of package - names. -
- -g CONFIG, --use-config=CONFIG - - Pass a set of options by - referencing a named configuration. -
- --pkgdir=PKGDIR - - Use an add-on located in PKGDIR. - PKGDIR may be specified as a full path or as a path relative to the - current directory. -
- --static-args=STATIC_ARGS - - Pass arguments to your add-on, - in JSON format. -
- --update-link=UPDATE_LINK - - Build an - update RDF - alongside the XPI file, and embed the URL supplied in UPDATE_LINK in it as - the value of updateLink. -
- --update-link=UPDATE_URL - - Embed the URL supplied in UPDATE_URL in the XPI file, as the value - of updateURL. -
- -### Experimental Options ### - - ---- - - - - - - -
- --templatedir=TEMPLATEDIR - - The cfx xpi command constructs the add-on using a extension - template which you can find under the SDK root, in - app-extension. - Use the --templatedir option to specify a different template. - TEMPLATEDIR may be specified as a full path or as a path relative to the - current directory. -
- -### Internal Options ### - - ---- - - - - - - -
- --keydir=KEYDIR - - Supply a different location for - signing keys. - KEYDIR may be specified as a full path or as a path relative to the - current directory. -
- -## Internal Commands ## - -### cfx sdocs ### - -Executing this command builds a static HTML version of the SDK documentation -that can be hosted on a web server. - -#### Options #### - - ---- - - - - - - -
- --baseurl=BASEURL - - The root of the static docs tree, for example: - http://example.com/sdk-docs/. -
- -### cfx testcfx ### - -This will run a number of tests on the cfx tool, including tests against the -documentation. Use `cfx testcfx -v` for the specific list of tests. - -This accepts the same options as `cfx test`. - -### cfx testaddons ### - -This will run a number of test add-ons that are packaged with the SDK. - -This accepts the same options as `cfx test`. - -### cfx testpkgs ### - -This will test all of the available CommonJS packages. Note that the number -of tests run and their success depends on what application they are run -with, and which binary is used. - -This accepts the same options as `cfx test`. - -### cfx testex ### - -This will test all available example code. Note that the number -of tests run and their success depends on what application they are run -with, and which binary is used. - -This accepts the same options as `cfx test`. - -### cfx testall ### - -This will test *everything*: the cfx tool, all available CommonJS packages, -and all examples. - -This accepts the same options as `cfx test`. - -## Using --profiledir ## - -By default, `cfx run` and `cfx test` use a new profile each time they -are executed. This means that any profile-specific data entered from -one run of `cfx` will not, by default, be available in the next run. - -This includes, for example, any extra add-ons you installed, or your -history, or any data stored using the -[simple-storage](modules/sdk/simple-storage.html) API. - -To make `cfx` use a specific profile, pass the `--profiledir` option, -specifying the path to the profile you wish to use. - -If you give `--profiledir` a path to a nonexistent profile, `cfx` -will create a profile there for you. So you just have to make up -a path and name the first time, and keep using it: - -
-cfx run --profiledir="~/addon-dev/profiles/boogaloo"
-
- -The path must contain at least one "/" (although you may specify -just "./dir"). - -## Using Configurations ## - -The `--use-config` option enables you to specify a set of options as a named -configuration in a file, then pass them to `cfx` by referencing the named set. - -You define configurations in a file called `local.json` which should live -in the root directory of your SDK. Configurations are listed under a key called -"configs". - -Suppose your the following `local.json` is as follows: - -
-  {
-      "configs": {
-          "ff40": ["-b", "/usr/bin/firefox-4.0"]
-      }
-  }
-
- -You can run: - -
-  cfx test --use-config=ff40
-
- -And it would be equivalent to: - -
-  cfx test -a firefox -b /usr/bin/firefox-4.0
-
- -This method of defining configuration options can be used for all of the `run`, -build, and test tools. If "default" is defined in the `local.json` cfx will use -that configuration unless otherwise specified. - -## Passing Static Arguments ## - -You can use the cfx `--static-args` option to pass arbitrary data to your -program. This may be especially useful if you run cfx from a script. - -The value of `--static-args` must be a JSON string. The object encoded by the -JSON becomes the `staticArgs` property of the -[`system` module](modules/sdk/system.html). - -The default value of -`--static-args` is `"{}"` (an empty object), so you don't have to worry about -checking whether `staticArgs` exists in `system`. - -For example, if your add-on looks like this: - - var system = require("sdk/system"); - console.log(system.staticArgs.foo); - -And you run cfx like this: - -
-  cfx run --static-args="{ \"foo\": \"Hello from the command line\" }"
-
- -Then your console should contain this: - -
-info: my-addon: Hello from the command line
-
- -The `--static-args` option is recognized by two of the package-specific -commands: `run` and `xpi`. When used with the `xpi` command, the JSON is -packaged with the XPI's harness options and will therefore be used whenever the -program in the XPI is run. diff --git a/addon-sdk/source/doc/dev-guide-source/console.md b/addon-sdk/source/doc/dev-guide-source/console.md deleted file mode 100644 index 33f21c5a44a7..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/console.md +++ /dev/null @@ -1,207 +0,0 @@ - - -# console # - -The `console` object enables your add-on to log messages. If you have started -Firefox for your add-on from the command line with `cfx run` or `cfx test` -then these messages appear in the command shell you used. If the add-on has -been installed in Firefox, then the messages appear in the host application's -[Error Console](https://developer.mozilla.org/en/Error_Console). - -If you're developing your add-on using the -[Add-on Builder](https://builder.addons.mozilla.org/) or are using -the [Extension Auto-installer](https://addons.mozilla.org/en-US/firefox/addon/autoinstaller/), -then the add-on is installed in Firefox, meaning that messages will appear in -the Error Console. But see the discussion of -[logging levels](dev-guide/console.html#Logging Levels): by default, messages -logged using `log()`, `info()`, `trace()`, or `warn()` won't be logged in -these situations. - -## Console Methods ## - -All console methods except `exception()` and `trace()` accept one or -more JavaScript objects as arguments and log them to the console. -Depending on the console's underlying implementation and user interface, -you may be able to examine the properties of non-primitive objects -that are logged. - -### console.log(*object*[, *object*, ...]) ### - -Logs the arguments to the console, preceded by "info:" and the name of your -add-on: - - console.log("This is an informational message"); - -
-info: my-addon: This is an informational message
-
- -### console.info(*object*[, *object*, ...]) ### - -A synonym for `console.log()`. - -### console.warn(*object*[, *object*, ...]) ### - -Logs the arguments to the console, preceded by "warn:" and the name of your -add-on: - - console.warn("This is a warning message"); - -
-warn: my-addon: This is a warning message
-
- -### console.error(*object*[, *object*, ...]) ### - -Logs the arguments to the console, preceded by "error:" and the name of your -add-on: - - console.error("This is an error message"); - -
-error: my-addon: This is an error message
-
- -### console.debug(*object*[, *object*, ...]) ### - -Logs the arguments to the console, preceded by "debug:" and the name of your -add-on: - - console.error("This is a debug message"); - -
-debug: my-addon: This is a debug message
-
- -### console.exception(*exception*) ### - -Logs the given exception instance as an error, outputting information -about the exception's stack traceback if one is available. - - try { - doThing(); - } catch (e) { - console.exception(e); - } - - function UserException(message) { - this.message = message; - this.name = "UserException"; - } - - function doThing() { - throw new UserException("Thing could not be done!"); - } - -
-error: my-addon: An exception occurred.
-UserException: Thing could not be done!
-
- -### console.trace() ### - -Logs a stack trace at the point the function is called. - -

Logging Levels

- -Logging's useful, of course, especially during development. But the more -logging there is, the more noise you see in the console output. -Especially when debug logging shows up in a production environment, the -noise can make it harder, not easier, to debug issues. - -This is the problem that logging levels are designed to fix. The console -defines a number of logging levels, from "more verbose" to "less verbose", -and a number of different logging functions that correspond to these levels, -which are arranged in order of "severity" from informational -messages, through warnings, to errors. - -At a given logging level, only calls to the corresponding functions and -functions with a higher severity will have any effect. - -For example, if the logging level is set to "info", then calls to `info()`, -`log()`, `warn()`, and `error()` will all result in output being written. -But if the logging level is "warn" then only calls to `warn()` and `error()` -have any effect, and calls to `info()` and `log()` are simply discarded. - -This means that the same code can be more verbose in a development -environment than in a production environment - you just need to arrange for -the appropriate logging level to be set. - -The complete set of logging levels is given in the table below, along -with the set of functions that will result in output at each level: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LevelWill log calls to:
allAny console method
debugdebug(), log(), info(), trace(), warn(), exception(), error()
infolog(), info(), trace(), warn(), exception(), error()
warnwarn(), exception(), error()
errorexception(), error()
offNothing
- -### Setting the Logging Level ### - -The logging level defaults to "error". - -There are two system preferences that can be used to override this default: - -* **extensions.sdk.console.logLevel**: if set, this determines the logging -level for all installed SDK-based add-ons. - -* **extensions.[extension-id].sdk.console.logLevel**: if set, this determines -the logging level for the specified add-on. This overrides the global -preference if both are set. - -Both these preferences can be set programmatically using the -[`preferences/service`](modules/sdk/preferences/service.html) API, or manually -using [about:config](http://kb.mozillazine.org/About:config). The value for each -preference is the desired logging level, given as a string. - -When you run your add-on using `cfx run` or `cfx test`, the global -**extensions.sdk.console.logLevel** preference is automatically set to "info". -This means that calls to `console.log()` will appear in the console output. - -When you install an add-on into Firefox, the logging level will be "error" -by default (that is, unless you have set one of the two preferences). This -means that messages written using `debug()`, `log()`, `info()`, `trace()`, -and `warn()` will not appear in the console. - -This includes add-ons being developed using the -[Add-on Builder](https://builder.addons.mozilla.org/) or the -[Extension Auto-installer](https://addons.mozilla.org/en-US/firefox/addon/autoinstaller/). diff --git a/addon-sdk/source/doc/dev-guide-source/credits.md b/addon-sdk/source/doc/dev-guide-source/credits.md deleted file mode 100644 index 8ad6acb648d1..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/credits.md +++ /dev/null @@ -1,167 +0,0 @@ - - -# Credits # - -We'd like to thank our many Jetpack project contributors! They include: - -### A ### - -* Adamantium -* Ehsan Akhgari -* arky -* [Heather Arthur](https://github.com/harthur) -* Dietrich Ayala - -### B ### - -* [Romain B](https://github.com/Niamor) -* [Louis-Rémi Babé](https://github.com/louisremi) -* Will Bamberg -* Thomas Bassetto -* Tomaz Bevec -* Zbigniew Braniecki -* Daniel Buchner -* James Burke - -### C ### - -* [Shane Caraveo](https://github.com/mixedpuppy) -* [Matěj Cepl](https://github.com/mcepl) -* Marc Chevrier -* [Timothy Guan-tin Chien](https://github.com/timdream) -* Hernán Rodriguez Colmeiro -* [David Creswick](https://github.com/dcrewi) - -### D ### - -* dexter -* Christopher Dorn -* Connor Dunn -* dynamis - -### F ### - -* [Corey Farwell](http://github.com/frewsxcv) -* [Matteo Ferretti](https://github.com/ZER0) -* fuzzykiller - -### G ### - -* [Marcio Galli](https://github.com/taboca) -* [Ben Gillbanks](http://www.iconfinder.com/browse/iconset/circular_icons/) -* Felipe Gomes -* Irakli Gozalishvili -* Luca Greco -* Jeff Griffiths -* [David Guo](https://github.com/dglol) - -### H ### - -* Mark Hammond -* Mark A. Hershberger -* Lloyd Hilaiel -* Bobby Holley - -### I ### - -* Shun Ikejima - -### J ### - -* Tomislav Jovanovic -* Eric H. Jung - -### K ### - -* Hrishikesh Kale -* Wes Kocher -* Lajos Koszti -* Kusanagi Kouichi -* [Vladimir Kukushkin](https://github.com/kukushechkin) - -### L ### - -* Edward Lee -* Gregg Lind - -### M ### - -* [Nils Maier](https://github.com/nmaier) -* Gervase Markham -* Dave Mason -* Myk Melez -* Zandr Milewski -* Noelle Murata - -### N ### - -* Siavash Askari Nasr -* Joe R. Nassimian ([placidrage](https://github.com/placidrage)) -* Dương H. Nguyễn -* Nick Nguyen -* nodeless - -### O ### - -* [ongaeshi](https://github.com/ongaeshi) -* Paul O’Shannessy -* Les Orchard - -### P ### - -* Robert Pankowecki -* [Jamie Phelps](https://github.com/jxpx777) -* [Alexandre Poirot](https://github.com/ochameau) -* Nickolay Ponomarev - -### R ### - -* Aza Raskin - -### S ### - -* [Jordan Santell](https://github.com/jsantell) -* Till Schneidereit -* Justin Scott -* Ayan Shah -* [skratchdot](https://github.com/skratchdot) -* Henrik Skupin -* slash -* Markus Stange -* Dan Stevens -* [J. Ryan Stinnett](https://github.com/jryans) -* [Mihai Sucan](https://github.com/mihaisucan) -* Sunny ([darkowlzz](https://github.com/darkowlzz)) - -### T ### - -* taku0 -* Clint Talbert -* Tim Taubert -* Shane Tomlinson -* Dave Townsend -* [Fraser Tweedale](https://github.com/frasertweedale) -* [Matthias Tylkowski](https://github.com/tylkomat) - -### V ### - -* Peter Van der Beken -* Sander van Veen -* Atul Varma -* [Erik Vold](https://github.com/erikvold) -* Vladimir Vukicevic - -### W ### - -* Brian Warner -* [Henri Wiechers](https://github.com/hwiechers) -* Drew Willcoxon -* Blake Winton -* Michal Wojciechowski - -### Z ### - -* Piotr Zalewa -* Brett Zamir diff --git a/addon-sdk/source/doc/dev-guide-source/glossary.md b/addon-sdk/source/doc/dev-guide-source/glossary.md deleted file mode 100644 index 5f5b8cf7b9bc..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/glossary.md +++ /dev/null @@ -1,73 +0,0 @@ - - -# Glossary # - -This glossary contains a list of terms used in the Add-on SDK. - -__Add-on__: A software package that adds functionality to a Mozilla application, -which can be built with either Mozilla's traditional add-on platform or the SDK. - -__Add-on SDK__: A toolchain and associated applications for developing add-ons. - -__API Utils__: A small, self-contained set of low-level modules that forms -the base functionality for the SDK. The library can be "bootstrapped" into -any Mozilla application or add-on. - -__CFX__: A command-line build, testing, and packaging tool for SDK-based code. - -__CommonJS__: A specification for a cross-platform JavaScript module -system and standard library. [Web site](http://commonjs.org/). - -__Extension__: Synonym for Add-on. - -__Globals__: The set of global variables and objects provided -to all modules, such as `console` and `memory`. Includes -CommonJS globals like `require` and standard JavaScript globals such -as `Array` and `Math`. - -__Host Application__: Add-ons are executed in -the context of a host application, which is the application they are extending. -Firefox and Thunderbird are the most obvious hosts for Mozilla add-ons, but -at present only Firefox is supported as a host for add-ons developed using the -Add-on SDK. - -__Jetpack Prototype__: A Mozilla Labs experiment that predated and inspired -the SDK. The SDK incorporates many ideas and some code from the prototype. - -__Loader__: An object capable of finding, evaluating, and -exposing CommonJS modules to each other in a given security context, -while providing each module with necessary globals and -enforcing security boundaries between the modules as necessary. It's -entirely possible for Loaders to create new Loaders. - -__Low-Level Module__: A module with the following properties: - - * Has "chrome" access to the Mozilla platform (e.g. `Components.classes`) - and all globals. - * Is reloadable without leaking memory. - * Logs full exception tracebacks originating from client-provided - callbacks (i.e., does not allow the exceptions to propagate into - Mozilla platform code). - * Can exist side-by-side with multiple instances and versions of - itself. - * Contains documentation on security concerns and threat modeling. - -__Module__: A CommonJS module that is either a Low-Level Module -or an Unprivileged Module. - -__Package__: A directory structure containing modules, -documentation, tests, and related metadata. If a package contains -a program and includes proper metadata, it can be built into -a Mozilla application or add-on. - -__Program__: A module named `main` that optionally exports -a `main()` function. This module is intended either to start an application for -an end-user or add features to an existing application. - -__Unprivileged Module__: A CommonJS module that may be run -without unrestricted access to the Mozilla platform, and which may use -all applicable globals that don't require chrome privileges. - - [Low-Level Module Best Practices]: dev-guide/module-development/best-practices.html diff --git a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/accessing-the-dom.md b/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/accessing-the-dom.md deleted file mode 100644 index 7e66a7925a9a..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/accessing-the-dom.md +++ /dev/null @@ -1,164 +0,0 @@ - - -# Accessing the DOM # - -This page talks about the access content scripts have to DOM objects -in the pages they are attached to. - -## XRayWrapper ## - -Content scripts need to be able to access DOM objects in arbitrary web -pages, but this could cause two potential security problems: - -1. JavaScript values from the content script could be accessed by the page, -enabling a malicious page to steal data or call privileged methods. -2. a malicious page could redefine standard functions and properties of DOM -objects so they don't do what the add-on expects. - -To deal with this, content scripts access DOM objects using -`XRayWrapper`, (also known as -[`XPCNativeWrapper`](https://developer.mozilla.org/en/XPCNativeWrapper)). -These wrappers give the user access to the native values of DOM functions -and properties, even if they have been redefined by a script. - -For example: the page below redefines `window.confirm()` to return -`true` without showing a confirmation dialog: - - - -But thanks to the wrapper, a content script which calls -`window.confirm()` will get the native implementation: - - var widgets = require("sdk/widget"); - var tabs = require("sdk/tabs"); - var data = require("sdk/self").data; - - var widget = widgets.Widget({ - id: "transfer", - label: "Transfer", - content: "Transfer", - width: 100, - onClick: function() { - tabs.activeTab.attach({ - // native implementation of window.confirm will be used - contentScript: "console.log(window.confirm('Transfer all my money?'));" - }); - } - }); - - tabs.open(data.url("xray.html")); - -The wrapper is transparent to content scripts: as far as the content script -is concerned, it is accessing the DOM directly. But because it's not, some -things that you might expect to work, won't. For example, if the page includes -a library like [jQuery](http://www.jquery.com), or any other page script -adds other objects to any DOM nodes, they won't be visible to the content -script. So to use jQuery you'll typically have to add it as a content script, -as in [this example](dev-guide/guides/content-scripts/reddit-example.html). - -### XRayWrapper Limitations ### - -There are some limitations with accessing objects through XRayWrapper. - -First, XRayWrappers don't inherit from JavaScript's -[`Object`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object), -so methods like `valueOf`, `toSource`, and `watch` are not available. -This issue is being tracked as -[bug 787013](https://bugzilla.mozilla.org/show_bug.cgi?id=787013). - -Second, you can't access the prototype of an object through an XRayWrapper. -Consider a script like this: - - window.HTMLElement.prototype.foo = 'bar'; - window.alert(window.document.body.foo); - -Run as a normal page script, this will work fine. But if you execute it as -a content script you'll see an error like: - -
-TypeError: window.HTMLElement.prototype is undefined
-
- -This issue is being tracked as -[bug 787070](https://bugzilla.mozilla.org/show_bug.cgi?id=787070). - -The main effect of this is that certain features of the -[Prototype JavaScript framework](http://www.prototypejs.org/) don't work -if it is loaded as a content script. As a workaround you can -disable these features by setting -`Prototype.BrowserFeatures.SpecificElementExtensions` to `false` -in `prototype.js`: - -
- if (Prototype.Browser.MobileSafari)
-   Prototype.BrowserFeatures.SpecificElementExtensions = false;
-
-+// Disable element extension in addon-sdk content scripts
-+Prototype.BrowserFeatures.SpecificElementExtensions = false;
-
- -## Adding Event Listeners ## - -You can listen for DOM events in a content script just as you can in a normal -page script, but there's one important difference: if you define an event -listener by passing it as a string into -[`setAttribute()`](https://developer.mozilla.org/en/DOM/element.setAttribute), -then the listener is evaluated in the page's context, so it will not have -access to any variables defined in the content script. - -For example, this content script will fail with the error "theMessage is not -defined": - - var theMessage = "Hello from content script!"; - - anElement.setAttribute("onclick", "alert(theMessage);"); - -So using `setAttribute()` is not recommended. Instead, add a listener by -assignment to -[`onclick`](https://developer.mozilla.org/en/DOM/element.onclick) or by using -[`addEventListener()`](https://developer.mozilla.org/en/DOM/element.addEventListener), -in either case defining the listener as a function: - - var theMessage = "Hello from content script!"; - - anElement.onclick = function() { - alert(theMessage); - }; - - anotherElement.addEventListener("click", function() { - alert(theMessage); - }); - -Note that with both `onclick` assignment and `addEventListener()`, you must -define the listener as a function. It cannot be defined as a string, whether -in a content script or in a page script. - -## unsafeWindow ## - -If you really need direct access to the underlying DOM, you can use the -global `unsafeWindow` object. - -To see the difference, try editing the example above -so the content script uses `unsafeWindow.confirm()` instead of -`window.confirm()`. - -Avoid using `unsafeWindow` if possible: it is the same concept as -Greasemonkey's unsafeWindow, and the -[warnings for that](http://wiki.greasespot.net/UnsafeWindow) apply equally -here. Also, `unsafeWindow` isn't a supported API, so it could be removed or -changed in a future version of the SDK. diff --git a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/communicating-with-other-scripts.md b/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/communicating-with-other-scripts.md deleted file mode 100644 index 7f39ff5538b7..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/communicating-with-other-scripts.md +++ /dev/null @@ -1,246 +0,0 @@ - - -# Communicating With Other Scripts # - -This section of the guide explains how content scripts can -communicate with: - -* [your `main.js` file](dev-guide/guides/content-scripts/communicating-with-other-scripts.html#main.js), -or any other modules in your add-on -* [other content scripts loaded by your add-on](dev-guide/guides/content-scripts/communicating-with-other-scripts.html#Content Scripts) -* [page scripts](dev-guide/guides/content-scripts/communicating-with-other-scripts.html#Page Scripts) (that is, scripts embedded in the web page or -included using ` - -#### Messaging From Page Script To Content Script #### - -Sending messages from the page script to the content script is just -the same, but in reverse. - -Here "main.js" creates a [`page-mod`](modules/sdk/page-mod.html) -that attaches "listen.js" to the web page: - - var data = require("sdk/self").data; - - var pageMod = require("sdk/page-mod"); - pageMod.PageMod({ - include: "http://my-domain.org/talk.html", - contentScriptFile: data.url("listen.js") - }); - -The web page "talk.html" embeds a script that uses `window.postMessage()` -to send the content script a message when the user clicks a button: - - - -Finally, the content script "listen.js" uses -`document.defaultView.addEventListener()` to listen for messages from the page -script: - - document.defaultView.addEventListener('message', function(event) { - console.log(event.data); - console.log(event.origin); - }, false); - -### Using Custom DOM Events ### - -As an alternative to using `postMessage()` you can use -[custom DOM events](https://developer.mozilla.org/en/DOM/CustomEvent) -to communicate between page scripts and content scripts. - -#### Messaging From Content Script To Page Script #### - -Here's an example showing how to use custom DOM events to send a message -from a content script to a page script. - -First, "main.js" will create a [`page-mod`](modules/sdk/page-mod.html) -that will attach "talk.js" to the target web page: - - var data = require("sdk/self").data; - - var pageMod = require("sdk/page-mod"); - pageMod.PageMod({ - include: "http://my-domain.org/listen.html", - contentScriptFile: data.url("talk.js") - }); - -Next, "talk.js" creates and dispatches a custom event, passing the payload -in the `detail` parameter to `initCustomEvent()`: - - - - var event = document.createEvent('CustomEvent'); - event.initCustomEvent("addon-message", true, true, { hello: 'world' }); - document.documentElement.dispatchEvent(event); - -Finally "listen.html" listens for the new event and examines its -`detail` attribute to retrieve the payload: - - - -#### Messaging From Page Script to Content Script #### - -Sending messages using custom DOM events from the page script -to the content script is just the same, but in reverse. - -Again, "main.js" creates a [`page-mod`](modules/sdk/page-mod.html) -to target the page we are interested in: - - var data = require("sdk/self").data; - - var pageMod = require("sdk/page-mod"); - pageMod.PageMod({ - include: "http://my-domain.org/talk.html", - contentScriptFile: data.url("listen.js") - }); - -The web page "talk.html" creates and dispatches a custom DOM event, -using `initCustomEvent()`'s `detail` parameter to supply the payload: - - - -Finally, the content script "listen.js" listens for the new event -and retrieves the payload from its `detail` attribute: - - document.documentElement.addEventListener("addon-message", function(event) { - console.log(JSON.stringify(event.detail)); - }, false); - diff --git a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/cross-domain.md b/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/cross-domain.md deleted file mode 100644 index aa6b53e425a3..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/cross-domain.md +++ /dev/null @@ -1,177 +0,0 @@ - - -# Cross-domain Content Scripts # - -By default, content scripts don't have any cross-domain privileges. -In particular, they can't: - -* [access content hosted in an `iframe`, if that content is served from a different domain](dev-guide/guides/content-scripts/cross-domain.html#Cross-domain iframes) -* [make cross-domain XMLHttpRequests](dev-guide/guides/content-scripts/cross-domain.html#Cross-domain XMLHttpRequest) - -However, you can enable these features for specific domains -by adding them to your add-on's [package.json](dev-guide/package-spec.html) -under the `"cross-domain-content"` key, which itself lives under the -`"permissions"` key: - -
-"permissions": {
-    "cross-domain-content": ["http://example.org/", "http://example.com/"]
-}
-
- -* The domains listed must include the scheme and fully qualified domain name, -and these must exactly match the domains serving the content - so in the -example above, the content script will not be allowed to access content -served from `https://example.com/`. -* Wildcards are not allowed. -* This feature is currently only available for content scripts, not for page -scripts included in HTML files shipped with your add-on. - -## Cross-domain iframes ## - -The following "main.js" creates a page-worker which loads a local HTML file -called "page.html", attaches a content script called "page.js" to the -page, waits for messages from the script, and logs the payload. - - //main.js - var data = require("sdk/self").data; - - var pageWorker = require("sdk/page-worker").Page({ - contentURL: data.url("page.html"), - contentScriptFile: data.url("page-script.js") - }); - - pageWorker.on("message", function(message) { - console.log(message); - }); - -The "page.html" file embeds an iframe whose content is -served from "http://en.m.wikipedia.org/": - -
-    <!doctype html>
-    <!-- page.html -->
-    <html>
-      <head></head>
-      <body>
-        <iframe id="wikipedia" src="http://en.m.wikipedia.org/"></iframe>
-      </body>
-    </html>
-
- -The "page-script.js" file locates "Today's Featured Article" and sends its -content to "main.js": - - // page-script.js - var iframe = window.document.getElementById("wikipedia"); - var todaysFeaturedArticle = iframe.contentWindow.document.getElementById("mp-tfa"); - self.postMessage(todaysFeaturedArticle.textContent); - -For this to work, we need to add the `"cross-domain-content"` key to -"package.json": - -
-"permissions": {
-  "cross-domain-content": ["http://en.m.wikipedia.org/"]
-}
-
- -The add-on should successfully retrieve the iframe's content. - -## Cross-domain XMLHttpRequest ## - -The following add-on creates a panel whose content is the summary weather -forecast for [Shetland](https://en.wikipedia.org/wiki/Shetland). -If you want to try it out, you'll need to -[register](http://www.metoffice.gov.uk/datapoint/support/API) -and get an API key. - -The "main.js": - -* creates a panel whose content is supplied by "panel.html" and -adds a content script "panel-script.js" to it -* sends the panel a "show" message when it is shown -* attaches the panel to a widget - - - - // main.js - var data = require("sdk/self").data; - - var forecast_panel = require("sdk/panel").Panel({ - height: 50, - contentURL: data.url("panel.html"), - contentScriptFile: data.url("panel-script.js") - }); - - forecast_panel.on("show", function(){ - forecast_panel.port.emit("show"); - }); - - require("sdk/widget").Widget({ - id: "forecast", - label: "Weather Forecast", - contentURL: "http://www.metoffice.gov.uk/favicon.ico", - panel: forecast_panel - }); - -The "panel.html" just includes a `
` block for the forecast: - -
-<!doctype HTML>
-<!-- panel.html -->
-
-<html>
-  <head></head>
-  <body>
-    <div id="forecast_summary"></div>
-  </body>
-</html>
-
- -The "panel-script.js" uses [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest) -to fetch the latest forecast: - - // panel-script.js - - var url = "http://datapoint.metoffice.gov.uk/public/data/txt/wxfcs/regionalforecast/json/500?key=YOUR-API-KEY"; - - self.port.on("show", function () { - var request = new XMLHttpRequest(); - request.open("GET", url, true); - request.onload = function () { - var jsonResponse = JSON.parse(request.responseText); - var summary = getSummary(jsonResponse); - var element = document.getElementById("forecast_summary"); - element.textContent = summary; - }; - request.send(); - }); - - function getSummary(forecast) { - return forecast.RegionalFcst.FcstPeriods.Period[0].Paragraph[0].$; - } - - -Finally, we need to add the `"cross-domain-content"` key to "package.json": - -
-"permissions": {
-  "cross-domain-content": ["http://datapoint.metoffice.gov.uk"]
-}
-
- -## Content Permissions and unsafeWindow ## - -If you use `"cross-domain-content"`, then JavaScript values in content -scripts will not be available from pages. Suppose your content script includes -a line like: - - // content-script.js: - unsafeWindow.myCustomAPI = function () {}; - -If you have included the `"cross-domain-content"` key, when the page script -tries to access `myCustomAPI` this will result in a "permission denied" -exception. diff --git a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/index.md b/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/index.md deleted file mode 100644 index 8dd377ff69a7..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/index.md +++ /dev/null @@ -1,98 +0,0 @@ - - -# Content Scripts # - -Almost all interesting add-ons will need to interact with web content or the -browser's user interface. For example, they may need to access and modify the -content of web pages or be notified when the user clicks a link. - -The SDK provides several core modules to support this: - -**[context-menu](modules/sdk/context-menu.html)**
-Add items to the browser's context menu. - -**[panel](modules/sdk/panel.html)**
-Create a dialog that can host web content. - -**[page-worker](modules/sdk/page-worker.html)**
-Retrieve a page and access its content, without displaying it to the user. - -**[page-mod](modules/sdk/page-mod.html)**
-Execute scripts in the context of selected web pages. - -**[tabs](modules/sdk/tabs.html)**
-Manipulate the browser's tabs, including the web content displayed in the tab. - -**[widget](modules/sdk/widget.html)**
-Host an add-on's user interface, including web content. - -Firefox is moving towards a model in which it uses separate -processes to display the UI, handle web content, and execute add-ons. The main -add-on code will run in the add-on process and will not have direct access to -any web content. - -This means that an add-on which needs to interact with web content needs to be -structured in two parts: - -* the main script runs in the add-on process -* any code that needs to interact with web content is loaded into the web -content process as a separate script. These separate scripts are called -_content scripts_. - -A single add-on may use multiple content scripts, and content scripts loaded -into the same context can interact directly with each other as well as with -the web content itself. See the chapter on - -communicating with other scripts. - -The add-on script and content script can't directly access each other's state. -Instead, you can define your own events which each side can emit, and the -other side can register listeners to handle them. The interfaces are similar -to the event-handling interfaces described in the -[Working with Events](dev-guide/guides/events.html) guide. - -The diagram below shows an overview of the main components and their -relationships. The gray fill represents code written by the add-on developer. - - - -This might sound complicated but it doesn't need to be. The following add-on -uses the [page-mod](modules/sdk/page-mod.html) module to replace the -content of any web page in the `.co.uk` domain by executing a content script -in the context of that page: - - var pageMod = require("sdk/page-mod"); - - pageMod.PageMod({ - include: ["*.co.uk"], - contentScript: 'document.body.innerHTML = ' + - '"

this page has been eaten

";' - }); - -In this example the content script is supplied directly to the page mod via -the `contentScript` option in its constructor, and does not need to be -maintained as a separate file at all. - -The next few chapters explain content scripts in detail: - -* [Loading Content Scripts](dev-guide/guides/content-scripts/loading.html): -how to attach content scripts to web pages, and how to control the point at -which they are executed -* [Accessing the DOM](dev-guide/guides/content-scripts/accessing-the-dom.html): -detail about the access content scripts get to the DOM -* [Communicating With Other Scripts](dev-guide/guides/content-scripts/communicating-with-other-scripts.html): -detail about how content scripts can communicate with "main.js", with other -content scripts, and with scripts loaded by the web page itself -* [Communicating Using port](dev-guide/guides/content-scripts/using-port.html): -how to communicate between your add-on and its content scripts using the -port object -* [Communicating using postMessage()](dev-guide/guides/content-scripts/using-postmessage.html): -how to communicate between your add-on and its content scripts using the -postMessage() API -* [Cross-domain Content Scripts](dev-guide/guides/content-scripts/cross-domain.html): -how to enable a content script to interact with content served from other domains. -* [Example](dev-guide/guides/content-scripts/reddit-example.html): -a simple example add-on using content scripts diff --git a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/loading.md b/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/loading.md deleted file mode 100644 index ced006555d1f..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/loading.md +++ /dev/null @@ -1,79 +0,0 @@ - - - -# Loading Content Scripts # - -The constructors for content-script-using objects such as panel and page-mod -define a group of options for loading content scripts: - -
-  contentScript         string, array
-  contentScriptFile     string, array
-  contentScriptWhen     string
-  contentScriptOptions  object
-
- -We have already seen the `contentScript` option, which enables you to pass -in the text of the script itself as a string literal. This version of the API -avoids the need to maintain a separate file for the content script. - -The `contentScriptFile` option enables you to pass in the local file URL from -which the content script will be loaded. To supply the file -"my-content-script.js", located in the /data subdirectory under your add-on's -root directory, use a line like: - - // "data" is supplied by the "self" module - var data = require("sdk/self").data; - ... - contentScriptFile: data.url("my-content-script.js") - -Both `contentScript` and `contentScriptFile` accept an array of strings, so you -can load multiple scripts, which can also interact directly with each other in -the content process: - - // "data" is supplied by the "self" module - var data = require("sdk/self").data; - ... - contentScriptFile: - [data.url("jquery-1.4.2.min.js"), data.url("my-content-script.js")] - -Scripts specified using contentScriptFile are loaded before those specified -using contentScript. This enables you to load a JavaScript library like jQuery -by URL, then pass in a simple script inline that can use jQuery. - -
-

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.

-
- -The `contentScriptWhen` option specifies when the content script(s) should be -loaded. It takes one of three possible values: - -* "start" loads the scripts immediately after the document element for the -page is inserted into the DOM. At this point the DOM content hasn't been -loaded yet, so the script won't be able to interact with it. - -* "ready" loads the scripts after the DOM for the page has been loaded: that -is, at the point the -[DOMContentLoaded](https://developer.mozilla.org/en/Gecko-Specific_DOM_Events) -event fires. At this point, content scripts are able to interact with the DOM -content, but externally-referenced stylesheets and images may not have finished -loading. - -* "end" loads the scripts after all content (DOM, JS, CSS, images) for the page -has been loaded, at the time the -[window.onload event](https://developer.mozilla.org/en/DOM/window.onload) -fires. - -The default value is "end". - -The `contentScriptOptions` is a json that is exposed to content scripts as a read -only value under `self.options` property. - -Any kind of jsonable value (object, array, string, etc.) can be used here. diff --git a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/reddit-example.md b/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/reddit-example.md deleted file mode 100644 index 067034ef1870..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/reddit-example.md +++ /dev/null @@ -1,71 +0,0 @@ - - -# Reddit Example # - -This example add-on creates a panel containing the mobile version of Reddit. -When the user clicks on the title of a story in the panel, the add-on opens -the linked story in a new tab in the main browser window. - -To accomplish this the add-on needs to run a content script in the context of -the Reddit page which intercepts mouse clicks on each title link and fetches the -link's target URL. The content script then needs to send the URL to the add-on -script. - -This is the complete add-on script: - - var data = require("sdk/self").data; - - var reddit_panel = require("sdk/panel").Panel({ - width: 240, - height: 320, - contentURL: "http://www.reddit.com/.mobile?keep_extension=True", - contentScriptFile: [data.url("jquery-1.4.4.min.js"), - data.url("panel.js")] - }); - - reddit_panel.port.on("click", function(url) { - require("sdk/tabs").open(url); - }); - - require("sdk/widget").Widget({ - id: "open-reddit-btn", - label: "Reddit", - contentURL: "http://www.reddit.com/static/favicon.ico", - panel: reddit_panel - }); - -This code supplies two content scripts to the panel's constructor in the -`contentScriptFile` option: the jQuery library and the script that intercepts -link clicks. - -Finally, it registers a listener to the user-defined `click` event which in -turn passes the URL into the `open` function of the -[tabs](modules/sdk/tabs.html) module. - -This is the `panel.js` content script that intercepts link clicks: - - $(window).click(function (event) { - var t = event.target; - - // Don't intercept the click if it isn't on a link. - if (t.nodeName != "A") - return; - - // Don't intercept the click if it was on one of the links in the header - // or next/previous footer, since those links should load in the panel itself. - if ($(t).parents('#header').length || $(t).parents('.nextprev').length) - return; - - // Intercept the click, passing it to the addon, which will load it in a tab. - event.stopPropagation(); - event.preventDefault(); - self.port.emit('click', t.toString()); - }); - -This script uses jQuery to interact with the DOM of the page and the -`self.port.emit` function to pass URLs back to the add-on script. - -See the `examples/reddit-panel` directory for the complete example (including -the content script containing jQuery). diff --git a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/using-port.md b/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/using-port.md deleted file mode 100644 index 07d3df57d96b..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/using-port.md +++ /dev/null @@ -1,292 +0,0 @@ - - - -# Communicating using "port" # - -To enable add-on scripts and content scripts to communicate with each other, -each end of the conversation has access to a `port` object. - -* to send messages from one side to the other, use `port.emit()` -* to receive messages sent from the other side, use `port.on()` - - - -Messages are asynchronous: that is, the sender does not wait for a reply from -the recipient but just emits the message and continues processing. - -Here's a simple add-on that sends a message to a content script using `port`: - - var tabs = require("sdk/tabs"); - - var alertContentScript = "self.port.on('alert', function(message) {" + - " window.alert(message);" + - "})"; - - tabs.on("ready", function(tab) { - worker = tab.attach({ - contentScript: alertContentScript - }); - worker.port.emit("alert", "Message from the add-on"); - }); - - tabs.open("http://www.mozilla.org"); - -In total, the `port` object defines four functions: - -* [`emit()`](dev-guide/guides/content-scripts/using-port.html#port.emit()): -emit a message. -* [`on()`](dev-guide/guides/content-scripts/using-port.html#port.on()): -listen to a message. -* [`removeListener()`](dev-guide/guides/content-scripts/using-port.html#port.removeListener()): -stop listening to a message. -* [`once()`](dev-guide/guides/content-scripts/using-port.html#port.once()): -listen to only the first occurrence of a message. - -## Accessing `port` ## - -### Accessing `port` in the Content Script ### - -Note that the global `self` object is completely -different from the [`self` module](modules/sdk/self.html), which -provides an API for an add-on to access its data files and ID. - -In the content script the `port` object is available as a property of the -global `self` object. Thus, to emit a message from a content script: - - self.port.emit("myContentScriptMessage", myContentScriptMessagePayload); - -To receive a message from the add-on code: - - self.port.on("myAddonMessage", function(myAddonMessagePayload) { - // Handle the message - }); - -Compare this to the technique used to receive _built-in_ messages in the -content script. For example, to receive the `context` message in a content script -associated with a [context menu](modules/sdk/context-menu.html) -object, you would call the `on` function attached to the global `self` object: - - self.on("context", function() { - // Handle the message - }); - -So the `port` property is essentially used here as a namespace for -user-defined messages. - -### Accessing `port` in the Add-on Script ### - -In the add-on code, the channel of communication between the add-on and a -particular content script context is encapsulated by the -[`worker`](modules/sdk/content/worker.html#Worker) object. Thus -the `port` object for communicating with a content script is a property of the -corresponding `worker` object. - -However, the worker is not exposed to add-on code in quite the same way -in all modules. The `panel` and `page-worker` objects integrate the -worker API directly. So to receive messages from a content script associated -with a panel you use `panel.port.on()`: - - var panel = require("sdk/panel").Panel({ - contentScript: "self.port.emit('showing', 'panel is showing');" - }); - - panel.port.on("showing", function(text) { - console.log(text); - }); - - panel.show(); - -Conversely, to emit user-defined messages from your add-on you can just call -`panel.port.emit()`: - - var panel = require("sdk/panel").Panel({ - contentScript: "self.port.on('alert', function(text) {" + - " console.log(text);" + - "});" - }); - - panel.show(); - panel.port.emit("alert", "panel is showing"); - -The `panel` and `page-worker` objects only host a single page at a time, -so each distinct page object only needs a single channel of communication -to its content scripts. But some modules, such as `page-mod`, might need to -handle multiple pages, each with its own context in which the content scripts -are executing, so it needs a separate channel (worker) for each page. - -So `page-mod` does not integrate the worker API directly: instead, each time a -content script is attached to a page, the -[worker](modules/sdk/content/worker.html#Worker) associated with the page is -supplied to the page-mod in its `onAttach` function. By supplying a target for -this function in the page-mod's constructor you can register to receive -messages from the content script, and take a reference to the worker so as to -emit messages to the content script. - - var pageModScript = "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);" + - "});" - - var pageMod = require('sdk/page-mod').PageMod({ - include: ['*'], - contentScript: pageModScript, - onAttach: function(worker) { - worker.port.on('click', function(html) { - worker.port.emit('warning', 'Do not click this again'); - }); - } - }); - -In the add-on above there are two user-defined messages: - -* `click` is sent from the page-mod to the add-on, when the user clicks an -element in the page -* `warning` sends a silly string back to the page-mod - -## port.emit() ## - -The `port.emit()` function sends a message from the "main.js", or another -add-on module, to a content script, or vice versa. - -It may be called with any number of parameters, but is most likely to be -called with a name for the message and an optional payload. -The payload can be any value that is -serializable to JSON. - -From the content script to the main add-on code: - - var myMessagePayload = "some data"; - self.port.emit("myMessage", myMessagePayload); - -From the main add-on code (in this case a panel instance) -to the content script: - - var myMessagePayload = "some data"; - panel.port.emit("myMessage", myMessagePayload); - -## port.on() ## - -The `port.on()` function registers a function as a listener for a specific -named message sent from the other side using `port.emit()`. - -It takes two parameters: the name of the message and a function to handle it. - -In a content script, to listen for "myMessage" sent from the main -add-on code: - - self.port.on("myMessage", function handleMyMessage(myMessagePayload) { - // Handle the message - }); - -In the main add-on code (in this case a panel instance), to listen for -"myMessage" sent from a a content script: - - panel.port.on("myMessage", function handleMyMessage(myMessagePayload) { - // Handle the message - }); - -## port.removeListener() ## - -You can uses `port.on()` to listen for messages. To stop listening for a -particular message, use `port.removeListener()`. This takes the -same two parameters as `port.on()`: the name of the message, and the name -of the listener function. - -For example, here's an add-on that creates a page-worker and a widget. -The page-worker loads -[http://en.wikipedia.org/wiki/Chalk](http://en.wikipedia.org/wiki/Chalk) -alongside a content script "listener.js". The widget sends the content script -a message called "get-first-para" when it is clicked: - - pageWorker = require("sdk/page-worker").Page({ - contentScriptFile: require("sdk/self").data.url("listener.js"), - contentURL: "http://en.wikipedia.org/wiki/Chalk" - }); - - require("sdk/widget").Widget({ - id: "mozilla-icon", - label: "My Mozilla Widget", - contentURL: "http://www.mozilla.org/favicon.ico", - onClick: function() { - console.log("sending 'get-first-para'"); - pageWorker.port.emit("get-first-para"); - } - }); - -The content script "listener.js" listens for "get-first-para". When it -receives this message, the script logs the first paragraph of the document -and then calls `removeListener()` to stop listening. - - function getFirstParagraph() { - var paras = document.getElementsByTagName('p'); - console.log(paras[0].textContent); - self.port.removeListener("get-first-para", getFirstParagraph); - } - - self.port.on("get-first-para", getFirstParagraph); - -The result is that the paragraph is only logged the first time the widget -is clicked. - -Due to [bug 816272](https://bugzilla.mozilla.org/show_bug.cgi?id=816272) -the [`page-mod`](modules/sdk/page-mod.html)'s `removeListener()` function -does not prevent the listener from receiving messages that are already queued. -This means that if "main.js" sends the message twice in successive lines, and -the listener stops listening as soon as it receives the first message, then -the listener will still receive the second message. - -## port.once() ## - -Often you'll want to receive a message just once, then stop listening. The -`port` object offers a shortcut to do this: the `once()` method. - -This example rewrites the "listener.js" content script in the -[`port.removeListener()` example](dev-guide/guides/content-scripts/using-port.html#port.removeListener()) -so that it uses `once()`: - - function getFirstParagraph() { - var paras = document.getElementsByTagName('p'); - console.log(paras[0].textContent); - } - - self.port.once("get-first-para", getFirstParagraph); - -## JSON-Serializable Values ## - -The payload for an message can be any JSON-serializable value. When messages -are sent their payloads are automatically serialized, and when messages are -received their payloads are automatically deserialized, so you don't need to -worry about serialization. - -However, you _do_ have to ensure that the payload can be serialized to JSON. -This means that it needs to be a string, number, boolean, null, array of -JSON-serializable values, or an object whose property values are themselves -JSON-serializable. This means you can't send functions, and if the object -contains methods they won't be encoded. - -For example, to include an array of strings in the payload: - - var pageModScript = "self.port.emit('loaded'," + - " [" + - " document.location.toString()," + - " document.title" + - " ]" + - ");" - - var pageMod = require('page-mod').PageMod({ - include: ['*'], - contentScript: pageModScript, - onAttach: function(worker) { - worker.port.on('loaded', function(pageInfo) { - console.log(pageInfo[0]); - console.log(pageInfo[1]); - }); - } - }); diff --git a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/using-postmessage.md b/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/using-postmessage.md deleted file mode 100644 index c15968403b99..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/content-scripts/using-postmessage.md +++ /dev/null @@ -1,140 +0,0 @@ - - -# Communicating using "postMessage()" # - -As an alternative to user-defined events content modules support the built-in -`message` event. In most cases user-defined events are preferable to message -events. However, the `context-menu` module does not support user-defined -events, so to send messages from a content script to the add-on via a context -menu object, you must use message events. - -## Handling Message Events in the Content Script ## - -To send a message from a content script, you use the `postMessage` function of -the global `self` object: - - self.postMessage(contentScriptMessage); - -This takes a single parameter, the message payload, which may be any -JSON-serializable value. - -To receive a message from the add-on script, use `self`'s `on` function: - - self.on("message", function(addonMessage) { - // Handle the message - }); - -Like all event-registration functions, this takes two parameters: the name -of the event, and the handler function. The handler function is passed the -message payload. - -## Handling Message Events in the Add-on Script ## - -To send a message to a content script, use the worker's `postMessage` -function. Again, `panel` and `page` integrate `worker` directly: - - // Post a message to the panel's content scripts - panel.postMessage(addonMessage); - -However, for `page-mod` objects you need to listen to the `onAttach` event -and use the [worker](modules/sdk/content/worker.html#Worker) supplied to that: - - var pageMod = require('sdk/page-mod').PageMod({ - include: ['*'], - contentScript: pageModScript, - onAttach: function(worker) { - worker.postMessage(addonMessage); - } - }); - -To receive messages from a content script, use the worker's `on` function. -To simplify this most content modules provide an `onMessage` property as an -argument to the constructor: - - panel = require("sdk/panel").Panel({ - onMessage: function(contentScriptMessage) { - // Handle message from the content script - } - }); - -## Message Events Versus User-Defined Events ## - -You can use message events as an alternative to user-defined events: - - var pageModScript = "window.addEventListener('mouseover', function(event) {" + - " self.postMessage(event.target.toString());" + - "}, false);"; - - var pageMod = require('sdk/page-mod').PageMod({ - include: ['*'], - contentScript: pageModScript, - onAttach: function(worker) { - worker.on('message', function(message) { - console.log('mouseover: ' + message); - }); - } - }); - -The reason to prefer user-defined events is that as soon as you need to send -more than one type of message, then both sending and receiving messages gets -more complex. - -Suppose the content script wants to send `mouseout` events as well as -`mouseover`. Now we have to embed the event type in the message payload, and -implement a switch function in the receiver to dispatch the message: - - var pageModScript = "window.addEventListener('mouseover', function(event) {" + - " self.postMessage({" + - " kind: 'mouseover'," + - " element: event.target.toString()" + - " });" + - "}, false);" + - "window.addEventListener('mouseout', function(event) {" + - " self.postMessage({" + - " kind: 'mouseout'," + - " element: event.target.toString()" + - " });" + - " }, false);" - - - var pageMod = require('sdk/page-mod').PageMod({ - include: ['*'], - contentScript: pageModScript, - onAttach: function(worker) { - worker.on('message', function(message) { - switch(message.kind) { - case 'mouseover': - console.log('mouseover: ' + message.element); - break; - case 'mouseout': - console.log('mouseout: ' + message.element); - break; - } - }); - } - }); - -Implementing the same add-on with user-defined events is shorter and more -readable: - - var pageModScript = "window.addEventListener('mouseover', function(event) {" + - " self.port.emit('mouseover', event.target.toString());" + - "}, false);" + - "window.addEventListener('mouseout', function(event) {" + - " self.port.emit('mouseout', event.target.toString());" + - "}, false);"; - - var pageMod = require('sdk/page-mod').PageMod({ - include: ['*'], - contentScript: pageModScript, - onAttach: function(worker) { - worker.port.on('mouseover', function(message) { - console.log('mouseover :' + message); - }); - worker.port.on('mouseout', function(message) { - console.log('mouseout :' + message); - }); - } - }); diff --git a/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/classes-and-inheritance.md b/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/classes-and-inheritance.md deleted file mode 100644 index f4a8f4776e6a..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/classes-and-inheritance.md +++ /dev/null @@ -1,272 +0,0 @@ - - -#Classes and Inheritance -A class is a blueprint from which individual objects are created. These -individual objects are the instances of the class. Each class defines one or -more members, which are initialized to a given value when the class is -instantiated. Data members are properties that allow each instance to have -their own state, whereas member functions are properties that allow instances to -have behavior. Inheritance allows classes to inherit state and behavior from an -existing classes, known as the base class. Unlike languages like C++ and Java, -JavaScript does not have native support for classical inheritance. Instead, it -uses something called prototypal inheritance. As it turns out, it is possible to -emulate classical inheritance using prototypal inheritance, but not without -writing a significant amount of boilerplate code. - -Classes in JavaScript are defined using constructor functions. Each constructor -function has an associated object, known as its prototype, which is shared -between all instances of that class. We will show how to define classes using -constructors, and how to use prototypes to efficiently define member functions -on each instance. Classical inheritance can be implemented in JavaScript using -constructors and prototypes. We will show how to make inheritance work correctly -with respect to constructors, prototypes, and the instanceof operator, and how -to override methods in subclasses. The SDK uses a special constructor internally, -known as `Class`, to create constructors that behave properly with respect to -inheritance. The last section shows how to work with the `Class` constructor. It -is possible to read this section on its own. However, to fully appreciate how -`Class` works, and the problem it is supposed to solve, it is recommended that -you read the entire article. - -##Constructors -In JavaScript, a class is defined by defining a constructor function for that -class. To illustrate this, let's define a simple constructor for a class -`Shape`: - - function Shape(x, y) { - this.x = x; - this.y = y; - } - -We can now use this constructor to create instances of `Shape`: - - let shape = new Shape(2, 3); - shape instanceof Shape; // => true - shape.x; // => 2 - shape.y; // => 3 - -The keyword new tells JavaScript that we are performing a constructor call. -Constructor calls differ from ordinary function calls in that JavaScript -automatically creates a new object and binds it to the keyword this for the -duration of the call. Moreover, if the constructor does not return a value, the -result of the call defaults to the value of this. Constructors are just ordinary -functions, however, so it is perfectly legal to perform ordinary function calls -on them. In fact, some people (including the Add-on SDK team) prefer to use -constructors this way. However, since the value of this is undefined for -ordinary function calls, we need to add some boilerplate code to convert them to -constructor calls: - - function Shape(x, y) { - if (!this) - return new Shape(x, y); - this.x = x; - this.y = y; - } - -##Prototypes -Every object has an implicit property, known as its prototype. When JavaScript -looks for a property, it first looks for it in the object itself. If it cannot -find the property there, it looks for it in the object's prototype. If the -property is found on the prototype, the lookup succeeds, and JavaScript pretends -that it found the property on the original object. Every function has an -explicit property, known as `prototype`. When a function is used in a -constructor call, JavaScript makes the value of this property the prototype of -the newly created object: - - let shape = Shape(2, 3); - Object.getPrototypeOf(shape) == Shape.prototype; // => true - -All instances of a class have the same prototype. This makes the prototype the -perfect place to define properties that are shared between instances of the -class. To illustrate this, let's add a member function to the class `Shape`: - - Shape.prototype.draw = function () { - throw Error("not yet implemented"); - } - let shape = Shape(2, 3); - Shape.draw(); // => Error: not yet implemented - -##Inheritance and Constructors -Suppose we want to create a new class, `Circle`, and inherit it from `Shape`. -Since every `Circle` is also a `Shape`, the constructor for `Circle` must be -called every time we call the constructor for `Shape`. Since JavaScript does -not have native support for inheritance, it doesn't do this automatically. -Instead, we need to call the constructor for `Shape` explicitly. The resulting -constructor looks as follows: - - function Circle(x, y, radius) { - if (!this) - return new Circle(x, y, radius); - Shape.call(this, x, y); - this.radius = radius; - } - -Note that the constructor for `Shape` is called as an ordinary function, and -reuses the object created for the constructor call to `Circle`. Had we used a -constructor call instead, the constructor for `Shape` would have been applied to -a different object than the constructor for `Circle`. We can now use the above -constructor to create instances of the class `Circle`: - - let circle = Circle(2, 3, 5); - circle instanceof Circle; // => true - circle.x; // => 2 - circle.y; // => 3 - circle.radius; // => 5 - -##Inheritance and Prototypes -There is a problem with the definition of `Circle` in the previous section that -we have glossed over thus far. Consider the following: - - let circle = Circle(2, 3, 5); - circle.draw(); // => TypeError: circle.draw is not a function - -This is not quite right. The method `draw` is defined on instances of `Shape`, -so we definitely want it to be defined on instances of `Circle`. The problem is -that `draw` is defined on the prototype of `Shape`, but not on the prototype of -`Circle`. We could of course copy every property from the prototype of `Shape` -over to the prototype of `Circle`, but this is needlessly inefficient. Instead, -we use a clever trick, based on the observation that prototypes are ordinary -objects. Since prototypes are objects, they have a prototype as well. We can -thus override the prototype of `Circle` with an object which prototype is the -prototype of `Shape`. - - Circle.prototype = Object.create(Shape.prototype); - -Now when JavaScript looks for the method draw on an instance of Circle, it first -looks for it on the object itself. When it cannot find the property there, it -looks for it on the prototype of `Circle`. When it cannot find the property -there either, it looks for it on `Shape`, at which point the lookup succeeds. -The resulting behavior is what we were aiming for. - -##Inheritance and Instanceof -The single line of code we added in the previous section solved the problem with -prototypes, but introduced a new problem with the **instanceof** operator. -Consider the following: - - let circle = Circle(2, 3, 5); - circle instanceof Shape; // => false - -Since instances of `Circle` inherit from `Shape`, we definitely want the result -of this expression to be true. To understand why it is not, we need to -understand how **instanceof** works. Every prototype has a `constructor` -property, which is a reference to the constructor for objects with this -prototype. In other words: - - Circle.prototype.constructor == Circle // => true - -The **instanceof** operator compares the `constructor` property of the prototype -of the left hand side with that of the right hand side, and returns true if they -are equal. Otherwise, it repeats the comparison for the prototype of the right -hand side, and so on, until either it returns **true**, or the prototype becomes -**null**, in which case it returns **false**. The problem is that when we -overrode the prototype of `Circle` with an object whose prototype is the -prototype of `Shape`, we didn't correctly set its `constructor` property. This -property is set automatically for the `prototype` property of a constructor, but -not for objects created with `Object.create`. The `constructor` property is -supposed to be non-configurable, non-enumberable, and non-writable, so the -correct way to define it is as follows: - - Circle.prototype = Object.create(Shape.prototype, { - constructor: { - value: Circle - } - }); - -##Overriding Methods -As a final example, we show how to override the stub implementation of the -method `draw` in `Shape` with a more specialized one in `Circle`. Recall that -JavaScript returns the first property it finds when walking the prototype chain -of an object from the bottom up. Consequently, overriding a method is as simple -as providing a new definition on the prototype of the subclass: - - Circle.prototype.draw = function (ctx) { - ctx.beginPath(); - ctx.arc(this.x, this.y, this.radius, - 0, 2 * Math.PI, false); - ctx.fill(); - }; - -With this definition in place, we get: - - let shape = Shape(2, 3); - shape.draw(); // Error: not yet implemented - let circle = Circle(2, 3, 5); - circle.draw(); // TypeError: ctx is not defined - -which is the behavior we were aiming for. - -##Classes in the Add-on SDK -We have shown how to emulate classical inheritance in JavaScript using -constructors and prototypes. However, as we have seen, this takes a significant -amount of boilerplate code. The Add-on SDK team consists of highly trained -professionals, but they are also lazy: that is why the SDK contains a helper -function that handles this boilerplate code for us. It is defined in the module -“core/heritage”: - - const { Class } = require('sdk/core/heritage'); - -The function `Class` is a meta-constructor: it creates constructors that behave -properly with respect to inheritance. It takes a single argument, which is an -object which properties will be defined on the prototype of the resulting -constructor. The semantics of `Class` are based on what we've learned earlier. -For instance, to define a constructor for a class `Shape` in terms of `Class`, -we can write: - - let Shape = Class({ - initialize: function (x, y) { - this.x = x; - this.y = y; - }, - draw: function () { - throw new Error("not yet implemented"); - } - }); - -The property `initialize` is special. When it is present, the call to the -constructor is forwarded to it, as are any arguments passed to it (including the -this object). In effect, initialize specifies the body of the constructor. Note -that the constructors created with `Class` automatically check whether they are -called as constructors, so an explicit check is no longer necessary. - -Another special property is `extends`. It specifies the base class from which -this class inherits, if any. `Class` uses this information to automatically set -up the prototype chain of the constructor. If the extends property is omitted, -`Class` itself is used as the base class: - - var shape = new Shape(2, 3); - shape instanceof Shape; // => true - shape instanceof Class; // => true - -To illustrate the use of the `extends` property, let's redefine the constructor -for the class `Circle` in terms of `Class`: - - var Circle = Class({ - extends: Shape, - initialize: function(x, y, radius) { - Shape.prototype.initialize.call(this, x, y); - this.radius = radius; - }, - draw: function () { - context.beginPath(); - context.arc(this.x, this.y, this.radius, - 0, 2 * Math.PI, false); - context.fill(); - } - }); - -Unlike the definition of `Circle` in the previous section, we no longer have to -override its prototype, or set its `constructor` property. This is all handled -automatically. On the other hand, the call to the constructor for `Shape` still -has to be made explicitly. This is done by forwarding to the initialize method -of the prototype of the base class. Note that this is always safe, even if there -is no `initialize` method defined on the base class: in that case the call is -forwarded to a stub implementation defined on `Class` itself. - -The last special property we will look into is `implements`. It specifies a list -of objects, which properties are to be copied to the prototype of the -constructor. Note that only properties defined on the object itself are copied: -properties defined on one of its prototypes are not. This allows objects to -inherit from more than one class. It is not true multiple inheritance, however: -no constructors are called for objects inherited via `implements`, and -**instanceof** only works correctly for classes inherited via `extends`. diff --git a/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/content-processes.md b/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/content-processes.md deleted file mode 100644 index f77d921a85fe..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/content-processes.md +++ /dev/null @@ -1,149 +0,0 @@ - - -#Content Processes -A content process was supposed to run all the code associated with a single tab. -Conversely, an add-on process was supposed to run all the code associated with a -single add-on. Neither content or add-on proceses were ever actually -implemented, but by the time they were cancelled, the SDK was already designed -with them in mind. To understand this article, it's probably best to read it as -if content and add-on processes actually exist. - -To communicate between add-on and content processes, the SDK uses something -called content scripts. These are explained in the first section. Content -scripts communicate with add-on code using something called event emitters. -These are explained in the next section. Content workers combine these ideas, -allowing you to inject a content script into a content process, and -automatically set up a communication channel between them. These are explained -in the third section. - -In the next section, we will look at how content scripts interact with the DOM -in a content process. There are several caveats here, all of them related to -security, that might cause things to not behave in the way you might expect. - -The final section explains why the SDK still uses the notion of content scripts -and message passing, even though the multiprocess model for which they were -designed never materialized. This, too, is primarily related to security. - -##Content Scripts -When the SDK was first designed, Firefox was being refactored towards a -multiprocess model. In this model, the UI would be rendered in one process -(called the chrome process), whereas each tab and each add-on would run in their -own dedicated process (called content and add-on processes, respectively). The -project behind this refactor was known as Electrolysis, or E10s. Although E10s -has now been suspended, the SDK was designed with this multiprocess model in -mind. Afterwards, it was decided to keep the design the way it is: even though -its no longer necessary, it turns out that from a security point of view there -are several important advantages to thinking about content and add-on code as -living in different processes. - -Many add-ons have to interact with content. The problem with the multiprocess -model is that add-ons and content are now in different processes, and scripts in -one process cannot interact directly with scripts in another. We can, however, -pass JSON messages between scripts in different processes. The solution we've -come up with is to introduce the notion of content scripts. A content script is -a script that is injected into a content process by the main script running in -the add-on process. Content scripts differ from scripts that are loaded by the -page itself in that they are provided with a messaging API that can be used to -send messages back to the add-on script. - -##Event Emitters -The messaging API we use to send JSON messages between scripts in different -processes is based on the use of event emitters. An event emitter maintains a -list of callbacks (or listeners) for one or more named events. Each event -emitter has several methods: the method on is used to add a listener for an -event. Conversely, the method removeListener is used to remove a listener for an -event. The method once is a helper function which adds a listener for an event, -and automatically removes it the first time it is called. - -Each event emitter has two associated emit functions. One emit function is -associated with the event emitter itself. When this function is called with a -given event name, it calls all the listeners currently associated with that -event. The other emit function is associated with another event emitter: it was -passed as an argument to the constructor of this event emitter, and made into a -method. Calling this method causes an event to be emitted on the other event -emitter. - -Suppose we have two event emitters in different processes, and we want them to -be able to emit events to each other. In this case, we would replace the emit -function passed to the constructor of each emitter with a function that sends a -message to the other process. We can then hook up a listener to be called when -this message arrives at the other process, which in turn calls the emit function -on the other event emitter. The combination of this function and the -corresponding listener is referred to as a pipe. - -##Content Workers -A content worker is an object that is used to inject content scripts into a -content process, and to provide a pipe between each content script and the main -add-on script. The idea is to use a single content worker for each content -process. The constructor for the content worker takes an object containing one -or more named options. Among other things, this allows us to specify one or more -content scripts to be loaded. - -When a content script is first loaded, the content worker automatically imports -a messaging API that allows the it to emit messages over a pipe. On the add-on -side, this pipe is exposed via the the port property on the worker. In addition -to the port property, workers also support the web worker API, which allows -scripts to send messages to each other using the postMessage function. This -function uses the same pipe internally, and causes a 'message' event to be -emitted on the other side. - -As explained earlier, Firefox doesn't yet use separate processes for tabs or -add-ons, so instead, each content script is loaded in a sandbox. Sandboxes were -explained [this article]("dev-guide/guides/contributors-guide/modules.html"). - -##Accessing the DOM -The global for the content sandbox has the window object as its prototype. This -allows the content script to access any property on the window object, even -though that object lives outside the sandbox. Recall that the window object -inside the sandbox is actually a wrapper to the real object. A potential -problem with the content script having access to the window object is that a -malicious page could override methods on the window object that it knows are -being used by the add-on, in order to trick the add-on into doing something it -does not expect. Similarly, if the content script defines any values on the -window object, a malicious page could potentially steal that information. - -To avoid problems like this, content scripts should always see the built-in -properties of the window object, even when they are overridden by another -script. Conversely, other scripts should not see any properties added to the -window object by the content script. This is where xray wrappers come in. Xray -wrappers automatically wrap native objects like the window object, and only -exposes their native properties, even if they have been overridden on the -wrapped object. Conversely, any properties defined on the wrapper are not -visible from the wrapped object. This avoids both problems we mentioned earlier. - -The fact that you can't override the properties of the window object via a -content script is sometimes inconvenient, so it is possible to circumvent this: -by defining the property on window.wrappedObject, the property is defined on the -underlying object, rather than the wrapper itself. This feature should only be -used when you really need it, however. - -##A few Notes on Security -As we stated earlier, the SDK was designed with multiprocess support in mind, -despite the fact that work on implementing this in Firefox has currently been -suspended. Since both add-on modules and content scripts are currently loaded in -sandboxes rather than separate processes, and sandboxes can communicate with -each other directly (using imports/exports), you might be wondering why we have -to go through all the trouble of passing messages between add-on and content -scripts. The reason for this extra complexity is that the code for add-on -modules and content scripts has different privileges. Every add-on module can -get chrome privileges simply by asking for them, whereas content scripts have -the same privileges as the page it is running on. - -When two sandboxes have the same privileges, a wrapper in one sandbox provides -transparent access to an object in the other sandbox. When the two sandboxes -have different privileges, things become more complicated, however. Code with -content privileges should not be able to acces code with chrome privileges, so -we use specialized wrappers, called security wrappers, to limit access to the -object in the other sandbox. The xray wrappers we saw earlier are an example of -such a security wrapper. Security wrappers are created automatically, by the -underlying host application. - -A full discussion of the different kinds of security wrappers and how they work -is out of scope for this document, but the main point is this: security wrappers -are very complex, and very error-prone. They are subject to change, in order to -fix some security leak that recently popped up. As a result, code that worked -just fine last week suddenly does not work the way you expect. By only passing -messages between add-on modules and content scripts, these problems can be -avoided, making your add-on both easier to debug and to maintain. diff --git a/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/getting-started.md b/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/getting-started.md deleted file mode 100644 index bdaa61a57cae..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/getting-started.md +++ /dev/null @@ -1,318 +0,0 @@ - - -#Getting Started -The contribution process consists of a number of steps. First, you need to get -a copy of the code. Next, you need to open a bug for the bug or feature you want -to work on, and assign it to yourself. Alternatively, you can take an existing -bug to work on. Once you've taken a bug, you can start writing a patch. Once -your patch is complete, you've made sure it doesn't break any tests, and you've -gotten a positive review for it, the last step is to request for your patch to -be merged with the main codebase. - -Although these individual steps are all obvious, there are quite some details -involved. The rest of this article will cover each individual step of the -contribution process in more detail. - -##Getting the Code -The Add-on SDK code is hosted on GitHub. GitHub is a web-based hosting service -for software projects that is based on Git, a distributed version control -system. Both GitHub and Git are an integral part of our workflow. If you haven't -familiarized yourself with Git before, I strongly suggest you do so now. You're -free to ignore that suggestion if you want, but it's going to hurt you later on -(don't come crying to me if you end up accidentally detaching your head, for -instance). A full explanation of how to use Git is out of scope for this -document, but a very good one -[can be found online here](http://git-scm.com/book). Reading at least sections -1-3 from that book should be enough to get you started. - -If you're already familiar with Git, or if you decided to ignore my advice and -jump right in, the following steps will get you a local copy of the Add-on SDK -code on your machine: - -1. Fork the SDK repository to your GitHub account -2. Clone the forked repository to your machine - -A fork is similar to a clone in that it creates a complete copy of a repository, -including the history of every file. The difference is that a fork copies the -repository to your GitHub account, whereas a clone copies it to your machine. To -create a fork of the SDK repository, you need a GitHub account. If you don't -already have one, you can [create one here](https://github.com/) (don't worry: -it's free!). Once you got yourself an account, go to -[the Add-on SDK repository](https://github.com/mozilla/addon-sdk), and click the -fork button in the upper-right corner. This will start the forking process. -This could take anywhere between a couple of seconds and a couple of minutes. - -Once the forking process is complete, the forked repository will be available at -https://github.com/\/addon-sdk. To create a clone of the this -repository, you need to have Git installed on your machine. If you don’t have it -already, you can [download it here](http://git-scm.com/). Once you have Git -installed (make sure you also configured your name and e-mail -address), open your terminal, and enter the following command from the directory -where you want to have the clone stored: - -> `git clone ssh://github.com//addon-sdk` - -This will start the cloning process. Like the forking process, this could take -anywhere between a couple of seconds and a couple of minutes, depending on the -speed of your connection. - -If you did everything correctly so far, once the cloning process is complete, -the cloned repository will have been stored inside the directory from which you -ran the clone command, in a new directory called addon-sdk. Now we can start -working with it. Yay! - -As a final note: it is possible to skip step 1, and clone the SDK repository -directly to your machine. This is useful if you only want to study the SDK code. -However, if your goal is to actually contribute to the SDK, skipping step 1 is a -bad idea, because you won’t be able to make pull requests in that case. - -##Opening a Bug -In any large software project, keeping track of bugs is crucially important. -Without it, developers wouldn't be able to answer questions such as: what do I -need to work on, who is working on what, etc. Mozilla uses its own web-based, -general-purpose bugtracker, called Bugzilla, to keep track of bugs. Like GitHub -and Git, Bugzilla is an integral part of our workflow. When you discover a new -bug, or want to implement a new feature, you start by creating an entry for it -in Bugzilla. By doing so, you give the SDK team a chance to confirm whether your -bug isn't actually a feature, or your feature isn't actually a bug -(that is, a feature we feel doesn't belong into the SDK). - -Within Bugzilla, the term _bug_ is often used interchangably to refer to both -bugs and features. Similarly, the Bugzilla entry for a bug is also named bug, -and the process of creating it is known as _opening a bug_. It is important that -you understand this terminology, as other people will regularly refer to it. - -I really urge you to open a bug first and wait for it to get confirmed before -you start working on something. Nothing sucks more than your patch getting -rejected because we felt it shouldn't go into the SDK. Having this discussion -first saves you from doing useless work. If you have questions about a bug, but -don't know who to ask (or the person you need to ask isn't online), Bugzilla is -the communication channel of choice. When you open a bug, the relevant people -are automatically put on the cc-list, so they will get an e-mail every time you -write a comment in the bug. - -To open a bug, you need a Bugzilla account. If you don't already have one, you -can [create it here](https://bugzilla.mozilla.org/). Once you got yourself an -account, click the "new" link in the upper-left corner. This will take you to a -page where you need to select the product that is affected by your bug. It isn't -immediately obvious what you should pick here (and with not immediately obvious -I mean completely non-obvious), so I'll just point it out to you: as you might -expect, the Add-on SDK is listed under "Other products", at the bottom of the -page. - -After selecting the Add-on SDK, you will be taken to another page, where you -need to fill out the details for the bug. The important fields are the component -affected by this bug, the summary, and a short description of the bug (don't -worry about coming up with the perfect description for your bug. If something is -not clear, someone from the SDK team will simply write a comment asking for -clarification). The other fields are optional, and you can leave them as is, if -you so desire. - -Note that when you fill out the summary field, Bugzilla automatically looks for -bugs that are possible duplicates of the one you're creating. If you spot such a -duplicate, there's no need to create another bug. In fact, doing so is -pointless, as duplicate bugs are almost always immediately closed. Don't worry -about accidentally opening a duplicate bug though. Doing so is not considered a -major offense (unless you do it on purpose, of course). - -After filling out the details for the bug, the final step is to click the -"Submit Bug" button at the bottom of the page. Once you click this button, the -bug will be stored in Bugzilla’s database, and the creation process is -completed. The initial status of your bug will be `UNCONFIRMED`. All you need to -do now is wait for someone from the SDK team to change the status to either -`NEW` or `WONTFIX`. - -##Taking a Bug -Since this is a contributor's guide, I've assumed until now that if you opened a -bug, you did so with the intention of fixing it. Simply because you're the one -that opened it doesn't mean you have to fix a bug, however. Conversely, simply -because you're _not_ the one that opened it doesn't mean you can't fix a bug. In -fact, you can work on any bug you like, provided nobody else is already working -on it. To check if somebody is already working on a bug, go to the entry for -that bug and check the "Assigned To" field. If it says "Nobody; OK to take it -and work on it", you're good to go: you can assign the bug to yourself by -clicking on "(take)" right next to it. - -Keep in mind that taking a bug to creates the expectation that you will work on -it. It's perfectly ok to take your time, but if this is the first bug you're -working on, you might want to make sure that this isn't something that has very -high priority for the SDK team. You can do so by checking the importance field -on the bug page (P1 is the highest priority). If you've assigned a bug to -yourself that looked easy at the time, but turns out to be too hard for you to -fix, don't feel bad! It happens to all of us. Just remove yourself as the -assignee for the bug, and write a comment explaining why you're no longer able -to work on it, so somebody else can take a shot at it. - -A word of warning: taking a bug that is already assigned to someone else is -considered extremely rude. Just imagine yourself working hard on a series of -patches, when suddenly this jerk comes out of nowhere and submits his own -patches for the bug. Not only is doing so an inefficient use of time, it also -shows a lack of respect for other the hard work of other contributors. The other -side of the coin is that contributors do get busy every now and then, so if you -stumble upon a bug that is already assigned to someone else but hasn't shown any -activity lately, chances are the person to which the bug is assigned will gladly -let you take it off his/her hands. The general rule is to always ask the person -assigned to the bug if it is ok for you to take it. - -As a final note, if you're not sure what bug to work on, or having a hard time -finding a bug you think you can handle, a useful tip is to search for the term -"good first bug". Bugs that are particularly easy, or are particularly well -suited to familiarize yourself with the SDK, are often given this label by the -SDK team when they're opened. - -##Writing a Patch -Once you've taken a bug, you're ready to start doing what you really want to do: -writing some code. The changes introduced by your code are known as a patch. -Your goal, of course, is to get this patch landed in the main SDK repository. In -case you aren't familiar with git, the following command will cause it to -generate a diff: - -> `git diff` - -A diff describes all the changes introduced by your patch. These changes are not -yet final, since they are not yet stored in the repository. Once your patch is -complete, you can _commit_ it to the repository by writing: - -> `git commit` - -After pressing enter, you will be prompted for a commit message. What goes in -the commit message is more or less up to you, but you should at least include -the bug number and a short summary (usually a single line) of what the patch -does. This makes it easier to find your commit later on. - -It is considered good manners to write your code in the same style as the rest -of a file. It doesn't really matter what coding style you use, as long as it's -consistent. The SDK might not always use the exact same coding style for each -file, but it strives to be as consistent as possible. Having said that: if -you're not completely sure what coding style to use, just pick something and -don't worry about it. If the rest of the file doesn't make it clear what you -should do, it most likely doesn't matter. - -##Making a Pull Request -To submit a patch for review, you need to make a pull request. Basically, a pull -request is a way of saying: "Hey, I've created this awesome patch on top of my -fork of the SDK repository, could you please merge it with the global -repository?". GitHub has built-in support for pull requests. However, you can -only make pull requests from repositories on your GitHub account, not from -repositories on your local machine. This is why I told you to fork the SDK -repository to your GitHub account first (you did listen to me, didn't you?). - -In the previous section, you commited your patch to your local repository, so -here, the next step is to synchronize your local repository with the remote one, -by writing: - -> `git push` - -This pushes the changes from your local repository into the remote repository. -As you might have guessed, a push is the opposite of a pull, where somebody else -pulls changes from a remote repository into their own repository (hence the term -'pull request'). After pressing enter, GitHub will prompt you for your username -and password before actually allowing the push. - -If you did everything correctly up until this point, your patch should now show -up in your remote repository (take a look at your repository on GitHub to make -sure). We're now ready to make a pull request. To do so, go to your repository -on GitHub and click the "Pull Request" button at the top of the page. This will -take you to a new page, where you need to fill out the title of your pull -request, as well as a short description of what the patch does. As we said -before, it is common practice to at least include the bug number and a short -summary in the title. After you've filled in both fields, click the "Send Pull -Request" button. - -That's it, we're done! Or are we? This is software development after all, so -we'd expect there to be at least one redundant step. Luckily, there is such a -step, because we also have to submit our patch for review on Bugzilla. I imagine -you might be wondering to yourself right now: "WHY???". Let me try to explain. -The reason we have this extra step is that most Mozilla projects use Mercurial -and Bugzilla as their version control and project management tool, respectively. -To stay consistent with the rest of Mozilla, we provide a Mercurial mirror of -our Git repository, and submit our patches for review in both GitHub and -Bugzilla. - -If that doesn't make any sense to you, that's ok: it doesn't to me, either. The -good news, however, is that you don't have to redo all the work you just did. -Normally, when you want to submit a patch for review on Bugzilla, you have to -create a diff for the patch and add it as an attachment to the bug (if you still -haven't opened one, this would be the time to do it). However, these changes are -also described by the commit of your patch, so its sufficient to attach a file -that links to the pull request. To find the link to your pull request, go to -your GitHub account and click the "Pull Requests" button at the top. This will -take you to a list of your active pull requests. You can use the template here -below as your attachment. Simply copy the link to your pull request, and use it -to replace all instances of \: - - - - - Bugzilla Code Review -

You can review this patch at , - or wait 5 seconds to be redirected there automatically.

- -Finally, to add the attachment to the bug, go to the bug in Bugzilla, and click -on "Add an attachment" right above the comments. Make sure you fill out a -description for the attachment, and to set the review flag to '?' (you can find -a list of reviewers on -[this page](https://github.com/mozilla/addon-sdk/wiki/contribute)). The '?' here -means that you're making a request. If your patch gets a positive review, the -reviewer will set this flag to '+'. Otherwise, he/she will set it to '-', with -some feedback on why your patch got rejected. Of course, since we also use -GitHub for our review process, you're most likely to get your feedback there, -instead of Bugzilla. If your patch didn't get a positive review right away, -don't sweat it. If you waited for your bug to get confirmed before submitting -your patch, you'll usually only have to change a few small things to get a -positive review for your next attempt. Once your patch gets a positive review, -you don't need to do anything else. Since you did a pull request, it will -automatically be merged into the remote repository, usually by the person that -reviewed your patch. - -##Getting Additional Help -If something in this article wasn't clear to you, or if you need additional -help, the best place to go is irc. Mozilla relies heavily on irc for direct -communication between contributors. The SDK team hangs out on the #jetpack -channel on the irc.mozilla.org server (Jetpack was the original name of the -SDK, in case you're wondering). - -Unless you are know what you are doing, it can be hard to get the information -you need from irc, uso here are a few useful tips: - -* Mozilla is a global organization, with contributors all over the world, so the - people you are trying to reach are likely not in the same timezone as you. - Most contributors to the SDK are currently based in the US, so if you're in - Europe, and asking a question on irc in the early afternoon, you're not likely - to get many replies. - -* Most members of the SDK team are also Mozilla employees, which means they're - often busy doing other stuff. That doesn't mean they don't want to help you. - On the contrary: Mozilla encourages employees to help out contributors - whenever they can. But it does mean that we're sometimes busy doing other - things than checking irc, so your question may go unnoticed. If that happens, - the best course of action is often to just ask again. - -* If you direct your question to a specific person, rather than the entire - channel, your chances of getting an answer are a lot better. If you prefix - your message with that person's irc name, he/she will get a notification in - his irc client. Try to make sure that the person you're asking is actually the - one you need, though. Don't just ask random questions to random persons in the - hopes you'll get more response that way. - -* If you're not familiar with irc, a common idiom is to send someone a message - saying "ping" to ask if that person is there. When that person actually shows - up and sees the ping, he will send you a message back saying "pong". Cute, - isn't it? But hey, it works. - -* Even if someone does end up answering your questions, it can happen that that - person gets distracted by some other task and forget he/she was talking to - you. Please don't take that as a sign we don't care about your questions. We - do, but we too get busy sometimes: we're only human. If you were talking to - somebody and haven't gotten any reply to your last message for some time, feel - free to just ask again. - -* If you've decided to pick up a good first bug, you can (in theory at least) - get someone from the SDK team to mentor you. A mentor is someone who is - already familiar with the code who can walk you through it, and who is your go - to guy in case you have any questions about it. The idea of mentoring was - introduced a while ago to make it easier for new contributors to familiarize - themselves with the code. Unfortunately, it hasn't really caught on yet, but - we're trying to change that. So by all means: ask! diff --git a/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/modules.md b/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/modules.md deleted file mode 100644 index fedfd5a69abb..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/modules.md +++ /dev/null @@ -1,316 +0,0 @@ - - -#Modules -A module is a self-contained unit of code, which is usually stored in a file, -and has a well defined interface. The use of modules greatly improves the -maintainability of code, by splitting it up into independent components, and -enforcing logical boundaries between them. Unfortunately, JavaScript does not -yet have native support for modules: it has to rely on the host application to -provide it with functionality such as loading subscripts, and exporting/ -importing names. We will show how to do each of these things using the built-in -Components object provided by Xulrunner application such as Firefox and -Thunderbird. - -To improve encapsulation, each module should be defined in the scope of its own -global object. This is made possible by the use of sandboxes. Each sandbox lives -in its own compartment. A compartment is a separate memory space. Each -compartment has a set of privileges that determines what scripts running in that -compartment can and cannot do. We will show how sandboxes and compartments can -be used to improve security in our module system. - -The module system used by the SDK is based on the CommonJS specification: it is -implemented using a loader object, which handles all the bookkeeping related to -module loading, such as resolving and caching URLs. We show how to create your -own custom loaders, using the `Loader` constructor provided by the SDK. The SDK -uses its own internal loader, known as Cuddlefish. All modules within the SDK -are loaded using Cuddlefish by default. Like any other custom loader, Cuddlefish -is created using the `Loader` constructor. In the final section, we will take a -look at some of the options passed by the SDK to the `Loader` constructor to -create the Cuddlefish loader. - -##Loading Subscripts -When a JavaScript project reaches a certain size, it becomes necessary to split -it up into multiple files. Unfortunately, JavaScript does not provide any means -to load scripts from other locations: we have to rely on the host application to -provide us with this functionality. Applications such as Firefox and Thunderbird -are based on Xulrunner. Xulrunner adds a built-in object, known as `Components`, -to the global scope. This object forms the central access point for all -functionality provided by the host application. A complete explanation of how to -use `Components` is out of scope for this document. However, the following -example shows how it can be used to load scripts from other locations: - - const { - classes: Cc - interfaces: Ci - } = Components; - - var instance = Cc["@mozilla.org/moz/jssubscript-loader;1"]; - var loader = instance.getService(Ci.mozIJSSubScriptLoader); - - function loadScript(url) { - loader.loadSubScript(url); - } - -When a script is loaded, it is evaluated in the scope of the global object of -the script that loaded it. Any property defined on the global object will be -accessible from both scripts: - - index.js: - loadScript("www.foo.com/a.js"); - foo; // => 3 - - a.js: - foo = 3; - -##Exporting Names -The script loader we obtained from the `Components` object allows us load -scripts from other locations, but its API is rather limited. For instance, it -does not know how to handle relative URLs, which is cumbersome if you want to -organize your project hierarchically. A more serious problem with the -`loadScript` function, however, is that it evaluates all scripts in the scope of -the same global object. This becomes a problem when two scripts try to define -the same property: - - index.js: - loadScript("www.foo.com/a.js"); - loadScript("www.foo.com/b.js"); - foo; // => 5 - - a.js: - foo = 3; - - b.js: - foo = 5; - -In the above example, the value of `foo` depends on the order in which the -subscripts are loaded: there is no way to access the property foo defined by -"a.js", since it is overwritten by "b.js". To prevent scripts from interfering -with each other, `loadScript` should evaluate each script to be loaded in the -scope of their own global object, and then return the global object as its -result. In effect, any properties defined by the script being loaded on its -global object are exported to the loading script. The script loader we obtained -from `Components` allows us to do just that: - - function loadScript(url) { - let global = {}; - loader.loadSubScript(url, global); - return global; - } - -If present, the `loadSubScript` function evaluates the script to be loaded in -the scope of the second argument. Using this new version of `loadScript`, we can -now rewrite our earlier example as follows - - index.js: - let a = loadScript("www.foo.com/a.js"); - let b = loadScript("www.foo.com/b.js"); - - a.foo // => 3 - b.foo; // => 5 - - a.js: - foo = 3; - - b.js: - foo = 5;: - -##Importing Names -In addition to exporting properties from the script being loaded to the loading -script, we can also import properties from the loading script to the script -being loaded: - - function loadScript(url, imports) { - let global = { - imports: imports, - exports: {} - }; - loader.loadSubScript(url, global); - return global.exports; - } - -Among other things, this allows us to import `loadScript` to scripts being -loaded, allowing them to load further scripts: - - index.js: - loadScript("www.foo.com/a.js", { - loadScript: loadScript - }).foo; => 5 - - a.js: - exports.foo = imports.loadScript("www.foo.com/b.js").bar; - - b.js: - exports.bar = 5; - -##Sandboxes and Compartments -The `loadScript` function as defined int the previous section still has some -serious shortcomings. The object it passed to the `loadSubScript` function is an -ordinary object, which has the global object of the loading script as its -prototype. This breaks encapsulation, as it allows the script being loaded to -access the built-in constructors of the loading script, which are defined on its -global object. The problem with breaking encapsulation like this is that -malicious scripts can use it to get the loading script to execute arbitrary -code, by overriding one of the methods on the built-in constructors. If the -loading script has chrome privileges, then so will any methods called by the -loading script, even if that method was installed by a malicious script. - -To avoid problems like this, the object passed to `loadSubScript` should be a -true global object, having its own instances of the built-in constructors. This -is exactly what sandboxes are for. A sandbox is a global object that lives in a -separate compartment. Compartments are a fairly recent addition to SpiderMonkey, -and can be seen as a separate memory space. Objects living in one compartment -cannot be accessed directly from another compartment: they need to be accessed -through an intermediate object, known as a wrapper. Compartments are very -useful from a security point of view: each compartment has a set of privileges -that determines what a script running in that compartment can and cannot do. -Compartments with chrome privileges have access to the `Components` object, -giving them full access to the host platform. In contrast, compartments with -content privileges can only use those features available to ordinary websites. - -The `Sandbox` constructor takes a `URL` parameter, which is used to determine -the set of privileges for the compartment in which the sandbox will be created. -Passing an XUL URL will result in a compartment with chrome privileges (note, -however, that if you ever actually do this in any of your code, Gabor will be -forced to hunt you down and kill you). Otherwise, the compartment will have -content privileges by default. Rewriting the `loadScript` function using -sandboxes, we end up with: - - function loadScript(url, imports) { - let global = Components.utils.Sandbox(url); - global.imports = imports; - global.exports = {}; - loader.loadSubScript(url, global); - return global.exports; - } - -Note that the object returned by `Sandbox` is a wrapper to the sandbox, not the -sandbox itself. A wrapper behaves exactly like the wrapped object, with one -difference: for each property access/function it performs an access check to -make sure that the calling script is actually allowed to access/call that -property/function. If the script being loaded is less privileged than the -loading script, the access is prevented, as the following example shows: - - index.js: - let a = loadScript("www.foo.com/a.js", { - Components: Components - }); - - // index.js has chrome privileges - Components.utils; // => [object nsXPCComponents_Utils] - - a.js: - // a.js has content privileges - imports.Components.utils; // => undefined - -##Modules in the Add-on SDK -The module system used by the SDK is based on what we learned so far: it follows -the CommonJS specification, which attempts to define a standardized module API. -A CommonJS module defines three global variables: `require`, which is a function -that behaves like `loadScript` in our examples, `exports`, which behaves -like the `exports` object, and `module`, which is an object representing -the module itself. The `require` function has some extra features not provided -by `loadScript`: it solves the problem of resolving relative URLs (which we have -left unresolved), and provides a caching mechanism, so that when the same module -is loaded twice, it returns the cached module object rather than triggering -another download. The module system is implemented using a loader object, which -is actually provided as a module itself. It is defined in the module -“toolkit/loader”: - - const { Loader } = require('toolkit/loader') - -The `Loader` constructor allows you to create your own custom loader objects. It -takes a single argument, which is a named options object. For instance, the -option `paths` is used to specify a list of paths to be used by the loader to -resolve relative URLs: - - let loader = Loader({ - paths: ["./": http://www.foo.com/"] - }); - -CommonJS also defines the notion of a main module. The main module is always the -first to be loaded, and differs from ordinary modules in two respects. Firstly, -since they do not have a requiring module. Instead, the main module is loaded -using a special function, called `main`: - - const { Loader, main } = require('toolkit/loader'); - - let loader = Loader({ - paths: ["./": http://www.foo.com/"] - }); - - main(loader, "./main.js"); - -Secondly, the main module is defined as a property on `require`. This allows -modules to check if it they have been loaded as the main module: - - function main() { - ... - } - - if (require.main === module) - main(); - -##The Cuddlefish Loader -The SDK uses its own internal loader, known as Cuddlefish (because we like crazy -names). Like any other custom loader, Cuddlefish is created using the `Loader` -constructor: Let's take a look at some of the options used by Cuddlefish to -customize its behavior. The way module ids are resolved can be customized by -passing a custom `resolve` function as an option. This function takes the id to -be resolved and the requiring module as an argument, and returns the resolved id -as its result. The resolved id is then further resolved using the paths array: - - const { Loader, main } = require('toolkit/loader'); - - let loader = Loader({ - paths: ["./": "http://www.foo.com/"], - resolve: function (id, requirer) { - // Your code here - return id; - } - }); - main(loader, "./main.js"); - -Cuddlefish uses a custom `resolve` function to implement a form of access -control: modules can only require modules for which they have been explicitly -granted access. A whitelist of modules is generated statically when the add-on -is linked. It is possible to pass a list of predefined modules as an option to -the `Loader` constructor. This is useful if the API to be exposed does not have -a corresponding JS file, or is written in an incompatible format. Cuddlefish -uses this option to expose the `Components` object as a module called `chrome`, -in a way similar to the code here below: - - const { - classes: Cc, - Constructor: CC, - interfaces: Ci, - utils: Cu, - results: Cr, - manager: Cm - } = Components; - - let loader = Loader({ - paths: ["./": "http://www.foo.com/"], - resolve: function (id, requirer) { - // Your logic here - return id; - }, - modules: { - 'chrome': { - components: Components, - Cc: Cc, - CC: bind(CC, Components), - Ci: Ci, - Cu: Cu, - Cr: Cr, - Cm: Cm - } - } - }); - -All accesses to the `chrome` module go through this one point. As a result, we -don't have to give modules chrome privileges on a case by case basis. More -importantly, however, any module that wants access to `Components` has to -explicitly express its intent via a call to `require("chrome")`. This makes it -possible to reason about which modules have chrome capabilities and which don't. diff --git a/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/private-properties.md b/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/private-properties.md deleted file mode 100644 index cc2b9428425c..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/contributors-guide/private-properties.md +++ /dev/null @@ -1,261 +0,0 @@ - - -#Private Properties - -A private property is a property that is only accessible to member -functions of instances of the same class. Unlike other languages, JavaScript -does not have native support for private properties. However, people have come -up with several ways to emulate private properties using existing language -features. We will take a look at two different techniques, using prefixes, and -closures, respectively. - -Prefixes and closures both have drawbacks in that they are either not -restrictive enough or too restrictive, respectively. We will therefore introduce -a third technique, based on the use of WeakMaps, that solves both these -problems. Note, however, that WeakMaps might not be supported by all -implementations yet. Next, we generalize the idea of using WeakMaps from -associating one or more private properties with an object to associating one or -more namespaces with each object. A namespace is simply an object on which one -or more private properties are defined. - -The SDK uses namespaces internally to implement private properties. The last -section explains how to work with the particular namespace implementation used -by the SDK. It is possible to read this section on its own, but to fully -appreciate how namespaces work, and the problem they are supposed to solve, it -is recommended that you read the entire article. - -##Using Prefixes - -A common technique to implement private properties is to prefix each private -property name with an underscore. Consider the following example: - - function Point(x, y) { - this._x = x; - this._y = y; - } - -The properties `_x` and `_y` are private, and should only be accessed by member -functions. - -To make a private property readable/writable from any function, it is common to -define a getter/setter function for the property, respectively: - - Point.prototype.getX = function () { - return this._x; - }; - - Point.prototype.setX = function (x) { - this._x = x; - }; - - Point.prototype.getY = function () { - return this._y; - }; - - Point.prototype.setY = function (y) { - this._y = y; - }; - -The above technique is simple, and clearly expresses our intent. However, the -use of an underscore prefix is just a coding convention, and is not enforced by -the language: there is nothing to prevent a user from directly accessing a -property that is supposed to be private. - -##Using Closures -Another common technique is to define private properties as variables, and their -getter and/or setter function as a closure over these variables: - - function Point(_x, _y) { - this.getX = function () { - return _x; - }; - - this.setX = function (x) { - _x = x; - }; - - this.getY = function () { - return _y; - }; - - this.setY = function (y) { - _y = y; - }; - } - -Note that this technique requires member functions that need access to private -properties to be defined on the object itself, instead of its prototype. This is -slightly less efficient, but this is probably acceptable. - -The advantage of this technique is that it offers more protection: there is no -way for the user to access a private property except by using its getter and/or -setter function. However, the use of closures makes private properties too -restrictive: since there is no way to access variables in one closure from -within another closure, there is no way for objects of the same class to access -each other's private properties. - -##Using WeakMaps - -The techniques we've seen so far ar either not restrictive enough (prefixes) or -too restrictive (closures). Until recently, a technique that solves both these -problems didn't exist. That changed with the introduction of WeakMaps. WeakMaps -were introduced to JavaScript in ES6, and have recently been implemented in -SpiderMonkey. Before we explain how WeakMaps work, let's take a look at how -ordinary objects can be used as hash maps, by creating a simple image cache: - - let images = {}; - - function getImage(name) { - let image = images[name]; - if (!image) { - image = loadImage(name); - images[name] = image; - } - return image; - } - -Now suppose we want to associate a thumbnail with each image. Moreover, we want -to create each thumbnail lazily, when it is first required: - - function getThumbnail(image) { - let thumbnail = image._thumbnail; - if (!thumbnail) { - thumbnail = createThumbnail(image); - image._thumbnail = thumbnail; - } - return thumbnail; - } - -This approach is straightforward, but relies on the use of prefixes. A better -approach would be to store thumbnails in their own, separate hash map: - - let thumbnails = {}; - - function getThumbnail(image) { - let thumbnail = thumbnails[image]; - if (!thumbnail) { - thumbnail = createThumbnail(image); - thumbnails[image] = thumbnail; - } - return thumbnail; - } - -There are two problems with the above approach. First, it's not possible to use -objects as keys. When an object is used as a key, it is converted to a string -using its toString method. To make the above code work, we'd have to associate a -unique identifier with each image, and override its `toString` method. The -second problem is more severe: the thumbnail cache maintains a strong reference -to each thumbnail object, so they will never be freed, even when their -corresponding image has gone out of scope. This is a memory leak waiting to -happen. - -The above two problems are exactly what WeakMaps were designed to solve. A -WeakMap is very similar to an ordinary hash map, but differs from it in two -crucial ways: - -1. It can use ordinary objects as keys -2. It does not maintain a strong reference to its values - -To understand how WeakMaps are used in practice, let's rewrite the thumbnail -cache using WeakMaps: - - let thumbnails = new WeakMap(); - - function getThumbnail(image) { - let thumbnail = thumbnails.get(image); - if (!thumbnail) { - thumbnail = createThumbnail(image); - thumbnails.set(image, thumbnail); - } - return thumbnail; - } - -This version suffers of none of the problems we mentioned earlier. When a -thumbnail's image goes out of scope, the WeakMap ensures that its entry in the -thumbnail cache will eventually be garbage collected. As a final caveat: the -image cache we created earlier suffers from the same problem, so for the above -code to work properly, we'd have to rewrite the image cache using WeakMaps, too. - -#From WeakMaps to Namespaces -In the previous section we used a WeakMap to associate a private property with -each object. Note that we need a separate WeakMap for each private property. -This is cumbersome if the number of private properties becomes large. A better -solution would be to store all private properties on a single object, called a -namespace, and then store the namespace as a private property on the original -object. Using namespaces, our earlier example can be rewritten as follows: - - let map = new WeakMap(); - - let internal = function (object) { - if (!map.has(object)) - map.set(object, {}); - return map.get(object); - } - - function Point(x, y) { - internal(this).x = x; - internal(this).y = y; - } - - Point.prototype.getX = function () { - return internal(shape).x; - }; - - Point.prototype.setX = function (x) { - internal(shape).x = x; - }; - - Point.prototype.getY = function () { - return internal(shape).y; - }; - - Point.prototype.setY = function () { - internal(shape).y = y; - }; - -The only way for a function to access the properties `x` and `y` is if it has a -reference to an instance of `Point` and its `internal` namespace. By keeping the -namespace hidden from all functions except members of `Point`, we have -effectively implemented private properties. Moreover, because members of `Point` -have a reference to the `internal` namespace, they can access private properties -on other instances of `Point`. - -##Namespaces in the Add-on SDK -The Add-on SDK is built on top of XPCOM, the interface between JavaScript and -C++ code. Since XPCOM allows the user to do virtually anything, security is very -important. Among other things, we don't want add-ons to be able to access -variables that are supposed to be private. The SDK uses namespaces internally to -ensure this. As always with code that is heavily reused, the SDK defines a -helper function to create namespaces. It is defined in the module -"core/namespace", and it's usage is straightforward. To illustrate this, let's -reimplement the class `Point` using namespaces: - - const { ns } = require("./core/namespace"); - - var internal = ns(); - - function Point(x, y) { - internal(this).x = x; - internal(this).y = y; - } - - Point.prototype.getX = function () { - return internal(shape).x; - }; - - Point.prototype.setX = function (x) { - internal(shape).x = x; - }; - - Point.prototype.getY = function () { - return internal(shape).y; - }; - - Point.prototype.setY = function () { - internal(shape).y = y; - }; - -As a final note, the function `ns` returns a namespace that uses the namespace -associated with the prototype of the object as its prototype. diff --git a/addon-sdk/source/doc/dev-guide-source/guides/events.md b/addon-sdk/source/doc/dev-guide-source/guides/events.md deleted file mode 100644 index 735ceaefd6a5..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/events.md +++ /dev/null @@ -1,156 +0,0 @@ - - -# Working with Events # - -The Add-on SDK supports event-driven programming through its -[`EventEmitter`](modules/sdk/deprecated/events.html) framework. - -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](dev-guide/guides/content-scripts/index.html) -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: - -* **listening to built-in events** emitted by objects in the SDK, such as tabs -opening, pages loading, mouse clicks - -* **sending and receiving user-defined events** between content scripts and -add-on code - -This guide only covers the first of these; the second is explained in the -[Working with Content Scripts](dev-guide/guides/content-scripts/index.html) -guide. - -## Adding Listeners ## - -You can add a listener to an event emitter by calling its `on(type, listener)` -method. - -It takes two parameters: - -* **`type`**: the type of event we are interested in, identified by a string. -Many event emitters may emit more than one type of event: for example, a browser -window might emit both `open` and `close` events. The list of valid event types -is specific to an event emitter and is included with its documentation. - -* **`listener`**: the listener itself. This is a function which will be called -whenever the event occurs. The arguments that will be passed to the listener -are specific to an event type and are documented with the event emitter. - -For example, the following add-on registers a listener with the -[`tabs`](modules/sdk/tabs.html) 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. - -### 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 [`widget`](modules/sdk/widget.html) object emits -an event when the widget is clicked. - -The following add-on creates a widget and assigns a listener to the -`onClick` property of the `options` object supplied to the widget's -constructor. The listener loads the Google home page: - - var widgets = require("sdk/widget"); - var tabs = require("sdk/tabs"); - - widgets.Widget({ - id: "google-link", - label: "Widget with an image and a click handler", - contentURL: "http://www.google.com/favicon.ico", - onClick: function() { - tabs.open("http://www.google.com/"); - } - }); - -This is exactly equivalent to constructing the widget and then calling the -widget's `on()` method: - - var widgets = require("sdk/widget"); - var tabs = require("sdk/tabs"); - - var widget = widgets.Widget({ - id: "google-link-alternative", - label: "Widget with an image and a click handler", - contentURL: "http://www.google.com/favicon.ico" - }); - - widget.on("click", function() { - tabs.open("http://www.google.com/"); - }); - -## 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](modules/sdk/tabs.html#ready). -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/addon-sdk/source/doc/dev-guide-source/guides/firefox-compatibility.md b/addon-sdk/source/doc/dev-guide-source/guides/firefox-compatibility.md deleted file mode 100644 index f91e832d2f2e..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/firefox-compatibility.md +++ /dev/null @@ -1,103 +0,0 @@ - - -# Firefox Compatibility # - -One of the promises the SDK makes is to maintain compatibility for its -["supported" or "high-level" APIs](modules/high-level-modules.html): -meaning that code written against them will not need to change as new -versions of Firefox are released. - -This ties the SDK release cycle into the Firefox release cycle because -the SDK must absorb any changes made to Firefox APIs. The SDK -and Firefox both release every 6 weeks, and the releases are precisely -staggered: so the SDK releases three weeks before Firefox. Each SDK -release is tested against, and marked as compatible with, two -versions of Firefox: - -* the currently shipping Firefox version at the time the SDK is released -* the Beta Firefox version at the time the SDK is released - which, -because SDK and Firefox releases are staggered, will become the -currently shipping Firefox three week later - -Add-ons built using a particular version of the SDK are marked -as being compatible with those two versions of Firefox, meaning -that in the -[`targetApplication` field of the add-on's install.rdf](https://developer.mozilla.org/en/Install.rdf#targetApplication): - -* the `minVersion` is set to the currently shipping Firefox -* the `maxVersion` is set to the current Firefox Beta - -See the -[SDK Release Schedule](https://wiki.mozilla.org/Jetpack/SDK_2012_Release_Schedule) -for the list of all SDK releases scheduled for 2012, along with the Firefox -versions they are compatible with. - -## "Compatible By Default" ## - -There are exceptions to the "compatible by default" rule: -add-ons with binary XPCOM components, add-ons that have their compatibility -set to less than Firefox 4, and add-ons that are repeatedly reported as -incompatible, which are added to a compatibility override list. - - -From Firefox 10 onwards, Firefox treats add-ons as -"compatible by default": that is, even if the Firefox installing the -add-on is not inside the range defined in `targetApplication`, -Firefox will happily install it. - -For example, although an add-on developed using version 1.6 of the SDK will be -marked as compatible with only versions 11 and 12 of Firefox, users of -Firefox 10 will still be able to install it. - -But before version 10, Firefox assumed that add-ons were incompatible unless -they were marked as compatible in the `targetApplication` field: so an add-on -developed using SDK 1.6 will not install on Firefox 9. - -## Changing minVersion and maxVersion Values ## - -The `minVersion` and `maxVersion` values that are written into add-ons -generated with the SDK are taken from the template file found at: - -
-app-extension/install.rdf
-
- -If you need to create add-ons which are compatible with a wider range of -Firefox releases, you can edit this file to change the -`minVersion...maxVersion` range. - -Obviously, you should be careful to test the resulting add-on on the extra -versions of Firefox you are including, because the version of the SDK you -are using will not have been tested against them. - -## Repacking Add-ons ## - -Suppose you create an add-on using version 1.6 of the SDK, and upload it to -[https://addons.mozilla.org/](https://addons.mozilla.org/). It's compatible -with versions 11 and 12 of Firefox, and indicates that in its -`minVersion...maxVersion` range. - -Now Firefox 13 is released. Suppose Firefox 13 does not change any of the -APIs used by version 1.6 of the SDK. In this case the add-on will still -work with Firefox 13. - -But if Firefox 13 makes some incompatible changes, then the add-on will -no longer work. In this case, we'll notify developers, who will need to: - -* download and install a new version of the SDK -* rebuild their add-on using this version of the SDK -* update their XPI on [https://addons.mozilla.org/](https://addons.mozilla.org/) -with the new version. - -If you created the add-on using the [Add-on Builder](https://builder.addons.mozilla.org/) -rather than locally using the SDK, then it will be repacked automatically -and you don't have to do this. - -### Future Plans ### - -The reason add-ons need to be repacked when Firefox changes is that the -SDK modules used by an add-on are packaged as part of the add-on, rather -than part of Firefox. In the future we plan to start shipping SDK modules -in Firefox, and repacking will not be needed any more. diff --git a/addon-sdk/source/doc/dev-guide-source/guides/index.md b/addon-sdk/source/doc/dev-guide-source/guides/index.md deleted file mode 100644 index e288dadfb092..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/index.md +++ /dev/null @@ -1,249 +0,0 @@ - - -# Guides # - -This page lists more theoretical in-depth articles about the SDK. - -
- -

Contributor's Guide

- - ---- - - - - - - - - - - - - - - - - - - -
-

Getting Started

- Learn how to contribute to the SDK: getting the code, opening/taking a - bug, filing a patch, getting reviews, and getting help. -
-

Private Properties

- Learn how private properties can be implemented in JavaScript using - prefixes, closures, and WeakMaps, and how the SDK supports private - properties by using namespaces (which are a generalization of WeakMaps). -
-

Modules

- Learn about the module system used by the SDK (which is based on the - CommonJS specification), how sandboxes and compartments can be used to - improve security, and about the built-in SDK module loader, known as - Cuddlefish. -
-

Content Processes

- The SDK was designed to work in an environment where the code to - manipulate web content runs in a different process from the main add-on - code. This article highlights the main features of that design. -
-

Classes and Inheritance

- Learn how classes and inheritance can be implemented in JavaScript, using - constructors and prototypes, and about the helper functions provided by - the SDK to simplify this. -
-
- -

SDK Infrastructure

- - ---- - - - - - - - - - - - - - - - - - - - - - - -
-

Module structure of the SDK

- The SDK, and add-ons built using it, are of composed from reusable JavaScript modules. This - explains what these modules are, how to load modules, and how the SDK's module - tree is structured. -
-

Program ID

- The Program ID is a unique identifier for your add-on. This guide - explains how it's created, what it's used for and how to define your - own. -
- -

Firefox compatibility

- Working out which Firefox releases a given SDK release is - compatible with, and dealing with compatibility problems. -
-

SDK API lifecycle

- Definition of the lifecycle for the SDK's APIs, including the stability - ratings for APIs. -
-
- -
- -

SDK Idioms

- - ---- - - - - - - - -
-

Working With Events

- Write event-driven code using the the SDK's event emitting framework. -
-

Two Types of Scripts

- This article explains the differences between the APIs - available to your main add-on code and those available - to content scripts. -
- -
- -

Content Scripts

- - ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Introducing content scripts

- An overview of content scripts. -
-

Loading content scripts

- Load content scripts into web pages, specified either as strings - or in separate files, and how to control the point at which they are - executed. -
-

Accessing the DOM

- Detail about the access content scripts get to the DOM. -
-

Communicating with other scripts

- Detail about how content scripts can communicate with "main.js", with other - content scripts, and with scripts loaded by the web page itself. -
-

Using "port"

- Communicating between a content script and the rest of your add-on - using the port object. -
-

Using "postMessage()"

- Communicating between a content script and the rest of your add-on - using the postMessage() API, and a comparison between - this technique and the port object. -
-

Cross-domain content scripts

- How to enable content scripts to interact with content served from different domains. -
-

Reddit example

- A simple add-on which uses content scripts. -
- -
- -

XUL Migration

- - ---- - - - - - - - - - - - - - - -
-

XUL Migration Guide

- Techniques to help port a XUL add-on to the SDK. -
-

XUL versus the SDK

- A comparison of the strengths and weaknesses of the SDK, - compared to traditional XUL-based add-ons. -
-

Porting Example

- A walkthrough of porting a relatively simple XUL-based - add-on to the SDK. -
-
diff --git a/addon-sdk/source/doc/dev-guide-source/guides/library-detector.md b/addon-sdk/source/doc/dev-guide-source/guides/library-detector.md deleted file mode 100644 index 7258a6dd2c52..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/library-detector.md +++ /dev/null @@ -1,218 +0,0 @@ - - -# Porting the Library Detector # - -This example walks through the process of porting a XUL-based add-on to the -SDK. It's a very simple add-on and a good candidate for porting because -there are suitable SDK APIs for all its features. - -Library Detector Screenshot - -The add-on is Paul Bakaus's -[Library Detector](https://addons.mozilla.org/en-US/firefox/addon/library-detector/). - -The Library Detector tells you which JavaScript frameworks the current -web page is using. It does this by checking whether particular objects -that those libraries add to the global window object are defined. -For example, if `window.jQuery` is defined, then the page has loaded -[jQuery](http://jquery.com/). - -For each library that it finds, the library detector adds an icon -representing that library to the status bar. It adds a tooltip to each -icon, which contains the library name and version. - -You can browse and run the ported version in the SDK's `examples` directory. - -### How the Library Detector Works ### - -All the work is done inside a single file, -[`librarydetector.xul`](http://code.google.com/p/librarydetector/source/browse/trunk/chrome/content/librarydetector.xul) -This contains: - -
    -
  • a XUL overlay
  • -
  • a script
  • -
- -The XUL overlay adds a `box` element to the browser's status bar: - - - -The script does everything else. - -The bulk of the script is an array of test objects, one for each library. -Each test object contains a function called `test()`: if the -function finds the library, it defines various additional properties for -the test object, such as a `version` property containing the library version. -Each test also contains a `chrome://` URL pointing to the icon associated with -its library. - -The script listens to [gBrowser](https://developer.mozilla.org/en/Code_snippets/Tabbed_browser)'s -`DOMContentLoaded` event. When this is triggered, the `testLibraries()` -function builds an array of libraries by iterating through the tests and -adding an entry for each library which passes. - -Once the list is built, the `switchLibraries()` function constructs a XUL -`statusbarpanel` element for each library it found, populates it with the -icon at the corresponding `chrome://` URL, and adds it to the box. - -Finally, it listens to gBrowser's `TabSelect` event, to update the contents -of the box for that window. - -### Content Script Separation ### - -The test objects in the original script need access to the DOM window object, -so in the SDK port, they need to run in a content script. In fact, they need -access to the un-proxied DOM window, so they can see the objects added by -libraries, so we’ll need to use the experimental [unsafeWindow](dev-guide/guides/content-scripts/accessing-the-dom.html#unsafeWindow) - -The main add-on script, `main.js`, will use a -[`page-mod`](modules/sdk/page-mod.html) -to inject the content script into every new page. - -The content script, which we'll call `library-detector.js`, will keep most of -the logic of the `test` functions intact. However, instead of maintaining its -own state by listening for `gBrowser` events and updating the -user interface, the content script will just run when it's loaded, collect -the array of library names, and post it back to `main.js`: - - function testLibraries() { - var win = unsafeWindow; - var libraryList = []; - for(var i in LD_tests) { - var passed = LD_tests[i].test(win); - if (passed) { - var libraryInfo = { - name: i, - version: passed.version - }; - libraryList.push(libraryInfo); - } - } - self.postMessage(libraryList); - } - - testLibraries(); - -`main.js` responds to that message by fetching the tab -corresponding to that worker using -[`worker.tab`](modules/sdk/content/worker.html#tab), and adding -the array of library names to that tab's `libraries` property: - - pageMod.PageMod({ - include: "*", - contentScriptWhen: 'end', - contentScriptFile: (data.url('library-detector.js')), - onAttach: function(worker) { - worker.on('message', function(libraryList) { - if (!worker.tab.libraries) { - worker.tab.libraries = []; - } - libraryList.forEach(function(library) { - if (worker.tab.libraries.indexOf(library) == -1) { - worker.tab.libraries.push(library); - } - }); - if (worker.tab == tabs.activeTab) { - updateWidgetView(worker.tab); - } - }); - } - }); - -The content script is executed once for every `window.onload` event, so -it will run multiple times when a single page containing multiple iframes -is loaded. So `main.js` needs to filter out any duplicates, in case -a page contains more than one iframe, and those iframes use the same library. - -### Implementing the User Interface ### - -#### Showing the Library Array #### - -The [`widget`](modules/sdk/widget.html) module is a natural fit -for displaying the library list. We'll specify its content using HTML, so we -can display an array of icons. The widget must be able to display different -content for different windows, so we'll use the -[`WidgetView`](modules/sdk/widget.html) object. - -`main.js` will create an array of icons corresponding to the array of library -names, and use that to build the widget's HTML content dynamically: - - function buildWidgetViewContent(libraryList) { - widgetContent = htmlContentPreamble; - libraryList.forEach(function(library) { - widgetContent += buildIconHtml(icons[library.name], - library.name + "
Version: " + library.version); - }); - widgetContent += htmlContentPostamble; - return widgetContent; - } - - function updateWidgetView(tab) { - var widgetView = widget.getView(tab.window); - if (!tab.libraries) { - tab.libraries = []; - } - widgetView.content = buildWidgetViewContent(tab.libraries); - widgetView.width = tab.libraries.length * ICON_WIDTH; - } - -`main.js` will -use the [`tabs`](modules/sdk/tabs.html) module to update the -widget's content when necessary (for example, when the user switches between -tabs): - - tabs.on('activate', function(tab) { - updateWidgetView(tab); - }); - - tabs.on('ready', function(tab) { - tab.libraries = []; - }); - -#### Showing the Library Detail #### - -The XUL library detector displayed the detailed information about each -library on mouseover in a tooltip: we can't do this using a widget, so -instead will use a panel. This means we'll need two additional content -scripts: - -* one in the widget's context, which listens for icon mouseover events -and sends a message to `main.js` containing the name of the corresponding -library: - -

-function setLibraryInfo(element) {
-  self.port.emit('setLibraryInfo', element.target.title);
-}
-
-var elements = document.getElementsByTagName('img');
-
-for (var i = 0; i < elements.length; i++) {
-  elements[i].addEventListener('mouseover', setLibraryInfo, false);
-}
-
- -* one in the panel, which updates the panel's content with the library -information: - -

-self.on("message", function(libraryInfo) {
-  window.document.body.innerHTML = libraryInfo;
-});
-
- -Finally `main.js` relays the library information from the widget to the panel: - -

-widget.port.on('setLibraryInfo', function(libraryInfo) {
-  widget.panel.postMessage(libraryInfo);
-});
-
- -Updating panel content diff --git a/addon-sdk/source/doc/dev-guide-source/guides/modules.md b/addon-sdk/source/doc/dev-guide-source/guides/modules.md deleted file mode 100644 index ece017542fe3..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/modules.md +++ /dev/null @@ -1,191 +0,0 @@ - - -# Modules in the SDK # - -[CommonJS](http://wiki.commonjs.org/wiki/CommonJS) is the underlying -infrastructure for both the SDK and the add-ons you build using the SDK. -A CommonJS module is a piece of reusable JavaScript: it exports certain -objects which are thus made available to dependent code. CommonJS defines: - -* an object called `exports` which contains all the objects which a CommonJS -module wants to make available to other modules -* a function called `require` which a module can use to import the `exports` -object of another module. - -![CommonJS modules](static-files/media/commonjs-modules.png) - -Except for [scripts that interact directly with web content](dev-guide/guides/content-scripts/index.html), -all the JavaScript code you'll write or use when developing add-ons using -the SDK is part of a CommonJS module, including: - -* [SDK modules](dev-guide/guides/modules.html#SDK Modules): -the JavaScript modules which the SDK provides, such as -[`panel`](modules/sdk/panel.html) and [page-mod](modules/sdk/page-mod.html). -* [Local modules](dev-guide/guides/modules.html#Local Modules): -each of the JavaScript files under your add-ons "lib" directory. -* [External modules](dev-guide/guides/modules.html#External Modules): -reusable modules developed and maintained outside the SDK, but usable by -SDK-based add-ons. - -## SDK Modules ## - -The modules supplied by the SDK are divided into two sorts: - -* [High-level modules](dev-guide/high-level-apis.html) like -[`panel`](modules/sdk/panel.html) and - [`page-mod`](modules/sdk/page-mod.html) provide relatively simple, -stable APIs for the most common add-on development tasks. -* [Low-level modules](dev-guide/low-level-apis.html) like -[`heritage`](modules/sdk/core/heritage.html) and -[`namespace`](modules/sdk/core/heritage.html) provide more -powerful functionality, and are typically less stable and more -complex. - -To use SDK modules, you can pass `require()` a complete path, starting with -"sdk", to the module you want to use. For high-level modules this is just -`sdk/`, and for low-level -modules it is `sdk//`: - - // load the high-level "tabs" module - var tabs = require("sdk/tabs"); - - // load the low-level "uuid" module - var uuid = require('sdk/util/uuid'); - -The path to specify for a low-level module is given along with the module -name itself in the title of the module's documentation page (for example, -[system/environment](modules/sdk/system/environment.html)). - -Although the [SDK repository in GitHub](https://github.com/mozilla/addon-sdk) -includes copies of these modules, they are built into Firefox and by -default, when you run or build an add-on using -[`cfx run`](dev-guide/cfx-tool.html#cfx-run) -or [`cfx xpi`](dev-guide/cfx-tool.html#cfx-xpi), it is the versions of -the modules in Firefox that are used. If you need to use a different version -of the modules, you can do this by checking out the version of the SDK -that you need and passing the `-o` or -`--overload-modules` option to `cfx run` or `cfx xpi`. - -## Local Modules ## - -At a minimum, an SDK-based add-on consists of a single module -named `main.js`, but you can factor your add-on's code into a collection -of separate CommonJS modules. Each module is a separate file stored under your -add-on's "lib" directory, and exports the objects you want to make available -to other modules in your add-on. See the tutorial on -[creating reusable modules](dev-guide/tutorials/reusable-modules.html) for -more details. - -To import a local module, specify a path relative to the importing module. - -For example, the following add-on contains an additional module directly under -"lib", and other modules under subdirectories of "lib": - -
    -
  • my-addon -
      -
    • lib -
        -
      • main.js
      • -
      • password-dialog.js
      • -
      • secrets -
          -
        • hash.js
        • -
        -
      • -
      • storage -
          -
        • password-store.js
        • -
        -
      • -
      -
    • -
    -
  • -
- -To import modules into `main`: - - // main.js code - var dialog = require("./password-dialog"); - var hash = require("./secrets/hash"); - -To import modules into `password-store`: - - // password-store.js code - var dialog = require("../password-dialog"); - var hash = require("../secrets/hash"); - -
- -For backwards compatibility, you may also omit the leading "`./`" -or "`../`" characters, treating the path as an absolute path from -your add-on's "lib" directory: - - var dialog = require("password-dialog"); - var hash = require("secrets/hash"); - -This form is not recommended for new code, because the behavior of `require` -is more complex and thus less predictable than if you specify the target -module explicitly using a relative path. - -## External Modules ## - -As well as using the SDK's modules and writing your own, you -can use modules that have been developed outside the SDK and made -available to other add-on authors. - -There's a list of these -["community-developed modules"](https://github.com/mozilla/addon-sdk/wiki/Community-developed-modules) -in the SDK's GitHub Wiki, and to learn how to use them, see -the tutorial on -[using external modules to add menu items to Firefox](dev-guide/tutorials/adding-menus.html). - -To import external modules, treat them like local modules: -copy them somewhere under your add-ons "lib" directory and -reference them with a path relative to the importing module. - -For example, this add-on places external modules in a "dependencies" -directory: - -
    -
  • my-addon -
      -
    • lib -
        -
      • main.js
      • -
      • dependencies -
          -
        • geolocation.js
        • -
        -
      • -
      -
    • -
    -
  • -
- -It can then load them in the same way it would load a local module. -For example, to load from `main`: - - // main.js code - var geo = require("./dependencies/geolocation"); - -
- -## Freezing ## - -The SDK -[freezes](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/freeze) -the `exports` object returned by `require`. So a if you import a module using -`require`, you can't change the properties of the object returned: - - self = require("sdk/self"); - // Attempting to define a new property - // will fail, or throw an exception in strict mode - self.foo = 1; - // Attempting to modify an existing property - // will fail, or throw an exception in strict mode - self.data = "foo"; diff --git a/addon-sdk/source/doc/dev-guide-source/guides/program-id.md b/addon-sdk/source/doc/dev-guide-source/guides/program-id.md deleted file mode 100644 index 186d35bbabea..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/program-id.md +++ /dev/null @@ -1,33 +0,0 @@ - - -# The Program ID # - -The Program ID is a unique identifier for your add-on. When you package your -add-on for distribution using `cfx xpi`, it will become the -[ID field in the add-on's Install Manifest](https://developer.mozilla.org/en/install.rdf#id). - -The ID is used for a variety -of purposes. For example: [addons.mozilla.org](http://addons.mozilla.org) uses -it to distinguish between new add-ons and updates to existing add-ons, and the -[`simple-storage`](modules/sdk/simple-storage.html) module uses it -to figure out which stored data belongs to which add-on. - -It is read from the `id` key in your add-on's [`package.json`](dev-guide/package-spec.html) file. -`cfx init` does not create this key, so if you don't set it yourself, the -first time you execute `cfx run` or `cfx xpi`, then `cfx` will create an -ID for you, and will show a message like this: - -
-  No 'id' in package.json: creating a new ID for you.
-  package.json modified: please re-run 'cfx run'
-
- -The ID generated by `cfx` in this way is a randomly-generated string, but -you can define your own ID by editing the `package.json` file -directly. In particular, you can use the `extensionname@example.org` format -described in the -[Install Manifest documentation](https://developer.mozilla.org/en/install.rdf#id). -However, you can't use the -[GUID-style](https://developer.mozilla.org/en/Generating_GUIDs) format. diff --git a/addon-sdk/source/doc/dev-guide-source/guides/sdk-vs-xul.md b/addon-sdk/source/doc/dev-guide-source/guides/sdk-vs-xul.md deleted file mode 100644 index a4d1d344c9a3..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/sdk-vs-xul.md +++ /dev/null @@ -1,107 +0,0 @@ - - - -# SDK and XUL Comparison # - -## Advantages of the SDK ## - - ---- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Simplicity

The SDK provides high-level JavaScript APIs to simplify many -common tasks in add-on development, and tool support which greatly simplifies -the process of developing, testing, and packaging an add-on.

-
Compatibility

Although we can't promise we'll never break a High-Level API, -maintaining compatibility across Firefox versions is a top priority for us.

-

We've designed the APIs to be forward-compatible with the new -multiple process architecture -(codenamed Electrolysis) planned for Firefox.

-

We also expect to support both desktop and mobile Firefox using a single -edition of the SDK: so you'll be able to write one extension and have it work -on both products.

Security

If they're not carefully designed, Firefox add-ons can open the browser -to attack by malicious web pages. Although it's possible to write insecure -add-ons using the SDK, it's not as easy, and the damage that a compromised -add-on can do is usually more limited.

Restartlessness

Add-ons built with the SDK are can be installed without having -to restart Firefox.

-

Although you can write - -traditional add-ons that are restartless, you can't use XUL overlays in -them, so most traditional add-ons would have to be substantially rewritten -anyway.

User Experience Best Practices

The UI components available in the SDK are designed to align with the usability -guidelines for Firefox, giving your users a better, more consistent experience.

Mobile Support

Starting in SDK 1.5, we've added experimental support for developing -add-ons on the new native version of Firefox Mobile. See the -tutorial on mobile development.

- -## Advantages of XUL-based Add-ons ## - - ---- - - - - - - - - - - -
User interface flexibility

XUL overlays offer a great deal of options for building a UI and -integrating it into the browser. Using only the SDK's supported APIs you have -much more limited options for your UI.

XPCOM

Traditional add-ons have access to a vast amount of Firefox -functionality via XPCOM. The SDK's supported APIs expose a relatively -small set of this functionality.

- -### Low-level APIs and Third-party Modules ### - -That's not the whole story. If you need more flexibility than the SDK's -High-Level APIs provide, you can use its Low-level APIs to load -XPCOM objects directly or to manipulate the DOM directly as in a -traditional -bootstrapped extension. - -Alternatively, you can load third-party modules, which extend the SDK's -core APIs. - -Note that by doing this you lose some of the benefits of programming -with the SDK including simplicity, compatibility, and to a lesser extent -security. diff --git a/addon-sdk/source/doc/dev-guide-source/guides/stability.md b/addon-sdk/source/doc/dev-guide-source/guides/stability.md deleted file mode 100644 index eedbb8314448..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/stability.md +++ /dev/null @@ -1,112 +0,0 @@ - - -# SDK API Lifecycle # - -Developers using the SDK's APIs need to know how far they can trust that -a given API will not change in future releases. At the same time, developers -maintaining and extending the SDK's APIs need to be able to introduce new -APIs that aren't yet fully proven, and to retire old APIs when they're -no longer optimal or supported by the underlying platform. - -The API lifecycle aims to balance these competing demands. It has two -main components: - -* a [stability index](dev-guide/guides/stability.html#Stability Index) -that defines how stable each module is -* a [deprecation process](dev-guide/guides/stability.html#Deprecation Process) -that defines when and how stable SDK APIs can be changed or removed from -future versions of the SDK while giving developers enough time to update -their code. - -## Stability Index ## - -The stability index is adopted from -[node.js](http://nodejs.org/api/documentation.html#documentation_stability_index). -The SDK uses only four of the six values defined by node.js: - - - - - - - - - - - - - - - - - - -
ExperimentalThe module is not yet stabilized. -You can try it out and provide feedback, but we may change or remove -it in future versions without having to pass through a formal -deprecation process.
UnstableThe API is in the process of settling, but has not yet had sufficient -real-world testing to be considered stable. -Backwards-compatibility will be maintained if reasonable. -If we do have to make backwards-incompatible changes, we will not guarantee -to go through the formal deprecation process.
StableThe module is a fully-supported part of -the SDK. We will avoid breaking backwards compatibility unless absolutely -necessary. If we do have to make backwards-incompatible changes, we will -go through the formal deprecation process.
DeprecatedWe plan to change this module, and backwards compatibility -should not be expected. Don’t start using it, and plan to migrate away from -this module to its replacement.
- -The stability index for each module is written into that module’s -metadata structure, and is displayed at the top of each module's -documentation page. - -## Deprecation Process ## - -### Deprecation ### - -In the chosen release, the SDK team will communicate the module's deprecation: - -* update the module's stability index to be "deprecated" -* include a deprecation notice in the -[release notes](https://wiki.mozilla.org/Labs/Jetpack/Release_Notes), -the [Add-ons blog](https://blog.mozilla.org/addons/), and the -[Jetpack Google group](https://groups.google.com/forum/?fromgroups#!forum/mozilla-labs-jetpack). -The deprecation notice should point developers at a migration guide. - -### Migration ### - -The deprecation period defaults to 18 weeks (that is, three releases) -although in some cases, generally those out of our control, it might -be shorter than this. - -During this time, the module will be in the deprecated state. The SDK -team will track usage of deprecated modules on -[addons.mozilla.org](https://addons.mozilla.org/en-US/firefox/) and support -developers migrating their code. The SDK will continue to provide warnings: - -* API documentation will inform users that the module is deprecated. -* Attempts to use a deprecated module at runtime will log an error to -the error console. -* The AMO validator will throw errors when deprecated modules are used, -and these add-ons will therefore fail AMO review. - -All warnings should include links to further information about what to -use instead of the deprecated module and when the module will be completely -removed. - -### Removal ### - -The target removal date is 18 weeks after deprecation. In preparation for -this date the SDK team will decide whether to go ahead with removal: this -will depend on how many developers have successfully migrated from the -deprecated module, and on how urgently the module needs to be removed. - -If it's OK to remove the module, it will be removed. The SDK team will -remove the corresponding documentation, and communicate the removal in -the usual ways: the [release notes](https://wiki.mozilla.org/Labs/Jetpack/Release_Notes), -the [Add-ons blog](https://blog.mozilla.org/addons/), and the -[Jetpack Google group](https://groups.google.com/forum/?fromgroups#!forum/mozilla-labs-jetpack). - -If it's not OK to remove it, the team will continue to support migration -and aim to remove the module in the next release. diff --git a/addon-sdk/source/doc/dev-guide-source/guides/two-types-of-scripts.md b/addon-sdk/source/doc/dev-guide-source/guides/two-types-of-scripts.md deleted file mode 100644 index 3a0eaf7c5e5c..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/two-types-of-scripts.md +++ /dev/null @@ -1,119 +0,0 @@ - - -# Two Types of Scripts # - -On the web, JavaScript executes in the context of a web page, and has access to -that page's DOM content. This enables you to call functions like: - - window.alert("Hello there"); - -In an add-on's main scripts you can't do that, because the add-on code does -not execute in the context of a page, and the DOM is therefore not available. -If you need to access the DOM of a particular page, you need to use a -content script. - -So there are two distinct sorts of JavaScript scripts you might include -in your add-on and they have access to different sets of APIs. In the SDK -documentation we call one sort "add-on code" and the other sort "content -scripts". - -## Add-on Code ## - -This is the place where the main logic of your add-on is implemented. - -Your add-on is implemented as a collection of one or more -[CommonJS modules](dev-guide/guides/modules.html). Each module -is supplied as a script stored under the `lib` directory under your add-on's -root directory. - -Minimally you'll have a single module implemented by a script called -"main.js", but you can include additional modules in `lib`, and import them -using the `require()` function. To learn how to implement and import your own -modules, see the tutorial on -[Implementing Reusable Modules](dev-guide/tutorials/reusable-modules.html). - -## Content Scripts ## - -While your add-on will always have a "main.js" module, you will only need -to write content scripts if your add-on needs to manipulate web content. -Content scripts are injected into web pages using APIs defined by some of the -SDK's modules such as `page-mod`, `panel` and `widget`. - -Content scripts may be supplied as literal strings or maintained in separate -files and referenced by filename. If they are stored in separate files you -should store them under the `data` directory under your add-on's root. - -To learn all about content scripts read the -[Working with Content Scripts](dev-guide/guides/content-scripts/index.html) -guide. - -## API Access for Add-on Code and Content Scripts ## - -The table below summarizes the APIs that are available to each type of -script. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
APIAdd-on codeContent script
The global objects defined in the core JavaScript language, such as -Math, Array, and JSON. See the -reference at MDN. -

The require() and exports globals defined -by version 1.0 of the -CommonJS Module Specification. -You use require() to import functionality from another module, -and exports to export functionality from your module.

-If require() is available, then so are the modules supplied in the -SDK. -
The console -global supplied by the SDK. -
Globals defined by the -HTML5 specification, -such as window, document, and -localStorage. -
The self global, used for communicating between content -scripts and add-on code. See the guide to -communicating with content scripts -for more details. -
diff --git a/addon-sdk/source/doc/dev-guide-source/guides/xul-migration.md b/addon-sdk/source/doc/dev-guide-source/guides/xul-migration.md deleted file mode 100644 index 6eba5c5f13cf..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/guides/xul-migration.md +++ /dev/null @@ -1,377 +0,0 @@ - - - -# XUL Migration Guide # - -This guide aims to help you migrate a XUL-based add-on to the SDK. - -First we'll outline how to decide whether - -your add-on is a good candidate for migration via a -[comparison of the benefits and limitations of the SDK versus XUL development](dev-guide/guides/sdk-vs-xul.html). - -Next, we'll look at some of the main tasks involved in migrating: - -* -working with content scripts -* -using the SDK's supported APIs -* how to -go beyond the supported APIs when necessary, by: - * -using third party modules - * -using the SDK's low-level APIs - * -getting direct access to XPCOM - -Finally, we'll walk through a - -simple example. - -## Should You Migrate? ## - -See this [comparison of the benefits and limitations of SDK development -and XUL development](dev-guide/guides/sdk-vs-xul.html). - -Whether you should migrate a particular add-on is largely a matter of -how well the SDK's - -supported APIs meet its needs. - -* If your add-on can accomplish everything it needs using only the -supported APIs, it's a good candidate for migration. - -* If your add-on needs a lot of help from third party packages, low-level -APIs, or XPCOM, then the cost of migrating is high, and may not be worth -it at this point. - -* If your add-on only needs a little help from those techniques, and can -accomplish most of what it needs using the supported APIs, then it might -still be worth migrating: we'll add more supported APIs in future releases -to meet important use cases. - -## User Interface Components## - -XUL-based add-ons typically implement a user interface using a combination -of two techniques: XUL overlays and XUL windows. - -### XUL Overlays ### - -XUL overlays are used to modify existing windows such as the main browser -window. In this way an extension can integrate its user interface into the -browser: for example, adding menu items, buttons, and toolbars. - -Because SDK-based extensions are restartless, they can't use XUL overlays. To -add user interface components to the browser, there are a few different -options. In order of complexity, the main options are: - -* the SDK includes modules that implement some basic user interface -components including [buttons](modules/sdk/widget.html), -[dialogs](modules/sdk/panel.html), and -[context menu items](modules/sdk/context-menu.html). - -* there is a collection of -[community-developed modules](https://github.com/mozilla/addon-sdk/wiki/Community-developed-modules) -that includes various user interface components, including -[toolbar buttons](https://github.com/voldsoftware/toolbarbutton-jplib) and -[menu items](https://github.com/voldsoftware/menuitems-jplib). - -* by using the SDK's -[low-level APIs](dev-guide/guides/xul-migration.html#Using the Low-level APIs) -you can directly modify the browser chrome. - -### XUL Windows - -XUL windows are used to define completely new windows to host user interface -elements specific to the add-on. - -The SDK generally expects you to specify your user interface using HTML, not -XUL. However, you can include a -[chrome.manifest file](https://developer.mozilla.org/en-US/docs/Chrome_Registration) -in your add-on and it will be included in the generated XPI. - -
    -
  • my-addon -
      -
    • chrome -
      • content
      • -
      • locale
      • -
      • skin
      -
    • -
    • chrome.manifest
    • -
    • data
    • -
    • lib
    • -
    • package.json
    • -
    -
  • -
- -There are limitations on what you can do in this manifest file: for example, -you can't register overlays, `resource:` URIs, or components. However, you -can register a `chrome:` URI, with a skin and locale, and this means you -can include XUL windows in an SDK-based add-on. - -You can keep the "chrome.manifest" file in your add-on's root directory -and create a directory there called "chrome". In that directory you can keep -your "content", "locale", and "skin" subdirectories: - -This allows you to refer to objects in these directories from "chrome.manifest" using a relative path, like "chrome/content". - -This is provided only as a migration aid, and it's still a good idea to port XUL windows to HTML. - -
- -## Content Scripts ## - -In a XUL-based add-on, code that uses XPCOM objects, code that manipulates -the browser chrome, and code that interacts with web pages all runs in the -same context. But the SDK makes a distinction between: - -* **add-on scripts**, which can use the SDK APIs, but are not able to interact -with web pages -* **content scripts**, which can access web pages, but do not have access to -the SDK's APIs - -Content scripts and add-on scripts communicate by sending each other JSON -messages: in fact, the ability to communicate with the add-on scripts is the -only extra privilege a content script is granted over a normal remote web -page script. - -A XUL-based add-on will need to be reorganized to respect this distinction. - -The main reason for this design is security: it reduces the risk that a -malicious web page will be able to access privileged APIs. - -There's much more information on content scripts in the -[Working With Content Scripts](dev-guide/guides/content-scripts/index.html) guide. - -## Using the Supported APIs ## - -The SDK provides a set of high level APIs -providing some basic user interface components and functionality commonly -required by add-ons. Because we expect to keep these APIs compatible as new versions -of Firefox are released, we call them the "supported" APIs. - -See the [tutorials](dev-guide/tutorials/index.html) -and the [High-Level API reference](modules/high-level-modules.html). -If the supported APIs do what you need, they're the best option: you get the -benefits of compatibility across Firefox releases and of the SDK's security -model. - -APIs like [`widget`](modules/sdk/widget.html) and -[`panel`](modules/sdk/panel.html) are very generic and with the -right content can be used to replace many specific XUL elements. But there are -some notable limitations in the SDK APIs and even a fairly simple UI may need -some degree of redesign to work with them. - -Some limitations are the result of intentional design choices. For example, -widgets always appear by default in the -[add-on bar](https://developer.mozilla.org/en/The_add-on_bar) (although users -may relocate them by -[toolbar customization](http://support.mozilla.com/en-US/kb/how-do-i-customize-toolbars)) -because it makes for a better user experience for add-ons to expose their -interfaces in a consistent way. In such cases it's worth considering -changing your user interface to align with the SDK APIs. - -Some limitations only exist because we haven't yet implemented the relevant -APIs: for example, there's currently no way to add items to the browser's main -menus using the SDK's supported APIs. - -Many add-ons will need to make some changes to their user interfaces if they -are to use only the SDK's supported APIs, and add-ons which make drastic -changes to the browser chrome will very probably need more than the SDK's -supported APIs can offer. - -Similarly, the supported APIs expose only a small fraction of the full range -of XPCOM functionality. - -## Using Third Party Packages ## - -The SDK is extensible by design: developers can create new modules filling gaps -in the SDK, and package them for distribution and reuse. Add-on developers can -install these packages and use the new modules. - -If you can find a third party package that does what you want, this is a great -way to use features not supported in the SDK without having to use the -low-level APIs. - -See the -[guide to adding Firefox menu items](dev-guide/tutorials/adding-menus.html). -Some useful third party packages are -[collected in the Jetpack Wiki](https://wiki.mozilla.org/Jetpack/Modules). - -Note, though, that by using third party packages you're likely to lose the -security and compatibility benefits of using the SDK. - -## Using the Low-level APIs ## - - -But note that unlike the supported APIs, low-level APIs do not come with a -compatibility guarantee, so we do not expect code using them will necessarily -continue to work as new versions of Firefox are released. - - -In addition to the High-Level APIs, the SDK includes a number of -[Low-Level APIs](modules/low-level-modules.html) some of which, such -[`xhr`](modules/sdk/net/xhr.html) and -[`window/utils`](modules/sdk/window/utils.html), expose powerful -browser capabilities. - -In this section we'll use low-level modules how to: - -* modify the browser chrome using dynamic manipulation of the DOM -* directly access the [tabbrowser](https://developer.mozilla.org/en/XUL/tabbrowser) -object - -### Modifying the Browser Chrome ### - -The [`window/utils`](modules/sdk/window/utils.html) module gives -you direct access to chrome windows, including the browser's chrome window. -Here's a really simple example add-on that modifies the browser chrome using -`window/utils`: - - function removeForwardButton() { - var window = require("sdk/window/utils").getMostRecentBrowserWindow(); - var forward = window.document.getElementById('forward-button'); - var parent = window.document.getElementById('unified-back-forward-button'); - parent.removeChild(forward); - } - - var widgets = require("sdk/widget"); - - widgets.Widget({ - id: "remove-forward-button", - label: "Remove the forward button", - contentURL: "http://www.mozilla.org/favicon.ico", - onClick: function() { - removeForwardButton(); - } - }); - -There are more useful examples of this technique in the Jetpack Wiki's -collection of [third party modules](https://wiki.mozilla.org/Jetpack/Modules). - -### Accessing tabbrowser ### - - -The [`tabs/utils`](modules/sdk/tabs/utils.html) module gives -you direct access to the -[tabbrowser](https://developer.mozilla.org/en/XUL/tabbrowser) object and the -XUL tab objects it contains. This simple example modifies the selected tab's -CSS to enable the user to highlight the selected tab: - - var widgets = require("sdk/widget"); - var tabUtils = require("sdk/tabs/utils"); - var self = require("sdk/self"); - - function highlightTab(tab) { - if (tab.style.getPropertyValue('background-color')) { - tab.style.setProperty('background-color','','important'); - } - else { - tab.style.setProperty('background-color','rgb(255,255,100)','important'); - } - } - - var widget = widgets.Widget({ - id: "tab highlighter", - label: "Highlight tabs", - contentURL: self.data.url("highlight.png"), - onClick: function() { - var window = require("sdk/window/utils").getMostRecentBrowserWindow(); - highlightTab(tabUtils.getActiveTab(window)); - } - }); - -### Security Implications ### - -The SDK implements a security model in which an add-on only gets to access the -APIs it explicitly imports via `require()`. This is useful, because it means -that if a malicious web page is able to inject code into your add-on's -context, it is only able to use the APIs you have imported. For example, if -you have only imported the -[`notifications`](modules/sdk/notifications.html) module, then -even if a malicious web page manages to inject code into your add-on, it -can't use the SDK's [`file`](modules/sdk/io/file.html) module to -access the user's data. - -But this means that the more powerful modules you `require()`, the greater -is your exposure if your add-on is compromised. Low-level modules like `xhr`, -`tab-browser` and `window-utils` are much more powerful than the modules in -`addon-kit`, so your add-on needs correspondingly more rigorous security -design and review. - -## Using XPCOM ## - -Finally, if none of the above techniques work for you, you can use the -`require("chrome")` statement to get direct access to the -[`Components`](https://developer.mozilla.org/en/Components_object) object, -which you can then use to load and access any XPCOM object. - -The following complete add-on uses -[`nsIPromptService`](https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIPromptService) -to display an alert dialog: - - var {Cc, Ci} = require("chrome"); - - var promptSvc = Cc["@mozilla.org/embedcomp/prompt-service;1"]. - getService(Ci.nsIPromptService); - - var widget = require("sdk/widget").Widget({ - id: "xpcom example", - label: "Mozilla website", - contentURL: "http://www.mozilla.org/favicon.ico", - onClick: function() { - promptSvc.alert(null, "My Add-on", "Hello from XPCOM"); - } - }); - -It's good practice to encapsulate code which uses XPCOM by -[packaging it in its own module](dev-guide/tutorials/reusable-modules.html). -For example, we could package the alert feature implemented above using a -script like: - - var {Cc, Ci} = require("chrome"); - - var promptSvc = Cc["@mozilla.org/embedcomp/prompt-service;1"]. - getService(Ci.nsIPromptService); - - exports.alert = function(title, text) { - promptSvc.alert(null, title, text); - }; - -If we save this as "alert.js" in our add-on's `lib` directory, we can rewrite -`main.js` to use it as follows: - - var widget = require("sdk/widget").Widget({ - id: "xpcom example", - label: "Mozilla website", - contentURL: "http://www.mozilla.org/favicon.ico", - onClick: function() { - require("./alert").alert("My Add-on", "Hello from XPCOM"); - } - }); - -One of the benefits of this is that we can control which parts of the add-on -are granted chrome privileges, making it easier to review and secure the code. - -### Security Implications ### - -We saw above that using powerful low-level modules like `tab-browser` -increases the damage that a malicious web page could do if it were able to -inject code into your add-ons context. This applies with even greater force -to `require("chrome")`, since this gives full access to the browser's -capabilities. - -## Example: Porting the Library Detector ## - -[Porting the Library Detector](dev-guide/guides/library-detector.html) -walks through the process of porting a XUL-based add-on to the -SDK. It's a very simple add-on and a good candidate for porting because -there are suitable SDK APIs for all its features. - -Even so, we have to change its user interface slightly if we are to use only -the supported APIs. diff --git a/addon-sdk/source/doc/dev-guide-source/high-level-apis.md b/addon-sdk/source/doc/dev-guide-source/high-level-apis.md deleted file mode 100644 index e4f82541a936..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/high-level-apis.md +++ /dev/null @@ -1,16 +0,0 @@ - - -# High-Level APIs # - -Modules in this section implement high-level APIs for -building add-ons: - -* creating user interfaces -* interacting with the web -* interacting with the browser - -These modules are "supported": meaning that they are relatively -stable, and that we'll avoid making incompatible changes to them -unless absolutely necessary. diff --git a/addon-sdk/source/doc/dev-guide-source/index.md b/addon-sdk/source/doc/dev-guide-source/index.md deleted file mode 100644 index 36df858c2790..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/index.md +++ /dev/null @@ -1,172 +0,0 @@ - - -

Welcome to the Add-on SDK!

- -Using the Add-on SDK you can create Firefox add-ons using standard Web -technologies: JavaScript, HTML, and CSS. The SDK includes JavaScript APIs which you can use to create add-ons, and tools for creating, running, testing, and packaging add-ons. - -
- -## Tutorials ## - - ---- - - - - - - - - - - - - - - - - - - -
-

Getting started

- How to - install the SDK and - use the cfx - tool to develop, test, and package add-ons. -
-

Create user interface components

- Create user interface components such as - toolbar buttons, - menu items, and - dialogs -
-

Interact with the browser

- Open web pages, - listen for pages loading, and - list open pages. -
-

Modify web pages

- Modify pages matching a URL pattern - or dynamically modify a particular tab. -
-

Development techniques

-Learn about common development techniques, such as -unit testing, -logging, -creating reusable modules, -localization, and -mobile development. -
-

Putting it together

- Walkthrough of the Annotator example add-on. -
- -
- -## Guides ## - - ---- - - - - - - - - - - - - - - - - - - - - - -
-

Contributor's Guide

- Learn - how to start contributing to the SDK, - and about the most important idioms used in the SDK code, such as - modules, - classes and inheritance, - private properties, and - content processes. -
-

SDK idioms

- The SDK's - event framework and the - distinction between add-on scripts and content scripts. -
-

SDK infrastructure

- Aspects of the SDK's underlying technology: - Modules, the - Program ID, - and the rules defining - Firefox compatibility. -
-

XUL migration

- A guide to porting XUL add-ons to the SDK. - This guide includes a - comparison of the two toolsets and a - worked example of porting a XUL add-on. -
-

Content scripts

- A detailed guide to working with content scripts, - including: how to load content scripts, which objects - content scripts can access, and how to communicate - between content scripts and the rest of your add-on. -
-
- -
- -## Reference ## - - ---- - - - - - - - - - - - -
-

High-Level APIs

- Reference documentation for the high-level SDK APIs. -
-

Low-Level APIs

- Reference documentation for the low-level SDK APIs. -
-

Tools reference

- Reference documentation for the - cfx tool - used to develop, test, and package add-ons, the - console - global used for logging, and the - package.json file. -
-
diff --git a/addon-sdk/source/doc/dev-guide-source/low-level-apis.md b/addon-sdk/source/doc/dev-guide-source/low-level-apis.md deleted file mode 100644 index a84cea551f6b..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/low-level-apis.md +++ /dev/null @@ -1,34 +0,0 @@ - - -# Low-Level APIs # - -Modules in this section implement low-level APIs. These -modules fall roughly into three categories: - -* fundamental utilities such as -[collection](modules/sdk/platform/xpcom.html) and -[url](modules/sdk/url.html). Many add-ons are likely to -want to use modules from this category. - -* building blocks for higher level modules, such as -[events](modules/sdk/deprecated/events.html), -[worker](modules/sdk/content/worker.html), and -[api-utils](modules/sdk/deprecated/api-utils.html). You're more -likely to use these if you are building your own modules that -implement new APIs, thus extending the SDK itself. - -* privileged modules that expose powerful low-level capabilities -such as [tab-browser](modules/sdk/deprecated/tab-browser.html), -[xhr](modules/sdk/net/xhr.html), and -[xpcom](modules/sdk/platform/xpcom.html). You can use these -modules in your add-on if you need to, but should be aware that -the cost of privileged access is the need to take more elaborate -security precautions. In many cases these modules have simpler, -more restricted analogs among the "High-Level APIs" (for -example, [tabs](modules/sdk/tabs.html) or -[request](modules/sdk/request.html)). - -These modules are still in active development, and we expect to -make incompatible changes to them in future releases. diff --git a/addon-sdk/source/doc/dev-guide-source/package-spec.md b/addon-sdk/source/doc/dev-guide-source/package-spec.md deleted file mode 100644 index d47126742d88..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/package-spec.md +++ /dev/null @@ -1,226 +0,0 @@ - - -# package.json # - -The "package.json" file contains metadata for your add-on. - -Some of its entries, such as [`icon`](dev-guide/package-spec.html#icon), -[`name`](dev-guide/package-spec.html#name), and -[`description`](dev-guide/package-spec.html#description), have -direct analogues in the -[install manifest](https://developer.mozilla.org/en-US/docs/Install_Manifests) -format, and entries from package.json are written into the install -manifest when the add-on is built using [`cfx xpi`](dev-guide/cfx-tool.html#cfx xpi). - -Others, such as -[`lib`](dev-guide/package-spec.html#lib), -[`permissions`](dev-guide/package-spec.html#permissions), -and [`preferences`](dev-guide/package-spec.html#preferences), -represent instructions to the cfx tool itself to generate and include -particular code and data structures in your add-on. - -The `package.json` file is initially generated in your add-on's root -directory the first time you run -[`cfx init`](dev-guide/cfx-tool.html#cfx init). It looks like this -(assuming the add-on's directory is "my-addon"): - -
-{
-  "name": "my-addon",
-  "fullName": "my-addon",
-  "description": "a basic add-on",
-  "author": "",
-  "license": "MPL 2.0",
-  "version": "0.1"
-}
-
- -`package.json` may contain the following keys: - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
author

The original author of the package. 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 its "install.rdf".

contributors

An array of additional author - strings.

-

These values will be used as the add-on's - em:contributor - elements in its "install.rdf".

dependencies

String or array of strings representing package - names that this add-on requires in order to function properly.

description

The add-on's description. 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".

fullName

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

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 relative path from the root of the add-on to a - PNG file containing the icon for the add-on. Defaults to - "icon.png".

-

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.

icon64

The relative path from the root of the add-on to a - PNG file containing the large icon for the add-on. Defaults to - "icon64.png".

-

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".

license

The name of the license under which the add-on is distributed, with an optional - URL in parentheses. Defaults to "MPL 2.0".

main

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 - key is not present, name is used as the add-on's - em:name - element in its "install.rdf".

packages

String or array of strings representing paths to - directories 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.

-
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.

tests

String representing the top-level module directory containing - test suites for this package. Defaults to "tests".

translators

An array of strings listing translators of this add-on.

-

These values will be used as the add-on's - em:translator - elements in its "install.rdf".

version

String representing the version of the add-on. Defaults to - "0.1".

-

This value will be used as the add-on's - em:version - element in its "install.rdf".

- diff --git a/addon-sdk/source/doc/dev-guide-source/search.md b/addon-sdk/source/doc/dev-guide-source/search.md deleted file mode 100644 index 26946d5cbc40..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/search.md +++ /dev/null @@ -1,190 +0,0 @@ - - -
Loading
- - - - - - diff --git a/addon-sdk/source/doc/dev-guide-source/third-party-apis.md b/addon-sdk/source/doc/dev-guide-source/third-party-apis.md deleted file mode 100644 index 6919c69bf4ea..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/third-party-apis.md +++ /dev/null @@ -1,7 +0,0 @@ - - -# Third-Party APIs # - -This section lists modules which you've downloaded and added to your SDK installation. \ No newline at end of file diff --git a/addon-sdk/source/doc/dev-guide-source/tutorials/add-a-context-menu-item.md b/addon-sdk/source/doc/dev-guide-source/tutorials/add-a-context-menu-item.md deleted file mode 100644 index 6f35c21ad0af..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/tutorials/add-a-context-menu-item.md +++ /dev/null @@ -1,89 +0,0 @@ - - -# Add a Context Menu Item # - - -To follow this tutorial you'll need to have -[installed the SDK](dev-guide/tutorials/installation.html) -and learned the -[basics of `cfx`](dev-guide/tutorials/getting-started-with-cfx.html). - - -To add items and submenus to the Firefox context menu, use the -[`context-menu`](modules/sdk/context-menu.html) module. - -Here's an add-on that adds a new context menu item. The item is -displayed whenever something in the page is selected. When it's -clicked, the selection is sent to the main add-on code, which just -logs it: - - 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: - - - -Click it, and the selection is -[logged to the console](dev-guide/tutorials/logging.html): - -
-info: elephantine lizard
-
- -All this add-on does is to construct a context menu item. You don't need -to add it: once you have constructed the item, it is automatically added -in the correct context. The constructor in this case takes four options: -`label`, `context`, `contentScript`, and `onMessage`. - -### label ### - -The `label` is just the string that's displayed. - -### context ### - -The `context` describes the circumstances in which the item should be -shown. The `context-menu` module provides a number of simple built-in -contexts, including this `SelectionContext()`, which means: display -the item when something on the page is selected. - -If these simple contexts aren't enough, you can define more sophisticated -contexts using scripts. - -### contentScript ### - -This attaches a script to the item. In this case the script listens for -the user to click on the item, then sends a message to the add-on containing -the selected text. - -### onMessage ### - -The `onMessage` property provides a way for the add-on code to respond to -messages from the script attached to the context menu item. In this case -it just logs the selected text. - -So: - -1. the user clicks the item -2. the content script's `click` event fires, and the content script retrieves -the selected text and sends a message to the add-on -3. the add-on's `message` event fires, and the add-on code's handler function -is passed the selected text, which it logs - -## Learning More ## - -To learn more about the `context-menu` module, see the -[`context-menu` API reference](modules/sdk/context-menu.html). \ No newline at end of file diff --git a/addon-sdk/source/doc/dev-guide-source/tutorials/adding-menus.md b/addon-sdk/source/doc/dev-guide-source/tutorials/adding-menus.md deleted file mode 100644 index 46e7130c68b6..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/tutorials/adding-menus.md +++ /dev/null @@ -1,137 +0,0 @@ - - -# Add a Menu Item to Firefox # - - -To follow this tutorial you'll need to have -[installed the SDK](dev-guide/tutorials/installation.html) -and learned the -[basics of `cfx`](dev-guide/tutorials/getting-started-with-cfx.html). - - -The SDK doesn't yet provide an API to add new menu items to Firefox. -But it's extensible by design, so anyone can build and publish -modules for add-on developers to use. Luckily, Erik Vold has written -a [`menuitems`](https://github.com/erikvold/menuitems-jplib) module -that enables us to add menu items. - -This tutorial does double-duty. It describes the general method for -using an external, third-party module in your add-on, and it -describes how to add a menu item using the `menuitems` module in particular. - -First, create a new add-on. Make a directory called "clickme" wherever you -like, navigate to it and run `cfx init`. - -
-mkdir clickme
-cd clickme
-cfx init
-
- -The usual directory structure will be created: - -
    -
  • clickme -
      -
    • data
    • -
    • docs -
      • main.md
      -
    • -
    • lib -
      • main.js
      -
    • -
    • package.json
    • -
    • README.md
    • -
    • tests -
      • test-main.js
      -
    • -
    -
  • -
- -
- -## Installing `menuitems` ## - -Create a directory under "clickme" called "packages". -Then download the `menuitems` package from -[https://github.com/erikvold/menuitems-jplib](https://github.com/erikvold/menuitems-jplib/zipball/51080383cbb0fe2a05f8992a8aae890f4c014176) and extract it into the "packages" directory you just created: - -
-mkdir packages
-cd packages
-tar -xf ../erikvold-menuitems-jplib-d80630c.zip
-
- -## Module Dependencies ## - -If third-party modules only depend on SDK modules, you can use them right -away, but if they depend on other third-party modules, you'll have to install -those dependencies as well. - -In the package's main directory you'll find a file called "package.json". -Open it up and look for an entry named "dependencies". The entry for the -`menuitems` package is: - -
-"dependencies": ["vold-utils"]
-
- -This tells us that we need to install the `vold-utils` package, -which we can do by downloading it from -[https://github.com/erikvold/vold-utils-jplib](https://github.com/voldsoftware/vold-utils-jplib/zipball/1b2ad874c2d3b2070a1b0d43301aa3731233e84f) -and adding it under the `packages` directory alongside `menuitems`. - -## Using `menuitems` ## - -The [documentation for the `menuitems` module](https://github.com/erikvold/menuitems-jplib/blob/master/docs/menuitems.md) -tells us to create a menu item using `MenuItem()`. Of the options -accepted by `MenuItem()`, we'll use this minimal set: - -* `id`: identifier for this menu item -* `label`: text the item displays -* `command`: function called when the user selects the item -* `menuid`: identifier for the item's parent element -* `insertbefore`: identifier for the item before which we want our item to -appear - - - - var menuitem = require("menuitems").Menuitem({ - id: "clickme", - menuid: "menu_ToolsPopup", - label: "Click Me!", - onCommand: function() { - console.log("clicked"); - }, - insertbefore: "menu_pageInfo" - }); - -Next, we have to declare our dependency on the `menuitems` package. -In your add-on's `package.json` add the line: - -
-"dependencies": "menuitems"
-
- -Note that due to -[bug 663480](https://bugzilla.mozilla.org/show_bug.cgi?id=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"]
-
- -Now we're done. Run the add-on and you'll see the new item appear in the -`Tools` menu: select it and you'll see `info: clicked` appear in the -console. - -## Caveats ## - -Third-party modules are a great way to use features not directly supported by -the SDK, but because third party modules typically use low-level APIs, -they may be broken by new releases of Firefox. diff --git a/addon-sdk/source/doc/dev-guide-source/tutorials/adding-toolbar-button.md b/addon-sdk/source/doc/dev-guide-source/tutorials/adding-toolbar-button.md deleted file mode 100644 index 184c6f563c57..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/tutorials/adding-toolbar-button.md +++ /dev/null @@ -1,174 +0,0 @@ - - -# Adding a Button to the Toolbar # - - -To follow this tutorial you'll need to have -[installed the SDK](dev-guide/tutorials/installation.html) -and learned the -[basics of `cfx`](dev-guide/tutorials/getting-started-with-cfx.html). - - -To add a button to the toolbar, use the -[`widget`](modules/sdk/widget.html) module. - -Create a new directory, navigate to it, and execute `cfx init`. -Then open the file called "main.js" in the "lib" directory and -add the following code to it: - - var widgets = require("sdk/widget"); - var tabs = require("sdk/tabs"); - - var widget = widgets.Widget({ - id: "mozilla-link", - label: "Mozilla website", - contentURL: "http://www.mozilla.org/favicon.ico", - onClick: function() { - tabs.open("http://www.mozilla.org/"); - } - }); - -The widget is added to the "Add-on Bar" at the bottom of the browser window: - - - -You can't change the initial location for the widget, but the user can move -it to a different toolbar. The `id` attribute is mandatory, and is used to -remember the position of the widget, so you should not change it in subsequent -versions of the add-on. - -Clicking the button opens [http://www.mozilla.org](http://www.mozilla.org). - -
- -## Specifying the Icon ## - -If you're using the widget to make a toolbar button, specify the icon to -display using `contentURL`: this may refer to a remote file as in the -example above, or may refer to a local file. The example below will load -an icon file called "my-icon.png" from the add-on's `data` directory: - - var widgets = require("sdk/widget"); - var tabs = require("sdk/tabs"); - var self = require("sdk/self"); - - var widget = widgets.Widget({ - id: "mozilla-link", - label: "Mozilla website", - contentURL: self.data.url("my-icon.png"), - onClick: function() { - tabs.open("http://www.mozilla.org/"); - } - }); - -You can change the icon at any time by setting the widget's `contentURL` -property. However, 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](https://bugzilla.mozilla.org/show_bug.cgi?id=825434). - -## Responding To the User ## - -You can listen for `click`, `mouseover`, and `mouseout` events by passing -handler functions as the corresponding constructor options. The widget -example above assigns a listener to the `click` event using the `onClick` -option, and there are similar `onMouseover` and `onMouseout` options. - -To handle user interaction in more detail, you can attach a content -script to the widget. 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. - -Here's an example. The widget's built-in `onClick` property does not -distinguish between left and right mouse clicks, so to do this we need -to use a content script. The script looks like this: - - window.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); - -It uses the standard DOM `addEventListener()` function to listen for click -events, and handles them by sending the corresponding message to the main -add-on code. Note that the messages "left-click" and "right-click" are not -defined in the widget API itself, they're custom events defined by the add-on -author. - -Save this script in your `data` directory as "click-listener.js". - -Next, modify `main.js` to: - -
    -
  • pass in the script by setting the contentScriptFile -property
  • -
  • listen for the new events:
  • -
- - var widgets = require("sdk/widget"); - var tabs = require("sdk/tabs"); - var self = require("sdk/self"); - - var widget = widgets.Widget({ - id: "mozilla-link", - label: "Mozilla website", - contentURL: "http://www.mozilla.org/favicon.ico", - contentScriptFile: self.data.url("click-listener.js") - }); - - widget.port.on("left-click", function(){ - console.log("left-click"); - }); - - widget.port.on("right-click", function(){ - console.log("right-click"); - }); - -Now execute `cfx run` again, and try right- and left-clicking on the button. -You should see the corresponding string written to the command shell. - -## Attaching a Panel ## - - - - - -If you supply a `panel` object to the widget's constructor, then the panel -will be shown 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 - }); - -To learn more about working with panels, see the tutorial on -[displaying a popup](dev-guide/tutorials/display-a-popup.html). - -## Learning More ## - -To learn more about the widget module, see its -[API reference documentation](modules/sdk/widget.html). - -To learn more about content scripts, see the -[content scripts guide](dev-guide/guides/content-scripts/index.html). diff --git a/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/creating.md b/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/creating.md deleted file mode 100644 index d0e5448e124e..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/creating.md +++ /dev/null @@ -1,344 +0,0 @@ - - -# Creating Annotations # - -We'll use two objects to create annotations: a page-mod to find page elements -that the user can annotate, and a panel for the user to enter the annotation -text itself. - -## Selector page-mod ## - -### Selector Content Scripts ### - -The content script for the selector page-mod uses [jQuery](http://jquery.com/) -to examine and manipulate the DOM. - -Its main job is to maintain a "matched element": this is the page element that -is the current candidate for an annotation. The matched element is highlighted -and has a click handler bound to it which sends a message to the main add-on -code. - -The selector page mod can be switched on and off using a message from the -main add-on code. It is initially off: - - var matchedElement = null; - var originalBgColor = null; - var active = false; - - function resetMatchedElement() { - if (matchedElement) { - $(matchedElement).css('background-color', originalBgColor); - $(matchedElement).unbind('click.annotator'); - } - } - - self.on('message', function onMessage(activation) { - active = activation; - if (!active) { - resetMatchedElement(); - } - }); - -This selector listens for occurrences of the -[jQuery mouseenter](http://api.jquery.com/mouseenter/) event. - -When a mouseenter event is triggered the selector checks whether the element -is eligible for annotation. An element is eligible if it, or one of its -ancestors in the DOM tree, has an attribute named `"id"`. The idea here is to -make it more likely that the annotator will be able to identify annotated -elements correctly later on. - -If the page element is eligible for annotation, then the selector highlights -that element and binds a click handler to it. The click handler sends a message -called `show` back to the main add-on code. The `show` message contains: the URL -for the page, the ID attribute value, and the text content of the page element. - - $('*').mouseenter(function() { - if (!active || $(this).hasClass('annotated')) { - return; - } - resetMatchedElement(); - ancestor = $(this).closest("[id]"); - matchedElement = $(this).first(); - originalBgColor = $(matchedElement).css('background-color'); - $(matchedElement).css('background-color', 'yellow'); - $(matchedElement).bind('click.annotator', function(event) { - event.stopPropagation(); - event.preventDefault(); - self.port.emit('show', - [ - document.location.toString(), - $(ancestor).attr("id"), - $(matchedElement).text() - ] - ); - }); - }); - -Conversely, the add-on resets the matched element on -[mouseout](http://api.jquery.com/mouseout/): - - $('*').mouseout(function() { - resetMatchedElement(); - }); - -Save this code in a new file called `selector.js` in your add-on's `data` -directory. - -Because this code uses jQuery, you'll need to -[download](http://docs.jquery.com/Downloading_jQuery) that as well, and save it in -`data`. - -### Updating main.js ### - -Go back to `main.js` and add the code to create the selector into the `main` -function: - - var selector = pageMod.PageMod({ - include: ['*'], - contentScriptWhen: 'ready', - contentScriptFile: [data.url('jquery-1.4.2.min.js'), - data.url('selector.js')], - onAttach: function(worker) { - worker.postMessage(annotatorIsOn); - selectors.push(worker); - worker.port.on('show', function(data) { - console.log(data); - }); - worker.on('detach', function () { - detachWorker(this, selectors); - }); - } - }); - -Make sure the name you use to load jQuery matches the name of the jQuery -version you downloaded. - -The page-mod matches all pages, so each time the user loads a page the page-mod -emits the `attach` event, which will call the listener function we've assigned -to `onAttach`. The handler is passed a -[worker](modules/sdk/content/worker.html) object. Each worker -represents a channel of communication between the add-on code and any content -scripts running in that particular page context. For a more detailed discussion -of the way `page-mod` uses workers, see the -[page-mod documentation](modules/sdk/page-mod.html). - -In the attach handler we do three things: - -* send the content script a message with the current activation status -* add the worker to an array called `selectors` so we can send it messages -later on -* assign a message handler for messages from this worker. If the message is -`show` we will just log the content for the time being. If the message is -`detach` we remove the worker from the `selectors` array. - -At the top of the file import the `page-mod` module and declare an array for -the workers: - - var pageMod = require('sdk/page-mod'); - var selectors = []; - -Add `detachWorker`: - - function detachWorker(worker, workerArray) { - var index = workerArray.indexOf(worker); - if(index != -1) { - workerArray.splice(index, 1); - } - } - -Edit `toggleActivation` to notify the workers of a change in activation state: - - function activateSelectors() { - selectors.forEach( - function (selector) { - selector.postMessage(annotatorIsOn); - }); - } - - function toggleActivation() { - annotatorIsOn = !annotatorIsOn; - activateSelectors(); - return annotatorIsOn; - } - -We'll be using this URL in all our screenshots. Because -`cfx run` doesn't preserve browsing history, if you want to play along it's -worth taking a note of the URL. -Save the file and execute `cfx run` again. Activate the annotator by clicking -the widget and load a page: the screenshot below uses -[http://blog.mozilla.com/addons/2011/02/04/ -overview-amo-review-process/](http://blog.mozilla.com/addons/2011/02/04/overview-amo-review-process/). -You should see the highlight appearing when you move the mouse over certain elements: - -Annotator Highlighting - -Click on the highlight and you should see something like this in the console -output: - -
-  info: show
-  info: http://blog.mozilla.com/addons/2011/02/04/overview-amo-review-process/,
-  post-2249,When you submit a new add-on, you will have to choose between 2
-  review tracks: Full Review and Preliminary Review.
-
- -## Annotation Editor Panel ## - -So far we have a page-mod that can highlight elements and send information -about them to the main add-on code. Next we will create the editor panel, -which enables the user to enter an annotation associated with the selected -element. - -We will supply the panel's content as an HTML file, and will also supply a -content script to execute in the panel's context. - -So create a subdirectory under `data` called `editor`. This will contain -two files: the HTML content, and the content script. - -### Annotation Editor HTML ### - -The HTML is very simple: - - - -Save this inside `data/editor` as `annotation-editor.html`. - -### Annotation Editor Content Script ### - -In the corresponding content script we do two things: - -* handle a message from the add-on code by giving the text area focus -* listen for the return key and when it is pressed, send the contents of the -text area to the add-on. - -Here's the code: - - var textArea = document.getElementById('annotation-box'); - - textArea.onkeyup = function(event) { - if (event.keyCode == 13) { - self.postMessage(textArea.value); - textArea.value = ''; - } - }; - - self.on('message', function() { - var textArea = document.getElementById('annotation-box'); - textArea.value = ''; - textArea.focus(); - }); - - -Save this inside `data/editor` as `annotation-editor.js`. - -### Updating main.js Again ### - -Now we'll update `main.js` again to create the editor and use it. - -First, import the `panel` module: - - var panels = require('sdk/panel'); - -Then add the following code to the `main` function: - - var annotationEditor = panels.Panel({ - width: 220, - height: 220, - contentURL: data.url('editor/annotation-editor.html'), - contentScriptFile: data.url('editor/annotation-editor.js'), - onMessage: function(annotationText) { - if (annotationText) { - console.log(this.annotationAnchor); - console.log(annotationText); - } - annotationEditor.hide(); - }, - onShow: function() { - this.postMessage('focus'); - } - }); - -We create the editor panel but don't show it. -We will send the editor panel the `focus` message when it is shown, so it will -give the text area focus. When the editor panel sends us its message we log the -message and hide the panel. - -The only thing left is to link the editor to the selector. So edit the message -handler assigned to the selector so that on receiving the `show` message we -assign the content of the message to the panel using a new property -"annotationAnchor", and show the panel: - - var selector = pageMod.PageMod({ - include: ['*'], - contentScriptWhen: 'ready', - contentScriptFile: [data.url('jquery-1.4.2.min.js'), - data.url('selector.js')], - onAttach: function(worker) { - worker.postMessage(annotatorIsOn); - selectors.push(worker); - worker.port.on('show', function(data) { - annotationEditor.annotationAnchor = data; - annotationEditor.show(); - }); - worker.on('detach', function () { - detachWorker(this, selectors); - }); - } - }); - -Execute `cfx run` again, activate the annotator, move your mouse over an -element and click the element when it is highlighted. You should see a panel -with a text area for a note: - -Annotator Editor Panel -
- -Enter the note and press the return key: you should see console output like -this: - -
-  info: http://blog.mozilla.com/addons/2011/02/04/overview-amo-review-process/,
-  post-2249,When you submit a new add-on, you will have to choose between 2
-  review tracks: Full Review and Preliminary Review.
-  info: We should ask for Full Review if possible.
-
- -That's a complete annotation, and in the next section we'll deal with -[storing it](dev-guide/tutorials/annotator/storing.html). diff --git a/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/displaying.md b/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/displaying.md deleted file mode 100644 index aa6d5a6dda0d..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/displaying.md +++ /dev/null @@ -1,213 +0,0 @@ - - -# Displaying Annotations # - -In this chapter we'll use a page-mod to locate elements of web pages that have -annotations associated with them, and a panel to display the annotations. - -## Matcher page-mod ## - -### Matcher Content Script ### - -The content script for the matcher page-mod is initialized with a list -of all the annotations that the user has created. - -When a page is loaded the matcher searches the DOM for elements that match -annotations. If it finds any it binds functions to that element's -[mouseenter](http://api.jquery.com/mouseenter/) and -[mouseleave](http://api.jquery.com/mouseleave/) events to send messages to the -`main` module, asking it to show or hide the annotation. - -Like the selector, the matcher also listens for the window's `unload` event -and on unload sends a `detach` message to the `main` module, so the add-on -can clean it up. - -The complete content script is here: - - self.on('message', function onMessage(annotations) { - annotations.forEach( - function(annotation) { - if(annotation.url == document.location.toString()) { - createAnchor(annotation); - } - }); - - $('.annotated').css('border', 'solid 3px yellow'); - - $('.annotated').bind('mouseenter', function(event) { - self.port.emit('show', $(this).attr('annotation')); - event.stopPropagation(); - event.preventDefault(); - }); - - $('.annotated').bind('mouseleave', function() { - self.port.emit('hide'); - }); - }); - - function createAnchor(annotation) { - annotationAnchorAncestor = $('#' + annotation.ancestorId); - annotationAnchor = $(annotationAnchorAncestor).parent().find( - ':contains(' + annotation.anchorText + ')').last(); - $(annotationAnchor).addClass('annotated'); - $(annotationAnchor).attr('annotation', annotation.annotationText); - } - -Save this in `data` as `matcher.js`. - -### Updating main.js ### - -First, initialize an array to hold workers associated with the matcher's -content scripts: - - var matchers = []; - -In the `main` function, add the code to create the matcher: - - var matcher = pageMod.PageMod({ - include: ['*'], - contentScriptWhen: 'ready', - contentScriptFile: [data.url('jquery-1.4.2.min.js'), - data.url('matcher.js')], - onAttach: function(worker) { - if(simpleStorage.storage.annotations) { - worker.postMessage(simpleStorage.storage.annotations); - } - worker.port.on('show', function(data) { - annotation.content = data; - annotation.show(); - }); - worker.port.on('hide', function() { - annotation.content = null; - annotation.hide(); - }); - worker.on('detach', function () { - detachWorker(this, matchers); - }); - matchers.push(worker); - } - }); - -When a new page is loaded the function assigned to `onAttach` is called. This -function: - -* initializes the content script instance with the current set of -annotations -* provides a handler for messages from that content script, handling the three -messages - `show`, `hide` and `detach` - that the content script might send -* adds the worker to an array, so we it can send messages back later. - -Then in the module's scope implement a function to update the matcher's -workers, and edit `handleNewAnnotation` to call this new function when the -user enters a new annotation: - - function updateMatchers() { - matchers.forEach(function (matcher) { - matcher.postMessage(simpleStorage.storage.annotations); - }); - } - -
- - function handleNewAnnotation(annotationText, anchor) { - var newAnnotation = new Annotation(annotationText, anchor); - simpleStorage.storage.annotations.push(newAnnotation); - updateMatchers(); - } -
- -## Annotation panel ## - -The annotation panel just shows the content of an annotation. - -There are two files associated with the annotation panel: - -* a simple HTML file to use as a template -* a simple content script to build the panel's content - -These files will live in a new subdirectory of `data` which we'll call -`annotation`. - -### Annotation panel HTML ### - - - -Save this in `data/annotation` as `annotation.html`. - -### Annotation panel Content Script ### - -The annotation panel has a minimal content script that sets the text: - - self.on('message', function(message) { - $('#annotation').text(message); - }); - -Save this in `data/annotation` as `annotation.js`. - -### Updating main.js ### - -Finally, update `main.js` with the code to construct the annotation panel: - - var annotation = panels.Panel({ - width: 200, - height: 180, - contentURL: data.url('annotation/annotation.html'), - contentScriptFile: [data.url('jquery-1.4.2.min.js'), - data.url('annotation/annotation.js')], - onShow: function() { - this.postMessage(this.content); - } - }); - -Execute `cfx run` one last time. Activate the annotator and enter an -annotation. You should see a yellow border around the item you annotated: - -Annotator Matcher -
- -When you move your mouse over the item, the annotation should appear: - -Annotation Panel -
- -Obviously this add-on isn't complete yet. It could do with more beautiful -styling, it certainly needs a way to delete annotations, it should deal with -`OverQuota` more reliably, and the matcher could be made to match more -reliably. - -But we hope this gives you an idea of the things that are possible with the -modules in the SDK. diff --git a/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/index.md b/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/index.md deleted file mode 100644 index ec71f55c7348..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/index.md +++ /dev/null @@ -1,31 +0,0 @@ - - -# Annotator: a More Complex Add-on # - -In this tutorial we'll build an add-on that uses many of the SDK's -[high-level APIs](modules/high-level-modules.html). - -The add-on is an annotator: it enables the user to select elements of web pages -and enter notes (annotations) associated with them. The annotator stores the -notes. Whenever the user loads a page containing annotated elements these -elements are highlighted, and if the user moves the mouse over an annotated -element its annotation is displayed. - -Next we'll give a quick overview of the annotator's design, then go through -the implementation, step by step. - -If you want to refer to the complete add-on you can find it under the -`examples` directory. - -* [Design Overview](dev-guide/tutorials/annotator/overview.html) - -* [Implementing the Widget](dev-guide/tutorials/annotator/widget.html) - -* [Creating Annotations](dev-guide/tutorials/annotator/creating.html) - -* [Storing Annotations](dev-guide/tutorials/annotator/storing.html) - -* [Displaying Annotations](dev-guide/tutorials/annotator/displaying.html) - diff --git a/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/overview.md b/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/overview.md deleted file mode 100644 index bbdba2c802d4..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/overview.md +++ /dev/null @@ -1,67 +0,0 @@ - - -# Annotator Design Overview # - -The annotator uses content scripts to build user interfaces, get user input, -and examine the DOM of pages loaded by the user. - -Meanwhile the `main` module contains the application logic and mediates -interactions between the different SDK objects. - -We could represent the basic interactions between the `main` module and the -various content scripts like this: - -Annotator Design - -## User Interface ## - -The annotator's main user interface consists of a widget and three panels. - -* The widget is used to switch the annotator on and off, and to display a list -of all the stored annotations. -* The **annotation-editor** panel enables the user to enter a new annotation. -* The **annotation-list** panel shows a list of all stored annotations. -* The **annotation** panel displays a single annotation. - -Additionally, we use the `notifications` module to notify the user when the -add-on's storage quota is full. - -## Working with the DOM ## - -We'll use two page-mods to interact with the DOMs of pages that the user has -opened. - -* The **selector** enables the user to choose an element to annotate. -It identifies page elements which are eligible for annotation, highlights them -on mouseover, and tells the main add-on code when the user clicks a highlighted -element. - -* The **matcher** is responsible for finding annotated elements: it is -initialized with the list of annotations and searches web pages for the -elements they are associated with. It highlights any annotated elements that -are found. When the user moves the mouse over an annotated element -the matcher tells the main add-on code, which displays the annotation panel. - -## Working with Data ## - -We'll use the `simple-storage` module to store annotations. - -Because we are recording potentially sensitive information, we want to prevent -the user creating annotations when in private browsing mode. The simplest way -to do this is to omit the -[`"private-browsing"` key](dev-guide/package-spec.html#permissions) from the -add-on's "package.json" file. If we do this, then the add-on won't see any -private windows, and the annotator's widget will not appear in any private -windows. - -## Getting Started ## - - -Let's get started by creating a directory called "annotator". Navigate to it -and type `cfx init`. - -Next, we will implement the -[widget](dev-guide/tutorials/annotator/widget.html). diff --git a/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/storing.md b/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/storing.md deleted file mode 100644 index 58fa4dc41f81..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/storing.md +++ /dev/null @@ -1,296 +0,0 @@ - - -# Storing Annotations # - -Now we are able to create annotations, let's store them using the -[`simple-storage`](modules/sdk/simple-storage.html) module. In -this chapter we will cover three topics relating to persistent storage: - -* using `simple-storage` to persist objects -* handling exhaustion of the storage quota allocated to you -* respecting Private Browsing - -## Storing New Annotations ## - -In this section we are only touching the `main.js` file. - -First, import the `simple-storage` module with a declaration like: - - var simpleStorage = require('sdk/simple-storage'); - -In the module scope, initialize an array which will contain the stored annotations: - - if (!simpleStorage.storage.annotations) - simpleStorage.storage.annotations = []; - -Now we'll add a function to the module scope which deals with a new -annotation. The annotation is composed of the text the user entered and the -"annotation anchor", which consists of the URL, element ID and element content: - - function handleNewAnnotation(annotationText, anchor) { - var newAnnotation = new Annotation(annotationText, anchor); - simpleStorage.storage.annotations.push(newAnnotation); - } - -This function calls a constructor for an `Annotation` object, which we also -need to supply: - - function Annotation(annotationText, anchor) { - this.annotationText = annotationText; - this.url = anchor[0]; - this.ancestorId = anchor[1]; - this.anchorText = anchor[2]; - } - -Now we need to link this code to the annotation editor, so that when the user -presses the return key in the editor, we create and store the new annotation: - - var annotationEditor = panels.Panel({ - width: 220, - height: 220, - contentURL: data.url('editor/annotation-editor.html'), - contentScriptFile: data.url('editor/annotation-editor.js'), - onMessage: function(annotationText) { - if (annotationText) - handleNewAnnotation(annotationText, this.annotationAnchor); - annotationEditor.hide(); - }, - onShow: function() { - this.postMessage('focus'); - } - }); - -## Listing Stored Annotations ## - -To prove that this works, let's implement the part of the add-on that displays -all the previously entered annotations. This is implemented as a panel that's -shown in response to the widget's `right-click` message. - -The panel has three new files associated with it: - -* a content-script which builds the panel content -* a simple HTML file used as a template for the panel's content -* a simple CSS file to provide some basic styling. - -These three files can all go in a new subdirectory of `data` which we will call `list`. - -### Annotation List Content Script ### - -Here's the annotation list's content script: - - self.on("message", function onMessage(storedAnnotations) { - var annotationList = $('#annotation-list'); - annotationList.empty(); - storedAnnotations.forEach( - function(storedAnnotation) { - var annotationHtml = $('#template .annotation-details').clone(); - annotationHtml.find('.url').text(storedAnnotation.url) - .attr('href', storedAnnotation.url); - annotationHtml.find('.url').bind('click', function(event) { - event.stopPropagation(); - event.preventDefault(); - self.postMessage(storedAnnotation.url); - }); - annotationHtml.find('.selection-text') - .text(storedAnnotation.anchorText); - annotationHtml.find('.annotation-text') - .text(storedAnnotation.annotationText); - annotationList.append(annotationHtml); - }); - }); - -It builds the DOM for the panel from the array of annotations it is given. - -The user will be able to click links in the panel, but we want to open them in -the main browser window rather than the panel. So the content script binds a -click handler to the links which will send the URL to the add-on. - -Save this file in `data/list` as `annotation-list.js`. - -### Annotation List HTML and CSS ### - -Here's the HTML for the annotation list: - -
-<html>
-<head>
-  <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
-  <title>Saved annotations</title>
-  <link rel="stylesheet" type="text/css" href="annotation-list.css" />
-</head>
-
-<body>
-
-<div id="annotation-list">
-</div>
-
-<div id="template">
-  <div class="annotation-details">
-    <a class="url"></a>
-    <div class="selection-text"></div>
-    <div class="annotation-text"></div>
-  </div>
-</div>
-
-</body>
-
-</html>
-
-
- -Here's the corresponding CSS: - - - -Save these in `data/list` as `annotation-list.html` and `annotation-list.css` -respectively. - -### Updating main.js ### - -Here's the code to create the panel, which can go in the `main` function. - - var annotationList = panels.Panel({ - width: 420, - height: 200, - contentURL: data.url('list/annotation-list.html'), - contentScriptFile: [data.url('jquery-1.4.2.min.js'), - data.url('list/annotation-list.js')], - contentScriptWhen: 'ready', - onShow: function() { - this.postMessage(simpleStorage.storage.annotations); - }, - onMessage: function(message) { - require('sdk/tabs').open(message); - } - }); - -Since this panel's content script uses jQuery we will pass that in too: again, -make sure the name of it matches the version of jQuery you downloaded. - -When the panel is shown we send it the array of stored annotations. When the -panel sends us a URL we use the `tabs` module to open it in a new tab. - -Finally we need to connect this to the widget's `right-click` message: - - 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'); - annotationList.show(); - }); - -This time execute `cfx xpi` to build the XPI for the add-on, and install it in -Firefox. Activate the add-on, add an annotation, and then right-click the -widget. You should see something like this: - -Annotation List -
- - -Until now we've always run `cfx run` rather than building an XPI and installing -the add-on in Firefox. If the annotation does not reappear when you restart -Firefox, double check you installed the add-on and didn't just use `cfx run` -again. -Restart Firefox, right-click the widget again, and check that the annotation -is still there. - -## Responding To OverQuota events ## - -Add-ons have a limited quota of storage space. If the add-on exits while -it is over quota, any data stored since the last time it was in quota will not -be persisted. - -So we want to listen to the `OverQuota` event emitted by `simple-storage` and -respond to it. Add the following to your add-on's `main` function: - - simpleStorage.on("OverQuota", function () { - notifications.notify({ - title: 'Storage space exceeded', - text: 'Removing recent annotations'}); - while (simpleStorage.quotaUsage > 1) - simpleStorage.storage.annotations.pop(); - }); - -Because we use a notification to alert the user, we need to import the -`notifications` module: - - var notifications = require("sdk/notifications"); - -(It should be obvious that this is an incredibly unhelpful way to deal with the -problem. A real add-on should give the user a chance to choose which data to -keep, and prevent the user from adding any more data until the add-on is back -under quota.) - -## Respecting Private Browsing ## - -Since annotations record the user's browsing history we should avoid recording -annotations in private windows. - -There's a very simple way to do this: do nothing. By omitting the -[`"private-browsing"` key](dev-guide/package-spec.html#permissions) from the -annotator's "package.json" file, the annotator opts out of private browsing -altogether. - -This means that its widget will not appear on any private windows and its -selector and matcher content scripts won't run, so the user won't be able to -enter any annotations in private windows. - -Try it: execute cfx run and open a new private window: you should no longer -see the annotator's widget. - -Now we can create and store annotations, the last piece is to -[display them when the user loads the page](dev-guide/tutorials/annotator/displaying.html). \ No newline at end of file diff --git a/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/widget.md b/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/widget.md deleted file mode 100644 index 605e062f027e..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/tutorials/annotator/widget.md +++ /dev/null @@ -1,115 +0,0 @@ - - -# Implementing the Widget # - -We want the widget to do two things: - - -[Bug 634712](https://bugzilla.mozilla.org/show_bug.cgi?id=634712) asks that -the widget API should emit separate, or at least distinguishable, events for -left and right mouse clicks, and when it is fixed this widget won't need a -content script any more. - -* On a left-click, the widget should activate or deactivate the annotator. -* On a right-click, the widget should display a list of all the annotations -the user has created. - -Because the widget's `click` event does not distinguish left and right mouse -clicks, we'll use a content script to capture the click events and send the -corresponding message back to our add-on. - -The widget will have two icons: one to display when it's active, one to display -when it's inactive. - -So there are three files we'll need to create: the widget's content script and -its two icons. - -Inside the `data` subdirectory create another subdirectory `widget`. We'll -keep the widget's files here. (Note that this isn't mandatory: you could just -keep them all under `data`. But it seems tidier this way.) - -## The Widget's Content Script ## - -The widget's content script just listens for left- and right- mouse clicks and -posts the corresponding message to the add-on code: - - 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); - -Save this in your `data/widget` directory as `widget.js`. - -## The Widget's Icons ## - -You can copy the widget's icons from here: - -Active Annotator -Inactive Annotator - -(Or make your own if you're feeling creative.) Save them in your `data/widget` directory. - -## main.js ## - -Now in the `lib` directory open `main.js` and add the following code: - - 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'); - }); - } - -The annotator is inactive by default. It creates the widget and responds to -messages from the widget's content script by toggling its activation state. -Note that due to -[bug 626326](https://bugzilla.mozilla.org/show_bug.cgi?id=626326) the add-on -bar's context menu is displayed, despite the `event.preventDefault()` call -in the widget's content script. -Since we don't have any code to display annotations yet, we just log the -right-click events to the console. - -Now from the `annotator` directory type `cfx run`. You should see the widget -in the add-on bar: - -
-Widget Icon -
-
- -Left- and right-clicks should produce the appropriate debug output, and a -left-click should also change the widget icon to signal that it is active. - -Next we'll add the code to -[create annotations](dev-guide/tutorials/annotator/creating.html). diff --git a/addon-sdk/source/doc/dev-guide-source/tutorials/chrome.md b/addon-sdk/source/doc/dev-guide-source/tutorials/chrome.md deleted file mode 100644 index bb1d4d28d6e4..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/tutorials/chrome.md +++ /dev/null @@ -1,105 +0,0 @@ - - -
The API used to gain Chrome access is currently an -experimental feature of the SDK, and may change in future releases.
- -# Chrome Authority # - -## Using Chrome Authority ## - -The most powerful low-level modules are run with "chrome privileges", -which gives them access to the infamous Components object, which -grants unfettered access to the host system. From this, the module can do -pretty much anything the browser is capable of. To obtain these privileges, -the module must declare its intent with a statement like the following: - - var {Cc, Ci} = require("chrome"); - -The object returned by require("chrome"), when unpacked with the -"destructuring assignment" feature available in the Mozilla JS environment, -will provide the usual Components.* aliases: - -**Cc** - -An alias for `Components.classes`. - -**Ci** - -An alias for `Components.interfaces`. - -**Cu** - -An alias for `Components.utils`. - -**Cr** - -An alias for `Components.results`. - -**Cm** - -An alias for `Components.manager`. - -**components** - -An alias for `Components` itself (note the lower-case). From this you can -access less-frequently-used properties like `Components.stack` and -`Components.isSuccessCode`. - -Note: the `require("chrome")` statement is the **only** way to access chrome -functionality and the `Components` API. The `Components` object should -**not** be accessed from modules. The SDK tools will emit a warning -if it sees module code which references `Components` directly. - -Your modules should refrain from using chrome privileges unless they are -absolutely necessary. Chrome-authority-using modules must receive extra -security review, and most bugs in these modules are security-critical. - -## Manifest Generation ## - -The **manifest** is a list, included in the generated XPI, which -specifies which modules have requested `require()` access to which other -modules. It also records which modules have requested chrome access. This -list is generated by scanning all included modules for `require(XYZ)` -statements and recording the particular "XYZ" strings that they reference. - -When the manifest implementation is complete the runtime loader will actually -prevent modules from `require()`ing modules that are not listed in the -manifest. Likewise, it will prevent modules from getting chrome authority -unless the manifest indicates that they have asked for it. This will ensure -that reviewers see the same authority restrictions that are enforced upon the -running code, increasing the effectiveness of the time spent reviewing the -add-on. (until this work is complete, modules may be able to sneak around these -restrictions). - -The manifest is built with a simple regexp-based scanner, not a full -Javascript parser. Developers should stick to simple `require` statements, -with a single static string, one per line of code. If the scanner fails to -see a `require` entry, the manifest will not include that entry, and (once -the implementation is complete) the runtime code will get an exception. - -For example, none of the following code will be matched by the manifest -scanner, leading to exceptions at runtime, when the `require()` call is -prohibited from importing the named modules: - - // all of these will fail! - var xhr = require("x"+"hr"); - var modname = "xpcom"; - var xpcom = require(modname); - var one = require("one"); var two = require("two"); - -The intention is that developers use `require()` statements for two purposes: -to declare (to security reviewers) what sorts of powers the module wants to -use, and to control how those powers are mapped into the module's local -namespace. Their statements must therefore be clear and easy to parse. A -future manifest format may move the declaration portion out to a separate -file, to allow for more fine-grained expression of authority. - -Commands that build a manifest, like "`cfx xpi`" or "`cfx run`", will scan -all included modules for use of `Cc`/`Ci` aliases (or the expanded -`Components.classes` forms). It will emit a warning if it sees the expanded -forms, or if it sees a use of e.g. "`Cc`" without a corresponding entry in -the `require("chrome")` statement. These warnings will serve to guide -developers to use the correct pattern. All module developers should heed the -warnings and correct their code until the warnings go away. diff --git a/addon-sdk/source/doc/dev-guide-source/tutorials/display-a-popup.md b/addon-sdk/source/doc/dev-guide-source/tutorials/display-a-popup.md deleted file mode 100644 index 70d8c7d37cc7..000000000000 --- a/addon-sdk/source/doc/dev-guide-source/tutorials/display-a-popup.md +++ /dev/null @@ -1,151 +0,0 @@ - - -# Display a Popup # - - -To follow this tutorial you'll need to have -[installed the SDK](dev-guide/tutorials/installation.html) -and learned the -[basics of `cfx`](dev-guide/tutorials/getting-started-with-cfx.html). - - -To display a popup dialog, use the -[`panel`](modules/sdk/panel.html) module. A panel's content is -defined using HTML. You can run content scripts in the panel: although the -script running in the panel can't directly access your main add-on code, -you can exchange messages between the panel script and the add-on code. - - - -In this tutorial we'll create an add-on that -[adds a widget to the toolbar](dev-guide/tutorials/adding-toolbar-button.html) -which displays a panel when clicked. - -The panel just contains a -`