diff options
Diffstat (limited to 'tools/addon-sdk-1.4/packages/addon-kit')
66 files changed, 0 insertions, 17540 deletions
diff --git a/tools/addon-sdk-1.4/packages/addon-kit/README.md b/tools/addon-sdk-1.4/packages/addon-kit/README.md deleted file mode 100644 index 9a68554..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/README.md +++ /dev/null @@ -1,8 +0,0 @@ -The addon-kit package provides high-level APIs for add-on developers. -Most of the needs of most add-on developers should be served by the modules -found here. Modules in this packages don't require any special privileges to -run. - -The modules in the addon-kit package are relatively stable. We intend to add -new APIs here and extend existing ones, but will avoid making incompatible -changes to them unless absolutely necessary. diff --git a/tools/addon-sdk-1.4/packages/addon-kit/data/moz_favicon.ico b/tools/addon-sdk-1.4/packages/addon-kit/data/moz_favicon.ico Binary files differdeleted file mode 100644 index d444389..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/data/moz_favicon.ico +++ /dev/null diff --git a/tools/addon-sdk-1.4/packages/addon-kit/data/test-page-mod.html b/tools/addon-sdk-1.4/packages/addon-kit/data/test-page-mod.html deleted file mode 100644 index 9211698..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/data/test-page-mod.html +++ /dev/null @@ -1,8 +0,0 @@ -<html> -<head> - <title>Page Mod test</title> -</head> -<body> - <p id="paragraph">Lorem ipsum dolor sit amet.</p> -</body> -</html> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/data/test-page-worker.html b/tools/addon-sdk-1.4/packages/addon-kit/data/test-page-worker.html deleted file mode 100644 index e89a283..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/data/test-page-worker.html +++ /dev/null @@ -1,8 +0,0 @@ -<html> -<head> - <title>Page Worker test</title> -</head> -<body> - <p id="paragraph">Lorem ipsum dolor sit amet.</p> -</body> -</html> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/data/test-page-worker.js b/tools/addon-sdk-1.4/packages/addon-kit/data/test-page-worker.js deleted file mode 100644 index d8effb9..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/data/test-page-worker.js +++ /dev/null @@ -1,25 +0,0 @@ - -// get title directly -self.postMessage(["assertEqual", document.title, "Page Worker test", - "Correct page title accessed directly"]); - -// get <p> directly -let p = document.getElementById("paragraph"); -self.postMessage(["assert", !!p, "<p> can be accessed directly"]); -self.postMessage(["assertEqual", p.firstChild.nodeValue, - "Lorem ipsum dolor sit amet.", - "Correct text node expected"]); - -// Modify page -let div = document.createElement("div"); -div.setAttribute("id", "block"); -div.appendChild(document.createTextNode("Test text created")); -document.body.appendChild(div); - -// Check back the modification -div = document.getElementById("block"); -self.postMessage(["assert", !!div, "<div> can be accessed directly"]); -self.postMessage(["assertEqual", div.firstChild.nodeValue, - "Test text created", "Correct text node expected"]); -self.postMessage(["done"]); - diff --git a/tools/addon-sdk-1.4/packages/addon-kit/data/test-request-invalid.json b/tools/addon-sdk-1.4/packages/addon-kit/data/test-request-invalid.json deleted file mode 100644 index 35f9ff6..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/data/test-request-invalid.json +++ /dev/null @@ -1 +0,0 @@ -"this": "isn't JSON" diff --git a/tools/addon-sdk-1.4/packages/addon-kit/data/test-request.json b/tools/addon-sdk-1.4/packages/addon-kit/data/test-request.json deleted file mode 100644 index 8c850a5..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/data/test-request.json +++ /dev/null @@ -1 +0,0 @@ -{ "foo": "bar" } diff --git a/tools/addon-sdk-1.4/packages/addon-kit/data/test-request.txt b/tools/addon-sdk-1.4/packages/addon-kit/data/test-request.txt deleted file mode 100644 index 390125d..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/data/test-request.txt +++ /dev/null @@ -1 +0,0 @@ -Look ma, no hands! diff --git a/tools/addon-sdk-1.4/packages/addon-kit/data/test.html b/tools/addon-sdk-1.4/packages/addon-kit/data/test.html deleted file mode 100644 index 39de477..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/data/test.html +++ /dev/null @@ -1,8 +0,0 @@ -<html> - <head> - <title>foo</title> - </head> - <body> - <p>bar</p> - </body> -</html> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/clipboard.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/clipboard.md deleted file mode 100644 index 7292017..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/clipboard.md +++ /dev/null @@ -1,58 +0,0 @@ -<!-- contributed by Dietrich Ayala [dietrich@mozilla.com] --> - -The `clipboard` module allows callers to interact with the system clipboard, -setting and retrieving its contents. - -You can optionally specify the type of the data to set and retrieve. -The following types are supported: - -* `text` (plain text) -* `html` (a string of HTML) - -If no data type is provided, then the module will detect it for you. - -Examples --------- - -Set and get the contents of the clipboard. - - let clipboard = require("clipboard"); - clipboard.set("Lorem ipsum dolor sit amet"); - let contents = clipboard.get(); - -Set the clipboard contents to some HTML. - - let clipboard = require("clipboard"); - clipboard.set("<blink>Lorem ipsum dolor sit amet</blink>", "html"); - -If the clipboard contains HTML content, open it in a new tab. - - let clipboard = require("clipboard"); - if (clipboard.currentFlavors.indexOf("html") != -1) - require("tabs").open("data:text/html," + clipboard.get("html")); - -<api name="set"> -@function - Replace the contents of the user's clipboard with the provided data. -@param data {string} - The data to put on the clipboard. -@param [datatype] {string} - The type of the data (optional). -</api> - -<api name="get"> -@function - Get the contents of the user's clipboard. -@param [datatype] {string} - Retrieve the clipboard contents only if matching this type (optional). - The function will return null if the contents of the clipboard do not match - the supplied type. -</api> - -<api name="currentFlavors"> -@property {array} - Data on the clipboard is sometimes available in multiple types. For example, - HTML data might be available as both a string of HTML (the `html` type) - and a string of plain text (the `text` type). This function returns an array - of all types in which the data currently on the clipboard is available. -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/context-menu.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/context-menu.md deleted file mode 100644 index f2bb5b3..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/context-menu.md +++ /dev/null @@ -1,702 +0,0 @@ -<!-- contributed by Drew Willcoxon [adw@mozilla.com] --> -<!-- edited by Noelle Murata [fiveinchpixie@gmail.com] --> - -The `context-menu` module lets you add items to Firefox's page context menu. - - -Introduction ------------- - -The `context-menu` API provides a simple, declarative way to add items to the -page's context menu. You can add items that perform an action when clicked, -submenus, and menu separators. - -Instead of manually adding items when particular contexts occur and then -removing them when those contexts go away, you *bind* items to contexts, and the -adding and removing is automatically handled for you. Items are bound to -contexts in much the same way that event listeners are bound to events. When -the user invokes the context menu, all of the items bound to the current context -are automatically added to the menu. If no items are bound, none are added. -Likewise, any items that were previously in the menu but are not bound to the -current context are automatically removed from the menu. You never need to -manually remove your items from the menu unless you want them to never appear -again. - -For example, if your add-on needs to add a context menu item whenever the -user visits a certain page, don't create the item when that page loads, and -don't remove it when the page unloads. Rather, create your item only once and -supply a context that matches the target URL. - - -Specifying Contexts -------------------- - -As its name implies, the context menu should be reserved for the occurrence of -specific contexts. Contexts can be related to page content or the page itself, -but they should never be external to the page. - -For example, a good use of the menu would be to show an "Edit Image" item when -the user right-clicks an image in the page. A bad use would be to show a -submenu that listed all the user's tabs, since tabs aren't related to the page -or the node the user clicked to open the menu. - -### The Page Context - -First of all, you may not need to specify a context at all. When an item does -not specify a context, the page context applies. - -The *page context* occurs when the user invokes the context menu on a -non-interactive portion of the page. Try right-clicking a blank spot in this -page, or on text. Make sure that no text is selected. The menu that appears -should contain the items "Back", "Forward", "Reload", "Stop", and so on. This -is the page context. - -The page context is appropriate when your item acts on the page as a whole. It -does not occur when the user invokes the context menu on a link, image, or other -non-text node, or while a selection exists. - -### Declarative Contexts - -You can specify some simple, declarative contexts when you create a menu item by -setting the `context` property of the options object passed to its constructor, -like this: - - var cm = require("context-menu"); - cm.Item({ - label: "My Menu Item", - context: cm.URLContext("*.mozilla.org") - }); - -These contexts may be specified by calling the following constructors. Each is -exported by the `context-menu` module. - -<table> - <tr> - <th>Constructor</th> - <th>Description</th> - </tr> - <tr> - <td><code> - PageContext() - </code></td> - <td> - The page context. - </td> - </tr> - <tr> - <td><code> - SelectionContext() - </code></td> - <td> - This context occurs when the menu is invoked on a page in which the user - has made a selection. - </td> - </tr> - <tr> - <td><code> - SelectorContext(selector) - </code></td> - <td> - This context occurs when the menu is invoked on a node that either matches - <code>selector</code>, a CSS selector, or has an ancestor that matches. - <code>selector</code> may include multiple selectors separated by commas, - e.g., <code>"a[href], img"</code>. - </td> - </tr> - <tr> - <td><code> - URLContext(matchPattern) - </code></td> - <td> - This context occurs when the menu is invoked on pages with particular - URLs. <code>matchPattern</code> is a match pattern string or an array of - match pattern strings. When <code>matchPattern</code> is an array, the - context occurs when the menu is invoked on a page whose URL matches any of - the patterns. These are the same match pattern strings that you use with - the <a href="packages/addon-kit/docs/page-mod.html"><code>page-mod</code></a> - <code>include</code> property. - <a href="packages/api-utils/docs/match-pattern.html">Read more about patterns</a>. - </td> - </tr> - <tr> - <td> - array - </td> - <td> - An array of any of the other types. This context occurs when all contexts - in the array occur. - </td> - </tr> -</table> - -Menu items also have a `context` property that can be used to add and remove -declarative contexts after construction. For example: - - var context = require("context-menu").SelectorContext("img"); - myMenuItem.context.add(context); - myMenuItem.context.remove(context); - -When a menu item is bound to more than one context, it appears in the menu when -all of those contexts occur. - -### In Content Scripts - -The declarative contexts are handy but not very powerful. For instance, you -might want your menu item to appear for any page that has at least one image, -but declarative contexts won't help you there. - -When you need more control control over the context in which your menu items are -shown, you can use content scripts. Like other APIs in the SDK, the -`context-menu` API uses -[content scripts](dev-guide/addon-development/web-content.html) to let your -add-on interact with pages in the browser. Each menu item you create in the -top-level context menu can have a content script. - -A special event named `"context"` is emitted in your content scripts whenever -the context menu is about to be shown. If you register a listener function for -this event and it returns true, the menu item associated with the listener's -content script is shown in the menu. - -For example, this item appears whenever the context menu is invoked on a page -that contains at least one image: - - require("context-menu").Item({ - label: "This Page Has Images", - contentScript: 'self.on("context", function (node) {' + - ' return !!document.querySelector("img");' + - '});' - }); - -Note that the listener function has a parameter called `node`. This is the node -in the page that the user context-clicked to invoke the menu. You can use it to -determine whether your item should be shown. - -You can both specify declarative contexts and listen for contexts in a content -script. In that case, the declarative contexts are evaluated first. If they -are not current, then your context listener is never called. - -This example takes advantage of that fact. The listener can be assured that -`node` will always be an image: - - require("context-menu").Item({ - label: "A Mozilla Image", - context: contextMenu.SelectorContext("img"), - contentScript: 'self.on("context", function (node) {' + - ' return /mozilla/.test(node.src);' + - '});' - }); - -Your item is shown only when all declarative contexts are current and your -context listener returns true. - - -Handling Menu Item Clicks -------------------------- - -In addition to using content scripts to listen for the `"context"` event as -described above, you can use content scripts to handle item clicks. When the -user clicks your menu item, an event named `"click"` is emitted in the item's -content script. - -Therefore, to handle an item click, listen for the `"click"` event in that -item's content script like so: - - require("context-menu").Item({ - label: "My Item", - contentScript: 'self.on("click", function (node, data) {' + - ' console.log("Item clicked!");' + - '});' - }); - -Note that the listener function has parameters called `node` and `data`. `node` -is the node that the user context-clicked to invoke the menu. You can use it -when performing some action. `data` is the `data` property of the menu item -that was clicked. Since only top-level menu items have content scripts, this -comes in handy for determining which item in a `Menu` was clicked: - - var cm = require("context-menu"); - cm.Menu({ - label: "My Menu", - contentScript: 'self.on("click", function (node, data) {' + - ' console.log("You clicked " + data);' + - '});', - items: [ - cm.Item({ label: "Item 1", data: "item1" }), - cm.Item({ label: "Item 2", data: "item2" }), - cm.Item({ label: "Item 3", data: "item3" }) - ] - }); - -Often you will need to collect some kind of information in the click listener -and perform an action unrelated to content. To communicate to the menu item -associated with the content script, the content script can call the -`postMessage` function attached to the global `self` object, passing it some -JSON-able data. The menu item's `"message"` event listener will be called with -that data. - - require("context-menu").Item({ - label: "Edit Image", - context: contextMenu.SelectorContext("img"), - contentScript: 'self.on("click", function (node, data) {' + - ' self.postMessage(node.src);' + - '});', - onMessage: function (imgSrc) { - openImageEditor(imgSrc); - } - }); - - -Updating a Menu Item's Label ----------------------------- - -Each menu item must be created with a label, but you can change its label later -using a couple of methods. - -The simplest method is to set the menu item's `label` property. This example -updates the item's label based on the number of times it's been clicked: - - var numClicks = 0; - var myItem = require("context-menu").Item({ - label: "Click Me: " + numClicks, - contentScript: 'self.on("click", self.postMessage);', - onMessage: function () { - numClicks++; - this.label = "Click Me: " + numClicks; - // Setting myItem.label is equivalent. - } - }); - -Sometimes you might want to update the label based on the context. For -instance, if your item performs a search with the user's selected text, it would -be nice to display the text in the item to provide feedback to the user. In -these cases you can use the second method. Recall that your content scripts can -listen for the `"context"` event and if your listeners return true, the items -associated with the content scripts are shown in the menu. In addition to -returning true, your `"context"` listeners can also return strings. When a -`"context"` listener returns a string, it becomes the item's new label. - -This item implements the aforementioned search example: - - var cm = require("context-menu"); - cm.Item({ - label: "Search Google", - context: cm.SelectionContext(), - contentScript: 'self.on("context", function () {' + - ' var text = window.getSelection().toString();' + - ' if (text.length > 20)' + - ' text = text.substr(0, 20) + "...";' + - ' return "Search Google for " + text;' + - '});' - }); - -The `"context"` listener gets the window's current selection, truncating it if -it's too long, and includes it in the returned string. When the item is shown, -its label will be "Search Google for `text`", where `text` is the truncated -selection. - - -More Examples -------------- - -For conciseness, these examples create their content scripts as strings and use -the `contentScript` property. In your own add-on, you will probably want to -create your content scripts in separate files and pass their URLs using the -`contentScriptFile` property. See -[Working with Content Scripts](dev-guide/addon-development/web-content.html) -for more information. - -Show an "Edit Page Source" item when the user right-clicks a non-interactive -part of the page: - - require("context-menu").Item({ - label: "Edit Page Source", - contentScript: 'self.on("click", function (node, data) {' + - ' self.postMessage(document.URL);' + - '});', - onMessage: function (pageURL) { - editSource(pageURL); - } - }); - -Show an "Edit Image" item when the menu is invoked on an image: - - require("context-menu").Item({ - label: "Edit Image", - context: contextMenu.SelectorContext("img"), - contentScript: 'self.on("click", function (node, data) {' + - ' self.postMessage(node.src);' + - '});', - onMessage: function (imgSrc) { - openImageEditor(imgSrc); - } - }); - -Show an "Edit Mozilla Image" item when the menu is invoked on an image in a -mozilla.org or mozilla.com page: - - var cm = require("context-menu"); - cm.Item({ - label: "Edit Mozilla Image", - context: [ - cm.URLContext(["*.mozilla.org", "*.mozilla.com"]), - cm.SelectorContext("img") - ], - contentScript: 'self.on("click", function (node, data) {' + - ' self.postMessage(node.src);' + - '});', - onMessage: function (imgSrc) { - openImageEditor(imgSrc); - } - }); - -Show an "Edit Page Images" item when the page contains at least one image: - - require("context-menu").Item({ - label: "Edit Page Images", - // This ensures the item only appears during the page context. - context: contextMenu.PageContext(), - contentScript: 'self.on("context", function (node) {' + - ' var pageHasImgs = !!document.querySelector("img");' + - ' return pageHasImgs;' + - '});' + - 'self.on("click", function (node, data) {' + - ' var imgs = document.querySelectorAll("img");' + - ' var imgSrcs = [];' + - ' for (var i = 0 ; i < imgs.length; i++)' + - ' imgSrcs.push(imgs[i].src);' + - ' self.postMessage(imgSrcs);' + - '});', - onMessage: function (imgSrcs) { - openImageEditor(imgSrcs); - } - }); - -Show a "Search With" menu when the user right-clicks an anchor that searches -Google or Wikipedia with the text contained in the anchor: - - var cm = require("context-menu"); - var googleItem = cm.Item({ - label: "Google", - data: "http://www.google.com/search?q=" - }); - var wikipediaItem = cm.Item({ - label: "Wikipedia", - data: "http://en.wikipedia.org/wiki/Special:Search?search=" - }); - var searchMenu = cm.Menu({ - label: "Search With", - context: contextMenu.SelectorContext("a[href]"), - contentScript: 'self.on("click", function (node, data) {' + - ' var searchURL = data + node.textContent;' + - ' window.location.href = searchURL;' + - '});', - items: [googleItem, wikipediaItem] - }); - - -<api name="Item"> -@class -A labeled menu item that can perform an action when clicked. -<api name="Item"> -@constructor - Creates a labeled menu item that can perform an action when clicked. -@param options {object} - An object with the following keys: - @prop label {string} - The item's label. It must either be a string or an object that implements - `toString()`. - @prop [image] {string} - The item's icon, a string URL. The URL can be remote, a reference to an - image in the add-on's `data` directory, or a data URI. - @prop [data] {string} - An optional arbitrary value to associate with the item. It must be either a - string or an object that implements `toString()`. It will be passed to - click listeners. - @prop [context] {value} - If the item is contained in the top-level context menu, this declaratively - specifies the context under which the item will appear; see Specifying - Contexts above. Ignored if the item is contained in a submenu. - @prop [contentScript] {string,array} - If the item is contained in the top-level context menu, this is the content - script or an array of content scripts that the item can use to interact with - the page. Ignored if the item is contained in a submenu. - @prop [contentScriptFile] {string,array} - If the item is contained in the top-level context menu, this is the local - file URL of the content script or an array of such URLs that the item can - use to interact with the page. Ignored if the item is contained in a - submenu. - @prop [onMessage] {function} - If the item is contained in the top-level context menu, this function will - be called when the content script calls `self.postMessage`. It will be - passed the data that was passed to `postMessage`. Ignored if the item is - contained in a submenu. -</api> - -<api name="label"> -@property {string} - The menu item's label. You can set this after creating the item to update its - label later. -</api> - -<api name="image"> -@property {string} - The item's icon, a string URL. The URL can be remote, a reference to an image - in the add-on's `data` directory, or a data URI. You can set this after - creating the item to update its image later. To remove the item's image, set - it to `null`. -</api> - -<api name="data"> -@property {string} - An optional arbitrary value to associate with the item. It must be either a - string or an object that implements `toString()`. It will be passed to - click listeners. You can set this after creating the item to update its data - later. -</api> - -<api name="context"> -@property {list} - A list of declarative contexts for which the menu item will appear in the - context menu. Contexts can be added by calling `context.add()` and removed by - called `context.remove()`. This property is meaningful only for items - contained in the top-level context menu. -</api> - -<api name="parentMenu"> -@property {Menu} - The item's parent `Menu`, or `null` if the item is contained in the top-level - context menu. This property is read-only. To add the item to a new menu, - call that menu's `addItem()` method. -</api> - -<api name="contentScript"> -@property {string,array} - The content script or the array of content scripts associated with the menu - item during creation. This property is meaningful only for items contained in - the top-level context menu. -</api> - -<api name="contentScriptFile"> -@property {string,array} - The URL of a content script or the array of such URLs associated with the menu - item during creation. This property is meaningful only for items contained in - the top-level context menu. -</api> - -<api name="destroy"> -@method - Permanently removes the item from its parent menu and frees its resources. - The item must not be used afterward. If you need to remove the item from its - parent menu but use it afterward, call `removeItem()` on the parent menu - instead. -</api> - -<api name="message"> -@event -If you listen to this event you can receive message events from content -scripts associated with this menu item. When a content script posts a -message using `self.postMessage()`, the message is delivered to the add-on -code in the menu item's `message` event. - -@argument {value} -Listeners are passed a single argument which is the message posted -from the content script. The message can be any -<a href = "dev-guide/addon-development/content-scripts/using-port.html#json_serializable">JSON-serializable value</a>. -</api> - -</api> - -<api name="Menu"> -@class -A labeled menu item that expands into a submenu. - -<api name="Menu"> -@constructor - Creates a labeled menu item that expands into a submenu. -@param options {object} - An object with the following keys: - @prop label {string} - The item's label. It must either be a string or an object that implements - `toString()`. - @prop items {array} - An array of menu items that the menu will contain. Each must be an `Item`, - `Menu`, or `Separator`. - @prop [image] {string} - The menu's icon, a string URL. The URL can be remote, a reference to an - image in the add-on's `data` directory, or a data URI. - @prop [context] {value} - If the menu is contained in the top-level context menu, this declaratively - specifies the context under which the menu will appear; see Specifying - Contexts above. Ignored if the menu is contained in a submenu. - @prop [contentScript] {string,array} - If the menu is contained in the top-level context menu, this is the content - script or an array of content scripts that the menu can use to interact with - the page. Ignored if the menu is contained in a submenu. - @prop [contentScriptFile] {string,array} - If the menu is contained in the top-level context menu, this is the local - file URL of the content script or an array of such URLs that the menu can - use to interact with the page. Ignored if the menu is contained in a - submenu. - @prop [onMessage] {function} - If the menu is contained in the top-level context menu, this function will - be called when the content script calls `self.postMessage`. It will be - passed the data that was passed to `postMessage`. Ignored if the item is - contained in a submenu. -</api> - -<api name="label"> -@property {string} - The menu's label. You can set this after creating the menu to update its - label later. -</api> - -<api name="items"> -@property {array} - An array containing the items in the menu. The array is read-only, meaning - that modifications to it will not affect the menu. However, setting this - property to a new array will replace all the items currently in the menu with - the items in the new array. -</api> - -<api name="image"> -@property {string} - The menu's icon, a string URL. The URL can be remote, a reference to an image - in the add-on's `data` directory, or a data URI. You can set this after - creating the menu to update its image later. To remove the menu's image, set - it to `null`. -</api> - -<api name="context"> -@property {list} - A list of declarative contexts for which the menu will appear in the context - menu. Contexts can be added by calling `context.add()` and removed by called - `context.remove()`. This property is meaningful only for menus contained in - the top-level context menu. -</api> - -<api name="parentMenu"> -@property {Menu} - The menu's parent `Menu`, or `null` if the menu is contained in the top-level - context menu. This property is read-only. To add the menu to a new menu, - call that menu's `addItem()` method. -</api> - -<api name="contentScript"> -@property {string,array} - The content script or the array of content scripts associated with the menu - during creation. This property is meaningful only for menus contained in the - top-level context menu. -</api> - -<api name="contentScriptFile"> -@property {string,array} - The URL of a content script or the array of such URLs associated with the menu - during creation. This property is meaningful only for menus contained in the - top-level context menu. -</api> - -<api name="addItem"> -@method - Appends a menu item to the end of the menu. If the item is already contained - in another menu or in the top-level context menu, it's automatically removed - first. -@param item {Item,Menu,Separator} - The `Item`, `Menu`, or `Separator` to add to the menu. -</api> - -<api name="removeItem"> -@method - Removes the given menu item from the menu. If the menu does not contain the - item, this method does nothing. -@param item {Item,Menu,Separator} - The menu item to remove from the menu. -</api> - -<api name="destroy"> -@method - Permanently removes the menu from its parent menu and frees its resources. - The menu must not be used afterward. If you need to remove the menu from its - parent menu but use it afterward, call `removeItem()` on the parent menu - instead. -</api> - -<api name="message"> -@event -If you listen to this event you can receive message events from content -scripts associated with this menu item. When a content script posts a -message using `self.postMessage()`, the message is delivered to the add-on -code in the menu item's `message` event. - -@argument {value} -Listeners are passed a single argument which is the message posted -from the content script. The message can be any -<a href = "dev-guide/addon-development/content-scripts/using-port.html#json_serializable">JSON-serializable value</a>. -</api> - -</api> - -<api name="Separator"> -@class -A menu separator. Separators can be contained only in `Menu`s, not in the -top-level context menu. - -<api name="Separator"> -@constructor - Creates a menu separator. -</api> - -<api name="parentMenu"> -@property {Menu} - The separator's parent `Menu`. This property is read-only. To add the - separator to a new menu, call that menu's `addItem()` method. -</api> - -<api name="destroy"> -@method - Permanently removes the separator from its parent menu and frees its - resources. The separator must not be used afterward. If you need to remove - the separator from its parent menu but use it afterward, call `removeItem()` - on the parent menu instead. -</api> - -</api> - -<api name="PageContext"> -@class -<api name="PageContext"> -@constructor - Creates a page context. See Specifying Contexts above. -</api> -</api> - -<api name="SelectionContext"> -@class -<api name="SelectionContext"> -@constructor - Creates a context that occurs when a page contains a selection. See - Specifying Contexts above. -</api> -</api> - -<api name="SelectorContext"> -@class -<api name="SelectorContext"> -@constructor - Creates a context that matches a given CSS selector. See Specifying Contexts - above. -@param selector {string} - A CSS selector. -</api> -</api> - -<api name="URLContext"> -@class -<api name="URLContext"> -@constructor - Creates a context that matches pages with particular URLs. See Specifying - Contexts above. -@param matchPattern {string,array} - A [match pattern](packages/api-utils/docs/match-pattern.html) string or an array of - match pattern strings. -</api> -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/hotkeys.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/hotkeys.md deleted file mode 100644 index dfbe572..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/hotkeys.md +++ /dev/null @@ -1,74 +0,0 @@ -<!-- contributed by Irakli Gozalishvili [gozala@mozilla.com] --> - -Some add-ons may wish to define keyboard shortcuts for certain operations. This -module exposes an API to create those. - -<api name="Hotkey"> -@class - -Module exports `Hotkey` constructor allowing users to create a `hotkey` for the -host application. - -<api name="Hotkey"> -@constructor -Creates a hotkey who's `onPress` listener method is invoked when key combination -defined by `hotkey` is pressed. - -Please note: If more than one `hotkey` is created for the same key -combination, the listener is executed only on the last one created - -@param options {Object} - Options for the hotkey, with the following keys: - -@prop combo {String} -Any function key: `"f1, f2, ..., f24"` or key combination in the format -of `'modifier-key'`: - - "accel-s" - "meta-shift-i" - "control-alt-d" - -Modifier keynames: - -- **shift**: The Shift key. -- **alt**: The Alt key. On the Macintosh, this is the Option key. On - Macintosh this can only be used in conjunction with another modifier, - since `Alt-Letter` combinations are reserved for entering special - characters in text. -- **meta**: The Meta key. On the Macintosh, this is the Command key. -- **control**: The Control key. -- **accel**: The key used for keyboard shortcuts on the user's platform, - which is Control on Windows and Linux, and Command on Mac. Usually, this - would be the value you would use. - -@prop onPress {Function} -Function that is invoked when the key combination `hotkey` is pressed. - -</api> -<api name="destroy"> -@method -Stops this instance of `Hotkey` from reacting on the key combinations. Once -destroyed it can no longer be used. -</api> -</api> - -## Example ## - - // Define keyboard shortcuts for showing and hiding a custom panel. - var { Hotkey } = require("hotkeys"); - - var showHotKey = Hotkey({ - combo: "accel-shift-o", - onPress: function() { - showMyPanel(); - } - }); - var hideHotKey = Hotkey({ - combo: "accel-alt-shift-o", - onPress: function() { - hideMyPanel(); - } - }); - -[Mozilla keyboard planning FAQ]:http://www.mozilla.org/access/keyboard/ -[keyboard shortcuts]:https://developer.mozilla.org/en/XUL_Tutorial/Keyboard_Shortcuts diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/notifications.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/notifications.md deleted file mode 100644 index 5e76c1b..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/notifications.md +++ /dev/null @@ -1,60 +0,0 @@ -<!-- contributed by Drew Willcoxon [adw@mozilla.com] --> - -The `notifications` module allows you to display transient, -[toaster](http://en.wikipedia.org/wiki/Toast_%28computing%29)-style -desktop messages to the user. - -This API supports desktop notifications on Windows, OS X using -[Growl](http://growl.info/), and Linux using libnotify. If the user's system -does not support desktop notifications or if its notifications service is not -running, then notifications made with this API are logged to Firefox's error -console and, if the user launched Firefox from the command line, the terminal. - -Examples --------- - -Here's a typical example. When the message is clicked, a string is logged to -the console. - - var notifications = require("notifications"); - notifications.notify({ - title: "Jabberwocky", - text: "'Twas brillig, and the slithy toves", - data: "did gyre and gimble in the wabe", - onClick: function (data) { - console.log(data); - // console.log(this.data) would produce the same result. - } - }); - -This one displays an icon that's stored in the add-on's `data` directory. (See -the [`self`](packages/addon-kit/docs/self.html) module documentation for more information.) - - var notifications = require("notifications"); - var self = require("self"); - var myIconURL = self.data.url("myIcon.png"); - notifications.notify({ - text: "I have an icon!", - iconURL: myIconURL - }); - - -<api name="notify"> -@function - Displays a transient notification to the user. -@param options {object} - An object with the following keys. Each is optional. - @prop [title] {string} - A string to display as the message's title. - @prop [text] {string} - A string to display as the body of the message. - @prop [iconURL] {string} - The URL of an icon to display inside the message. It may be a remote URL, - a data URI, or a URL returned by the [`self`](packages/addon-kit/docs/self.html) - module. - @prop [onClick] {function} - A function to be called when the user clicks the message. It will be passed - the value of `data`. - @prop [data] {string} - A string that will be passed to `onClick`. -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/page-mod.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/page-mod.md deleted file mode 100644 index e523d48..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/page-mod.md +++ /dev/null @@ -1,367 +0,0 @@ -<!-- contributed by Nickolay Ponomarev [asqueella@gmail.com] --> -<!-- contributed by Myk Melez [myk@mozilla.org] --> -<!-- contributed by Irakli Gozalishvil [gozala@mozilla.com] --> - -Overview --------- -The page-mod module enables add-on developers to execute scripts in the context -of specific web pages. Most obviously you could use page-mod to dynamically -modify the content of certain pages. - -The module exports a constructor function `PageMod` which creates a new page -modification (or "mod" for short). - -A page mod does not modify its pages until those pages are loaded or reloaded. -In other words, if your add-on is loaded while the user's browser is open, the -user will have to reload any open pages that match the mod for the mod to affect -them. - -To stop a page mod from making any more modifications, call its `destroy` -method. - -Like all modules that interact with web content, page-mod uses content -scripts that execute in the content process and defines a messaging API to -communicate between the content scripts and the main add-on script. For more -details on content scripting see the tutorial on [interacting with web -content](dev-guide/addon-development/web-content.html). - -To create a PageMod the add-on developer supplies: - -* a set of rules to select the desired subset of web pages based on their URL. -Each rule is specified using the -[match-pattern](packages/api-utils/docs/match-pattern.html) syntax. - -* a set of content scripts to execute in the context of the desired pages. - -* a value for the onAttach option: this value is a function which will be -called when a page is loaded that matches the ruleset. This is used to set up a -communication channel between the add-on code and the content script. - -All these parameters are optional except for the ruleset, which must include -at least one rule. - -The following add-on displays an alert whenever a page matching the ruleset is -loaded: - - var pageMod = require("page-mod"); - pageMod.PageMod({ - include: "*.org", - contentScript: 'window.alert("Page matches ruleset");' - }); - -If you specify a value of "ready" or "end" for `contentScriptWhen`, -as opposed to "start", -then the content script can interact with the DOM itself: - - var pageMod = require("page-mod"); - pageMod.PageMod({ - include: "*.org", - contentScriptWhen: 'end', - contentScript: 'document.body.innerHTML = ' + - ' "<h1>Page matches ruleset</h1>";' - }); - -### Using `contentScriptFile` ### - -Most of the examples in this page define content scripts as strings, -and use the `contentScript` option to assign them to page mods. - -In your code you will more often create content scripts in separate files -under your add-on's `data` directory. Then you can use the -[`self`](packages/addon-kit/docs/self.html) module to retrieve a URL pointing -to the file, and assign this to the page-mod's `contentScriptFile` -property. - -For example, if you save the content script -file in your `data` directory as "myScript.js", you would assign it using -code like: - - var data = require("self").data; - - var pageMod = require("page-mod"); - pageMod.PageMod({ - include: "*.org", - contentScriptWhen: 'end', - contentScriptFile: data.url("myScript.js") - }); - -## Communicating With Content Scripts ## - -When a matching page is loaded the `PageMod` will call the function that the -add-on code supplied to `onAttach`. The `PageMod` supplies one argument to -this function: a `worker` object. - -The worker can be thought of as the add-on's end of -a communication channel between the add-on code and the content scripts that -have been attached to this page. - -Thus the add-on can pass messages to the content scripts by calling the -worker's `postMessage` function and can receive messages from the content -scripts by registering a function as a listener to the worker's `on` function. - -Note that if multiple matching pages are loaded simultaneously then each page -is loaded into its own execution context with its own copy of the content -scripts. In this case `onAttach` is called once for each loaded page, and the -add-on code will have a separate worker for each page: - -![Multiple workers](static-files/media/multiple-workers.jpg) - -This is demonstrated in the following example: - - var pageMod = require("page-mod"); - var tabs = require("tabs"); - - var workers = []; - - pageMod.PageMod({ - include: ["http://www.mozilla*"], - contentScriptWhen: 'end', - contentScript: "onMessage = function onMessage(message) {" + - " window.alert(message);};", - onAttach: function onAttach(worker) { - if (workers.push(worker) == 3) { - workers[0].postMessage("The first worker!"); - workers[1].postMessage("The second worker!"); - workers[2].postMessage("The third worker!"); - } - } - }); - - tabs.open("http://www.mozilla.com"); - tabs.open("http://www.mozilla.org"); - tabs.open("http://www.mozilla-europe.org"); - -Here we specify a ruleset to match any URLs starting with -"http://www.mozilla". When a page matches we add the supplied worker to -an array, and when we have three workers in the array we send a message to -each worker in turn, telling it the order in which it was attached. The -worker just displays the message in an alert box. - -This shows that separate pages execute in separate contexts and that each -context has its own communication channel with the add-on script. - -Note though that while there is a separate worker for each execution context, -the worker is shared across all the content scripts associated with a single -execution context. In the following example we pass two content scripts into -the `PageMod`: these content scripts will share a worker instance. - -In the example each content script identifies itself to the add-on script -by sending it a message using the global `postMessage` function. In the -`onAttach` function the add-on code logs the fact that a new page is -attached and registers a listener function that simply logs the message: - - - var pageMod = require("page-mod"); - var data = require("self").data; - var tabs = require("tabs"); - - pageMod.PageMod({ - include: ["http://www.mozilla*"], - contentScriptWhen: 'end', - contentScript: ["postMessage('Content script 1 is attached to '+ " + - "document.URL);", - "postMessage('Content script 2 is attached to '+ " + - "document.URL);"], - onAttach: function onAttach(worker) { - console.log("Attaching content scripts") - worker.on('message', function(data) { - console.log(data); - }); - } - }); - - tabs.open("http://www.mozilla.com"); - -The console output of this add-on is: - -<pre> - info: Attaching content scripts - info: Content script 1 is attached to http://www.mozilla.com/en-US/ - info: Content script 2 is attached to http://www.mozilla.com/en-US/ -</pre> - -### Mapping workers to tabs ### - -The [`worker`](packages/api-utils/docs/content/worker.html) has a `tab` -property which returns the tab associated with this worker. You can use this -to access the [`tabs API`](packages/addon-kit/docs/tabs.html) for the tab -associated with a specific page: - - var pageMod = require("page-mod"); - var tabs = require("tabs"); - - pageMod.PageMod({ - include: ["*"], - onAttach: function onAttach(worker) { - console.log(worker.tab.title); - } - }); - -### Attaching content scripts to tabs ### - -We've seen that the page mod API attaches content scripts to pages based on -their URL. Sometimes, though, we don't care about the URL: we just want -to execute a script on demand in the context of a particular tab. - -For example, we might want to run a script in the context of the currently -active tab when the user clicks a widget: to block certain content, to -change the font style, or to display the page's DOM structure. - -Using the `attach` method of the [`tab`](packages/addon-kit/docs/tabs.html) -object, you can attach a set of content scripts to a particular tab. The -scripts are executed immediately. - -The following add-on creates a widget which, when clicked, highlights all the -`div` elements in the page loaded into the active tab: - - var widgets = require("widget"); - var tabs = require("tabs"); - - var widget = widgets.Widget({ - id: "div-show", - label: "Show divs", - contentURL: "http://www.mozilla.org/favicon.ico", - onClick: function() { - tabs.activeTab.attach({ - contentScript: - 'var divs = document.getElementsByTagName("div");' + - 'for (var i = 0; i < divs.length; ++i) {' + - 'divs[i].setAttribute("style", "border: solid red 1px;");' + - '}' - }); - } - }); - -## Destroying Workers ## - -Workers generate a `detach` event when their associated page is closed: that -is, when the tab is closed or the tab's location changes. If -you are maintaining a list of workers belonging to a page mod, you can use -this event to remove workers that are no longer valid. - -For example, if you maintain a list of workers attached to a page mod: - - var workers = []; - - var pageMod = require("page-mod").PageMod({ - include: ['*'], - contentScriptWhen: 'ready', - contentScriptFile: data.url('pagemod.js'), - onAttach: function(worker) { - workers.push(worker); - } - }); - -You can remove workers when they are no longer valid by listening to `detach`: - - var workers = []; - - function detachWorker(worker, workerArray) { - var index = workerArray.indexOf(worker); - if(index != -1) { - workerArray.splice(index, 1); - } - } - - var pageMod = require("page-mod").PageMod({ - include: ['*'], - contentScriptWhen: 'ready', - contentScriptFile: data.url('pagemod.js'), - onAttach: function(worker) { - workers.push(worker); - worker.on('detach', function () { - detachWorker(this, workers); - }); - } - }); - -<api name="PageMod"> -@class -A PageMod object. Once activated a page mod will execute the supplied content -scripts in the context of any pages matching the pattern specified by the -'include' property. -<api name="PageMod"> -@constructor -Creates a PageMod. -@param options {object} - Options for the PageMod, with the following keys: - @prop include {string,array} - A match pattern string or an array of match pattern strings. These define - the pages to which the PageMod applies. See the - [match-pattern](packages/api-utils/docs/match-pattern.html) module for - a description of match pattern syntax. - At least one match pattern must be supplied. - - @prop [contentScriptFile] {string,array} - The local file URLs of content scripts to load. Content scripts specified - by this option are loaded *before* those specified by the `contentScript` - option. Optional. - @prop [contentScript] {string,array} - The texts of content scripts to load. Content scripts specified by this - option are loaded *after* those specified by the `contentScriptFile` option. - Optional. - @prop [contentScriptWhen="end"] {string} - When to load the content scripts. This may take one of the following - values: - - * "start": load content scripts immediately after the document - element for the page is inserted into the DOM, but before the DOM content - itself has been loaded - * "ready": load content scripts once DOM content has been loaded, - corresponding to the - [DOMContentLoaded](https://developer.mozilla.org/en/Gecko-Specific_DOM_Events) - event - * "end": load content scripts once all the 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 - - This property is optional and defaults to "end". - - @prop [onAttach] {function} -A function to call when the PageMod attaches content scripts to -a matching page. The function will be called with one argument, a `worker` -object which the add-on script can use to communicate with the content scripts -attached to the page in question. - -</api> - -<api name="include"> -@property {List} -A [list](packages/api-utils/docs/list.html) of match pattern strings. These -define the pages to which the page mod applies. See the -[match-pattern](packages/api-utils/docs/match-pattern.html) module for a -description of match patterns. Rules can be added to the list by calling its -`add` method and removed by calling its `remove` method. - -</api> - -<api name="destroy"> -@method -Stops the page mod from making any more modifications. Once destroyed the page -mod can no longer be used. Note that modifications already made to open pages -will not be undone. -</api> - -<api name="attach"> -@event -This event is emitted this event when the page-mod's content scripts are -attached to a page whose URL matches the page-mod's `include` filter. - -@argument {Worker} -The listener function is passed a [`Worker`](packages/api-utils/docs/content/worker.html) object that can be used to communicate -with any content scripts attached to this page. -</api> - -<api name="error"> -@event -This event is emitted when an uncaught runtime error occurs in one of the page -mod's content scripts. - -@argument {Error} -Listeners are passed a single argument, the -[Error](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error) -object. -</api> - -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/page-worker.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/page-worker.md deleted file mode 100644 index 06097ae..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/page-worker.md +++ /dev/null @@ -1,218 +0,0 @@ -<!-- contributed by Felipe Gomes [felipc@gmail.com] --> - -The `page-worker` module provides a way to create a permanent, invisible page -and access its DOM. - -Introduction ------------- - -The module exports a constructor function `Page`, which constructs a new page -worker. A page worker may be destroyed, after which its memory is freed, and -you must create a new instance to load another page. - -Page workers have associated content scripts, which are JavaScript scripts that -have access to the content loaded into the pages. You can specify scripts to -load for a page worker, and you communicate with those scripts over an -asynchronous JSON pipe. For more information on content scripts, see -[Working with Content Scripts](dev-guide/addon-development/web-content.html). - -Examples --------- - -For conciseness, these examples create their content scripts as strings and use -the `contentScript` property. In your own add-ons, you will probably want to -create your content scripts in separate files and pass their URLs using the -`contentScriptFile` property. See -[Working with Content Scripts](dev-guide/addon-development/web-content.html) -for more information. - -### Print all header titles from a Wikipedia article ### - - var pageWorkers = require("page-worker"); - - // This content script sends header titles from the page to the add-on: - var script = "var elements = document.querySelectorAll('h2 > span'); " + - "for (var i = 0; i < elements.length; i++) { " + - " postMessage(elements[i].textContent) " + - "}"; - - // Create a page worker that loads Wikipedia: - pageWorkers.Page({ - contentURL: "http://en.wikipedia.org/wiki/Internet", - contentScript: script, - contentScriptWhen: "ready", - onMessage: function(message) { - console.log(message); - } - }); - -The page worker's "message" event listener, specified by `onMessage`, will print -all the titles it receives from the content script. - -<api name="Page"> -@class -A `Page` object loads the page specified by its `contentURL` option and -executes any content scripts that have been supplied to it in the -`contentScript` and `contentScriptFile` options. - -The page is not displayed to the user. - -The page worker is loaded as soon as the `Page` object is created and stays -loaded until its `destroy` method is called or the add-on is unloaded. - -<api name="Page"> -@constructor - Creates an uninitialized page worker instance. -@param [options] {object} - The *`options`* parameter is optional, and if given it should be an object - with any of the following keys: - @prop [contentURL] {string} - The URL of the content to load in the panel. - @prop [allow] {object} - An object with keys to configure the permissions on the page worker. The - boolean key `script` controls if scripts from the page are allowed to run. - `script` defaults to true. - @prop [contentScriptFile] {string,array} - A local file URL or an array of local file URLs of content scripts to load. - Content scripts specified by this option are loaded *before* those specified - by the `contentScript` option. See - [Working with Content Scripts](dev-guide/addon-development/web-content.html) - for help on setting this property. - @prop [contentScript] {string,array} - A string or an array of strings containing the texts of content scripts to - load. Content scripts specified by this option are loaded *after* those - specified by the `contentScriptFile` option. - @prop [contentScriptWhen="end"] {string} - When to load the content scripts. This may take one of the following - values: - - * "start": load content scripts immediately after the document - element for the page is inserted into the DOM, but before the DOM content - itself has been loaded - * "ready": load content scripts once DOM content has been loaded, - corresponding to the - [DOMContentLoaded](https://developer.mozilla.org/en/Gecko-Specific_DOM_Events) - event - * "end": load content scripts once all the 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 - - This property is optional and defaults to "end". - - @prop [onMessage] {function} - Use this to add a listener to the page worker's `message` event. -</api> - -<api name="port"> -@property {EventEmitter} -[EventEmitter](packages/api-utils/docs/events.html) object that allows you to: - -* send events to the content script using the `port.emit` function -* receive events from the content script using the `port.on` function - -See the guide to -<a href="dev-guide/addon-development/content-scripts/using-port.html"> -communicating using <code>port</code></a> for details. -</api> - -<api name="contentURL"> -@property {string} -The URL of the content loaded. -</api> - -<api name="allow"> -@property {object} - A object describing permissions for the content. It contains a single key - named `script` whose value is a boolean that indicates whether or not to - execute script in the content. `script` defaults to true. -</api> - -<api name="contentScriptFile"> -@property {string,array} -A local file URL or an array of local file URLs of content scripts to load. -</api> - -<api name="contentScript"> -@property {string,array} -A string or an array of strings containing the texts of content scripts to -load. -</api> - -<api name="contentScriptWhen"> -@property {string} - When to load the content scripts. This may have one of the following - values: - - * "start": load content scripts immediately after the document - element for the page is inserted into the DOM, but before the DOM content - itself has been loaded - * "ready": load content scripts once DOM content has been loaded, - corresponding to the - [DOMContentLoaded](https://developer.mozilla.org/en/Gecko-Specific_DOM_Events) - event - * "end": load content scripts once all the 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 - -</api> - -<api name="destroy"> -@method -Unloads the page worker. After you destroy a page worker, its memory is freed -and you must create a new instance if you need to load another page. -</api> - -<api name="postMessage"> -@method -Sends a message to the content scripts. -@param message {value} -The message to send. Must be JSON-able. -</api> - -<api name="on"> -@method -Registers an event listener with the page worker. See -[Working with Events](dev-guide/addon-development/events.html) for help with -events. -@param type {string} -The type of event to listen for. -@param listener {function} -The listener function that handles the event. -</api> - -<api name="removeListener"> -@method -Unregisters an event listener from the page worker. -@param type {string} -The type of event for which `listener` was registered. -@param listener {function} -The listener function that was registered. -</api> - -<api name="message"> -@event -If you listen to this event you can receive message events from content -scripts associated with this page worker. When a content script posts a -message using `self.postMessage()`, the message is delivered to the add-on -code in the page worker's `message` event. - -@argument {value} -Listeners are passed a single argument which is the message posted -from the content script. The message can be any -<a href = "dev-guide/addon-development/content-scripts/using-port.html#json_serializable">JSON-serializable value</a> -</api> - -<api name="error"> -@event -This event is emitted when an uncaught runtime error occurs in one of the -page worker's content scripts. - -@argument {Error} -Listeners are passed a single argument, the -[Error](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error) -object. -</api> - -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/panel.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/panel.md deleted file mode 100644 index 45eea2f..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/panel.md +++ /dev/null @@ -1,301 +0,0 @@ -<!-- contributed by Myk Melez [myk@mozilla.org] --> -<!-- contributed by Irakli Gozalishvili [gozala@mozilla.com] --> - -The `panel` module creates floating modal "popup dialogs" that appear on top of -web content and browser chrome and persist until dismissed by users or programs. -Panels are useful for presenting temporary interfaces to users in a way that is -easier for users to ignore and dismiss than a modal dialog, since panels are -hidden the moment users interact with parts of the application interface outside -them. - -The module exports a single constructor function `Panel` which constructs a -new panel. - -A panel's content is loaded as soon as it is created, before the panel is shown, -and the content remains loaded when a panel is hidden, so it is possible -to keep a panel around in the background, updating its content as appropriate -in preparation for the next time it is shown. - -Your add-on can receive notifications when a panel is shown or hidden by -listening to its `show` and `hide` events. - -Panels have associated content scripts, which are JavaScript scripts that have -access to the content loaded into the panels. An add-on can specify one or -more content scripts to load for a panel, and the add-on can communicate with -those scripts either using the `message` event or by using user-defined -events. See -[Working with Content Scripts](dev-guide/addon-development/web-content.html) -for more information. - -The panel's default style is different for each operating system. -For example, suppose a panel's content is specified with the following HTML: - -<script type="syntaxhighlighter" class="brush: html"><![CDATA[ -<h1>Default Style</h1> - -This is what a panel with no custom styling looks like. -]]> -</script> - -On OS X it will look like this: - -<img class="image-center" src="static-files/media/screenshots/default-panel-osx.png" -alt="OS X panel default style"> -<br> - -On Windows 7 it will look like this: - -<img class="image-center" src="static-files/media/screenshots/default-panel-windows.png" -alt="Windows 7 panel default style"> -<br> - -On Ubuntu it will look like this: - -<img class="image-center" src="static-files/media/screenshots/default-panel-ubuntu.png" -alt="Ubuntu panel default style"> -<br> - -This helps to ensure that the panel's style is consistent with the dialogs -displayed by Firefox and other applications, but means you need to take care -when applying your own styles. For example, if you set the panel's -`background-color` property to `white` and do not set the `color` property, -then the panel's text will be invisible on OS X although it looks fine on Ubuntu. - -Examples --------- - -Create and show a simple panel with content from the `data/` directory: - - var data = require("self").data; - var panel = require("panel").Panel({ - contentURL: data.url("foo.html") - }); - - panel.show(); - -The tutorial section on -[web content](dev-guide/addon-development/web-content.html) has -a more complex example using panels. - -<api name="Panel"> -@class -The Panel object represents a floating modal dialog that can by an add-on to -present user interface content. - -Once a panel object has been created it can be shown and hidden using its -`show()` and `hide()` methods. Once a panel is no longer needed it can be -deactivated using `destroy()`. - -The content of a panel is specified using the `contentURL` option. An add-on -can interact with the content of a panel using content scripts which it -supplies in the `contentScript` and/or `contentScriptFile` options. For example, -a content script could create a menu and send the user's selection to the -add-on. - -<api name="Panel"> -@constructor -Creates a panel. -@param options {object} - Options for the panel, with the following keys: - @prop [width] {number} - The width of the panel in pixels. Optional. - @prop [height] {number} - The height of the panel in pixels. Optional. - @prop [contentURL] {string} - The URL of the content to load in the panel. - @prop [allow] {object} - An optional object describing permissions for the content. It should - contain a single key named `script` whose value is a boolean that indicates - whether or not to execute script in the content. `script` defaults to true. - @prop [contentScriptFile] {string,array} - A local file URL or an array of local file URLs of content scripts to load. - Content scripts specified by this property are loaded *before* those - specified by the `contentScript` property. - @prop [contentScript] {string,array} - A string or an array of strings containing the texts of content scripts to - load. Content scripts specified by this property are loaded *after* those - specified by the `contentScriptFile` property. - @prop [contentScriptWhen="end"] {string} - When to load the content scripts. This may take one of the following - values: - - * "start": load content scripts immediately after the document - element for the panel is inserted into the DOM, but before the DOM content - itself has been loaded - * "ready": load content scripts once DOM content has been loaded, - corresponding to the - [DOMContentLoaded](https://developer.mozilla.org/en/Gecko-Specific_DOM_Events) - event - * "end": load content scripts once all the content (DOM, JS, CSS, - images) for the panel has been loaded, at the time the - [window.onload event](https://developer.mozilla.org/en/DOM/window.onload) - fires - - This property is optional and defaults to "end". - - @prop [onMessage] {function} - Include this to listen to the panel's `message` event. - @prop [onShow] {function} - Include this to listen to the panel's `show` event. - @prop [onHide] {function} - Include this to listen to the panel's `hide` event. -</api> - -<api name="port"> -@property {EventEmitter} -[EventEmitter](packages/api-utils/docs/events.html) object that allows you to: - -* send events to the content script using the `port.emit` function -* receive events from the content script using the `port.on` function - -See the guide to -<a href="dev-guide/addon-development/content-scripts/using-port.html"> -communicating using <code>port</code></a> for details. -</api> - -<api name="isShowing"> -@property {boolean} -Tells if the panel is currently shown or not. This property is read-only. -</api> - -<api name="height"> -@property {number} -The height of the panel in pixels. -</api> - -<api name="width"> -@property {number} -The width of the panel in pixels. -</api> - -<api name="contentURL"> -@property {string} -The URL of the content loaded in the panel. -</api> - -<api name="allow"> -@property {object} -An object describing permissions for the content. It contains a single key -named `script` whose value is a boolean that indicates whether or not to execute -script in the content. -</api> - -<api name="contentScriptFile"> -@property {string,array} -A local file URL or an array of local file URLs of content scripts to load. -Content scripts specified by this property are loaded *before* those -specified by the `contentScript` property. -</api> - -<api name="contentScript"> -@property {string,array} -A string or an array of strings containing the texts of content scripts to -load. Content scripts specified by this property are loaded *after* those -specified by the `contentScriptFile` property. -</api> - -<api name="contentScriptWhen"> -@property {string} -When to load the content scripts. This may have one of the following -values: - -* "start": load content scripts immediately after the document -element for the panel is inserted into the DOM, but before the DOM content -itself has been loaded -* "ready": load content scripts once DOM content has been loaded, -corresponding to the -[DOMContentLoaded](https://developer.mozilla.org/en/Gecko-Specific_DOM_Events) -event -* "end": load content scripts once all the content (DOM, JS, CSS, -images) for the panel has been loaded, at the time the -[window.onload event](https://developer.mozilla.org/en/DOM/window.onload) -fires - -</api> - -<api name="destroy"> -@method -Destroys the panel, unloading any content that was loaded in it. Once -destroyed, the panel can no longer be used. If you just want to hide -the panel and might show it later, use `hide` instead. -</api> - -<api name="postMessage"> -@method -Sends a message to the content scripts. -@param message {value} -The message to send. Must be stringifiable to JSON. -</api> - -<api name="show"> -@method -Displays the panel. -</api> - -<api name="hide"> -@method -Stops displaying the panel. -</api> - -<api name="resize"> -@method -Resizes the panel. -@param width {number} -The new width of the panel in pixels. -@param height {number} -The new height of the panel in pixels. -</api> - -<api name="on"> -@method - Registers an event listener with the panel. -@param type {string} - The type of event to listen for. -@param listener {function} - The listener function that handles the event. -</api> - -<api name="removeListener"> -@method - Unregisters an event listener from the panel. -@param type {string} - The type of event for which `listener` was registered. -@param listener {function} - The listener function that was registered. -</api> - -<api name="show"> -@event -This event is emitted when the panel is shown. -</api> - -<api name="hide"> -@event -This event is emitted when the panel is hidden. -</api> - -<api name="message"> -@event -If you listen to this event you can receive message events from content -scripts associated with this panel. When a content script posts a -message using `self.postMessage()`, the message is delivered to the add-on -code in the panel's `message` event. - -@argument {value} -Listeners are passed a single argument which is the message posted -from the content script. The message can be any -<a href = "dev-guide/addon-development/content-scripts/using-port.html#json_serializable">JSON-serializable value</a>. -</api> - -<api name="error"> -@event -This event is emitted when an uncaught runtime error occurs in one of the -panel's content scripts. - -@argument {Error} -Listeners are passed a single argument, the -[Error](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error) -object. -</api> - -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/passwords.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/passwords.md deleted file mode 100644 index 6a4b246..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/passwords.md +++ /dev/null @@ -1,564 +0,0 @@ -<!-- contributed by Irakli Gozalishvili [gozala@mozilla.com] --> - -The `passwords` module allows add-ons to interact with Firefox's -[Password Manager](http://support.mozilla.com/en-US/kb/Remembering%20passwords) -to add, retrieve and remove stored credentials. - -A _credential_ is the set of information a user supplies to authenticate -herself with a service. Typically a credential consists of a username and a -password. - -Using this module you can: - -1. **Search** for credentials which have been stored in the Password Manager. - You can then use the credentials to access their related service (for - example, by logging into a web site). - -2. **Store** credentials in the Password Manager. You can store different sorts - of credentials, as outlined in the "Credentials" section below. - -3. **Remove** stored credentials from the Password Manager. - -## Credentials ## - -In this API, credentials are represented by objects. - -You create credential objects to pass into the API, and the API also returns -credential objects to you. The sections below explain both the properties you -should define on credential objects and the properties you can expect on -credential objects returned by the API. - -All credential objects include `username` and `password` properties. Different -sorts of stored credentials include various additional properties, as -outlined in this section. - -You can use the Passwords API with three sorts of credentials: - -* Add-on credentials -* HTML form credentials -* HTTP Authentication credentials - -### Add-on Credential ### - -These are associated with your add-on rather than a particular web site. -They contain the following properties: - -<table> -<colgroup> -<col width="25%"> -</colgroup> -<tr> - <td> - <code>username</code> - </td> - <td> - The username. - </td> -</tr> - -<tr> - <td> - <code>password</code> - </td> - <td> - The password. - </td> -</tr> - -<tr> - <td> - <code>url</code> - </td> - <td> - <p>For an add-on credential, this property is of the form:<br><code> - addon:<addon-id></code>, where <code><addon-id></code> - is the add-on's - <a href="dev-guide/addon-development/program-id.html"> - Program ID</a>.</p> - <p>You don't supply this value when storing an add-on credential: it is - automatically generated for you. However, you can use it to work out - which stored credentials belong to your add-on by comparing it with the - <code>uri</code> property of the - <a href="packages/addon-kit/docs/self.html"><code>self</code></a> - module.</p> - </td> -</tr> - -<tr> - <td> - <code>realm</code> - </td> - <td> - <p>You can use this as a name for the credential, to distinguish - it from any other credentials you've stored.</p> - <p>The realm is displayed - in Firefox's Password Manager, under "Site", in brackets after the URL. - For example, if the realm for a credential is "User Registration", then - its "Site" field will look something like:</p> - <code>addon:jid0-01mBBFyu0ZAXCFuB1JYKooSTKIc (User Registration)</code> - </td> -</tr> - -</table> - -### HTML Form Credential ### - -If a web service uses HTML forms to authenticate its users, then the -corresponding credential is an HTML Form credential. - -It contains the following properties: - -<table> -<colgroup> -<col width="25%"> -</colgroup> -<tr> - <td> - <code>username</code> - </td> - <td> - The username. - </td> -</tr> - -<tr> - <td> - <code>password</code> - </td> - <td> - The password. - </td> -</tr> - -<tr> - <td> - <code>url</code> - </td> - <td> - The URL for the web service which requires the credential. - You should omit anything after the hostname and (optional) port. - </td> -</tr> - -<tr> - <td> - <code>formSubmitURL</code> - </td> - <td> - The value of the form's "action" attribute. - You should omit anything after the hostname and (optional) port. - If the form doesn't contain an "action" attribute, this property should - match the <code>url</code> property. - </td> -</tr> - -<tr> - <td> - <code>usernameField</code> - </td> - <td> - The value of the "name" attribute for the form's username field. - </td> -</tr> - -<tr> - <td> - <code>passwordField</code> - </td> - <td> - The value of the "name" attribute for the form's password field. - </td> -</tr> - -</table> - -So: given a form at `http://www.example.com/login` -with the following HTML: - -<script type="syntaxhighlighter" class="brush: html"><![CDATA[ -<form action="http://login.example.com/foo/authenticate.cgi"> - <div>Please log in.</div> - <label>Username:</label> <input type="text" name="uname"> - <label>Password:</label> <input type="password" name="pword"> -</form> -]]> -</script> - -The corresponding values for the credential (excluding username and password) -should be: - -<pre> - url: "http://www.example.com" - formSubmitURL: "http://login.example.com" - usernameField: "uname" - passwordField: "pword" -</pre> - -Note that for both `url` and `formSubmitURL`, the portion of the URL after the -hostname is omitted. - -### HTTP Authentication Credential ### - -These are used to authenticate the user to a web site -which uses HTTP Authentication, as detailed in -[RFC 2617](http://tools.ietf.org/html/rfc2617). -They contain the following properties: - -<table> -<colgroup> -<col width="25%"> -</colgroup> -<tr> - <td> - <code>username</code> - </td> - <td> - The username. - </td> -</tr> - -<tr> - <td> - <code>password</code> - </td> - <td> - The password. - </td> -</tr> - -<tr> - <td> - <code>url</code> - </td> - <td> - The URL for the web service which requires the credential. - You should omit anything after the hostname and (optional) port. - </td> -</tr> - -<tr> - <td> - <code>realm</code> - </td> - <td> - <p>The WWW-Authenticate response header sent by the server may include a - "realm" field as detailed in - <a href="http://tools.ietf.org/html/rfc2617">RFC 2617</a>. If it does, - this property contains the value for the "realm" field. Otherwise, it is - omitted.</p> - <p>The realm is displayed in Firefox's Password Manager, under "Site", - in brackets after the URL.</p> - </td> -</tr> - -</table> - -So: if a web server at `http://www.example.com` requested authentication with -a response code like this: - -<pre> - HTTP/1.0 401 Authorization Required - Server: Apache/1.3.27 - WWW-Authenticate: Basic realm="ExampleCo Login" -</pre> - -The corresponding values for the credential (excluding username and password) -should be: - -<pre> - url: "http://www.example.com" - realm: "ExampleCo Login" -</pre> - -## onComplete and onError ## - -This API is explicitly asynchronous, so all its functions take two callback -functions as additional options: `onComplete` and `onError`. - -`onComplete` is called when the operation has completed successfully and -`onError` is called when the function encounters an error. - -Because the `search` function is expected to return a list of matching -credentials, its `onComplete` option is mandatory. Because the other functions -don't return a value in case of success their `onComplete` options are -optional. - -For all functions, `onError` is optional. - -<api name="search"> -@function - -This function is used to retrieve a credential, or a list of credentials, -stored in the Password Manager. - -You pass it any subset of the possible properties a credential can contain. -Credentials which match all the properties you supplied are returned as an -argument to the `onComplete` callback. - -So if you pass in an empty set of properties, all stored credentials are -returned: - - function show_all_passwords() { - require("passwords").search({ - onComplete: function onComplete(credentials) { - credentials.forEach(function(credential) { - console.log(credential.username); - console.log(credential.password); - }); - } - }); - } - -If you pass it a single property, only credentials matching that property are -returned: - - function show_passwords_for_joe() { - require("passwords").search({ - username: "joe", - onComplete: function onComplete(credentials) { - credentials.forEach(function(credential) { - console.log(credential.username); - console.log(credential.password); - }); - } - }); - } - -If you pass more than one property, returned credentials must match all of -them: - - function show_google_password_for_joe() { - require("passwords").search({ - username: "joe", - url: "https://www.google.com", - onComplete: function onComplete(credentials) { - credentials.forEach(function(credential) { - console.log(credential.username); - console.log(credential.password); - }); - } - }); - } - -To retrieve only credentials associated with your add-on, use the `url` -property, initialized from `self.uri`: - - function show_my_addon_passwords() { - require("passwords").search({ - url: require("self").uri, - onComplete: function onComplete(credentials) { - credentials.forEach(function(credential) { - console.log(credential.username); - console.log(credential.password); - }); - } - }); - } - -@param options {object} -The `options` object may contain any credential properties. It is used to -restrict the set of credentials returned by the `search` function. - -See "Credentials" above for details on what these properties should be. - -Additionally, `options` must contain a function assigned to its `onComplete` -property: this is called when the function completes and is passed the set of -credentials retrieved. - -`options` may contain a function assigned to its `onError` property, which is -called if the function encounters an error. `onError` is passed the error as an -[nsIException](https://developer.mozilla.org/en/nsIException) object. - -@prop [username] {string} -The username for the credential. - -@prop [password] {string} -The password for the credential. - -@prop [url] {string} -The URL associated with the credential. - -@prop [formSubmitURL] {string} -The URL an HTML form credential is submitted to. - -@prop [realm] {string} -For HTTP Authentication credentials, the realm for which the credential was -requested. For add-on credentials, a name for the credential. - -@prop [usernameField] {string} -The value of the `name` attribute for the user name input field in a form. - -@prop [passwordField] {string} -The value of the `name` attribute for the password input field in a form. - -@prop onComplete {function} -The callback function that is called once the function completes successfully. -It is passed all the matching credentials as a list. This is the only -mandatory option. - -@prop [onError] {function} -The callback function that is called if the function failed. The -callback is passed an `error` containing a reason of a failure: this is an -[nsIException](https://developer.mozilla.org/en/nsIException) object. - -</api> - -<api name="store"> -@function - -This function is used to store a credential in the Password Manager. - -It takes an `options` object as an argument: this contains all the properties -for the new credential. - -As different sorts of credentials contain different properties, the -appropriate options differ depending on the sort of credential being stored. - -To store an add-on credential: - - require("passwords").store({ - realm: "User Registration", - username: "joe", - password: "SeCrEt123", - }); - -To store an HTML form credential: - - require("passwords").store({ - url: "http://www.example.com", - formSubmitURL: "http://login.example.com", - username: "joe", - usernameField: "uname", - password: "SeCrEt123", - passwordField: "pword" - }); - -To store an HTTP Authentication credential: - - require("passwords").store({ - url: "http://www.example.com", - realm: "ExampleCo Login", - username: "joe", - password: "SeCrEt123", - }); - -See "Credentials" above for more details on how to set these properties. - -The options parameter may also include `onComplete` and `onError` -callback functions, which are called when the function has completed -successfully and when it encounters an error, respectively. These options -are both optional. - -@param options {object} -An object containing the properties of the credential to be stored, and -optional `onComplete` and `onError` callback functions. - -@prop username {string} -The username for the credential. - -@prop password {string} -The password for the credential. - -@prop [url] {string} -The URL to which the credential applies. Omitted for add-on -credentials. - -@prop [formSubmitURL] {string} -The URL a form-based credential was submitted to. Omitted for add-on -credentials and HTTP Authentication credentials. - -@prop [realm] {string} -For HTTP Authentication credentials, the realm for which the credential was -requested. For add-on credentials, a name for the credential. - -@prop [usernameField] {string} -The value of the `name` attribute for the username input in a form. -Omitted for add-on credentials and HTTP Authentication credentials. - -@prop [passwordField] {string} -The value of the `name` attribute for the password input in a form. -Omitted for add-on credentials and HTTP Authentication credentials. - -@prop [onComplete] {function} -The callback function that is called once the function completes successfully. - -@prop [onError] {function} -The callback function that is called if the function failed. The -callback is passed an `error` argument: this is an -[nsIException](https://developer.mozilla.org/en/nsIException) object. - -</api> - -<api name="remove"> -@function - -Removes a stored credential. You supply it all the properties of the credential -to remove, along with optional `onComplete` and `onError` callbacks. - -Because you must supply all the credential's properties, it may be convenient -to call `search` first, and use its output as the input to `remove`. For -example, to remove all of joe's stored credentials: - - require("passwords").search({ - username: "joe", - onComplete: function onComplete(credentials) { - credentials.forEach(require("passwords").remove); - }) - }); - -To change an existing credential just call `store` after `remove` succeeds: - - require("passwords").remove({ - realm: "User Registration", - username: "joe", - password: "SeCrEt123" - onComplete: function onComplete() { - require("passwords").store({ - realm: "User Registration", - username: "joe", - password: "{{new password}}" - }) - } - }); - -@param options {object} - -An object containing all the properties of the credential to be removed, -and optional `onComplete` and `onError` callback functions. - -@prop username {string} -The username for the credential. - -@prop password {string} -The password for the credential. - -@prop [url] {string} -The URL to which the credential applies. Omitted for add-on -credentials. - -@prop [formSubmitURL] {string} -The URL a form-based credential was submitted to. Omitted for add-on -credentials and HTTP Authentication credentials. - -@prop [realm] {string} -For HTTP Authentication credentials, the realm for which the credential was -requested. For add-on credentials, a name for the credential. - -@prop [usernameField] {string} -The value of the `name` attribute for the username input in a form. -Omitted for add-on credentials and HTTP Authentication credentials. - -@prop [passwordField] {string} -The value of the `name` attribute for the password input in a form. -Omitted for add-on credentials and HTTP Authentication credentials. - -@prop [onComplete] {function} -The callback function that is called once the function has completed -successfully. - -@prop [onError] {function} -The callback function that is called if the function failed. The -callback is passed an `error` argument: this is an -[nsIException](https://developer.mozilla.org/en/nsIException) object. - -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/private-browsing.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/private-browsing.md deleted file mode 100644 index cad6166..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/private-browsing.md +++ /dev/null @@ -1,46 +0,0 @@ -<!-- contributed by Paul O'Shannessy [paul@oshannessy.com] --> -<!-- edited by Noelle Murata [fiveinchpixie@gmail.com] --> -<!-- contributed by Irakli Gozalishvili [gozala@mozilla.com] --> - -The `private-browsing` module allows you to access Firefox's private browsing -mode, detecting if it is active and when its state changes. - -This module is available in all applications. However, only Firefox will ever -transition into or out of private browsing mode. For all other applications, -`pb.isActive` will always be `false`, and none of the events will be emitted. - -<api name="isActive"> -@property {boolean} - This read-only boolean is true if private browsing mode is turned on. -</api> - -<api name="activate"> -@function - Turns on private browsing mode. -</api> - -<api name="deactivate"> -@function - Turns off private browsing mode. -</api> - -<api name="start"> -@event -Emitted immediately after the browser enters private browsing mode. - - var pb = require("private-browsing"); - pb.on("start", function() { - // Do something when the browser starts private browsing mode. - }); - -</api> - -<api name="stop"> -@event -Emitted immediately after the browser exits private browsing mode. - - var pb = require("private-browsing"); - pb.on("stop", function() { - // Do something when the browser stops private browsing mode. - }); -</api>
\ No newline at end of file diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/request.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/request.md deleted file mode 100644 index 77bea43..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/request.md +++ /dev/null @@ -1,192 +0,0 @@ -The `request` module lets you make simple yet powerful network requests. - -<api name="Request"> -@class -The `Request` object is used to make `GET` or `POST` network requests. It is -constructed with a URL to which the request is sent. Optionally the user may -specify a collection of headers and content to send alongside the request and -a callback which will be executed once the request completes. - -Once a `Request` object has been created a `GET` request can be executed by -calling its `get()` method, or a `POST` request by calling its `post()` method. - -When the server completes the request, the `Request` object emits a "complete" -event. Registered event listeners are passed a `Response` object. - -Each `Request` object is designed to be used once. Once `GET` or `POST` are -called, attempting to call either will throw an error. - -Since the request is not being made by any particular website, requests made -here are not subject to the same-domain restriction that requests made in web -pages are subject to. - -With the exception of `response`, all of a `Request` object's properties -correspond with the options in the constructor. Each can be set by simply -performing an assignment. However, keep in mind that the same validation rules -that apply to `options` in the constructor will apply during assignment. Thus, -each can throw if given an invalid value. - -The example below shows how to use Request to get the most recent public tweet. - - var Request = require("request").Request; - var latestTweetRequest = Request({ - url: "http://api.twitter.com/1/statuses/public_timeline.json", - onComplete: function (response) { - var tweet = response.json[0]; - console.log("User: " + tweet.user.screen_name); - console.log("Tweet: " + tweet.text); - } - }); - - // Be a good consumer and check for rate limiting before doing more. - Request({ - url: "http://api.twitter.com/1/account/rate_limit_status.json", - onComplete: function (response) { - if (response.json.remaining_hits) { - latestTweetRequest.get(); - } else { - console.log("You have been rate limited!"); - } - } - }).get(); - -<api name="Request"> -@constructor -This constructor creates a request object that can be used to make network -requests. The constructor takes a single parameter `options` which is used to -set several properties on the resulting `Request`. -@param options {object} - @prop url {string} - This is the url to which the request will be made. - - @prop [onComplete] {function} - This function will be called when the request has received a response (or in - terms of XHR, when `readyState == 4`). The function is passed a `Response` - object. - - @prop [headers] {object} - An unordered collection of name/value pairs representing headers to send - with the request. - - @prop [content] {string,object} - The content to send to the server. If `content` is a string, it should be - URL-encoded (use `encodeURIComponent`). If `content` is an object, it - should be a collection of name/value pairs. Nested objects & arrays should - encode safely. - - For `GET` requests, the query string (`content`) will be appended to the - URL. For `POST` requests, the query string will be sent as the body of the - request. - - @prop [contentType] {string} - The type of content to send to the server. This explicitly sets the - `Content-Type` header. The default value is `application/x-www-form-urlencoded`. - - @prop [overrideMimeType] {string} - Use this string to override the MIME type returned by the server in the - response's Content-Type header. You can use this to treat the content as a - different MIME type, or to force text to be interpreted using a specific - character. - - For example, if you're retrieving text content which was encoded as - ISO-8859-1 (Latin 1), it will be given a content type of "utf-8" and - certain characters will not display correctly. To force the response to - be interpreted as Latin-1, use `overrideMimeType`: - - var Request = require("request").Request; - var quijote = Request({ - url: "http://www.latin1files.org/quijote.txt", - overrideMimeType: "text/plain; charset=latin1", - onComplete: function (response) { - console.log(response.text); - } - }); - - quijote.get(); - -</api> - -<api name="url"> -@property {string} -</api> - -<api name="headers"> -@property {object} -</api> - -<api name="content"> -@property {string,object} -</api> - -<api name="contentType"> -@property {string} -</api> - -<api name="response"> -@property {Response} -</api> - -<api name="get"> -@method -Make a `GET` request. -@returns {Request} -</api> - -<api name="post"> -@method -Make a `POST` request. -@returns {Request} -</api> - -<api name="complete"> -@event -The `Request` object emits this event when the request has completed and a -response has been received. - -@argument {Response} -Listener functions are passed the response to the request as a `Response` object. -</api> - -</api> - - -<api name="Response"> -@class -The Response object contains the response to a network request issued using a -`Request` object. It is returned by the `get()` or `post()` method of a -`Request` object. - -All members of a `Response` object are read-only. -<api name="text"> -@property {string} -The content of the response as plain text. -</api> - -<api name="json"> -@property {object} -The content of the response as a JavaScript object. The value will be `null` -if the document cannot be processed by `JSON.parse`. -</api> - -<api name="status"> -@property {string} -The HTTP response status code (e.g. *200*). -</api> - -<api name="statusText"> -@property {string} -The HTTP response status line (e.g. *OK*). -</api> - -<api name="headers"> -@property {object} -The HTTP response headers represented as key/value pairs. - -To print all the headers you can do something like this: - - for (var headerName in response.headers) { - console.log(headerName + " : " + response.headers[headerName]); - } - -</api> -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/selection.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/selection.md deleted file mode 100644 index 62a3d64..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/selection.md +++ /dev/null @@ -1,86 +0,0 @@ -<!-- contributed by Eric H. Jung [eric.jung@yahoo.com] --> -<!-- contributed by Irakli Gozalishvili [gozala@mozilla.com] --> - -The `selection` module provides a means to get and set text and HTML selections -in the current Firefox page. It can also observe new selections. - -Registering for Selection Notifications ---------------------------------------- - -To be notified when the user makes a selection, register a listener for the -"select" event. Each listener will be called after a selection is made. - - function myListener() { - console.log("A selection has been made."); - } - var selection = require("selection"); - selection.on('select', myListener); - - // You can remove listeners too. - selection.removeListener('select', myListener); - -Iterating Over Discontiguous Selections ---------------------------------------- - -Discontiguous selections can be accessed by iterating over the `selection` -module itself. Each iteration yields a `Selection` object from which `text`, -`html`, and `isContiguous` properties can be accessed. - - -Examples --------- - -Log the current contiguous selection as text: - - var selection = require("selection"); - if (selection.text) - console.log(selection.text); - -Log the current discontiguous selections as HTML: - - var selection = require("selection"); - if (!selection.isContiguous) { - for (var subselection in selection) { - console.log(subselection.html); - } - } - -Surround HTML selections with delimiters: - - var selection = require("selection"); - selection.on('select', function () { - selection.html = "\\\" + selection.html + "///"; - }); - -<api name="text"> -@property {string} - Gets or sets the current selection as plain text. Setting the selection - removes all current selections, inserts the specified text at the location of - the first selection, and selects the new text. Getting the selection when - there is no current selection returns `null`. Setting the selection when there - is no current selection throws an exception. Getting the selection when - `isContiguous` is `true` returns the text of the first selection. -</api> - -<api name="html"> -@property {string} - Gets or sets the current selection as HTML. Setting the selection removes all - current selections, inserts the specified text at the location of the first - selection, and selects the new text. Getting the selection when there is no - current selection returns `null`. Setting the selection when there is no - current selection throws an exception. Getting the selection when - `isContiguous` is `true` returns the text of the first selection. -</api> - -<api name="isContiguous"> -@property {boolean} - `true` if the current selection is a single, contiguous selection, and `false` - if there are two or more discrete selections, each of which may or may not be - spatially adjacent. (Discontiguous selections can be created by the user with - Ctrl+click-and-drag.) -</api> - -<api name="select"> -@event - This event is emitted whenever the user makes a new selection in a page. -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/self.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/self.md deleted file mode 100644 index e76ad50..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/self.md +++ /dev/null @@ -1,73 +0,0 @@ -The `self` module provides access to data that is bundled with the add-on -as a whole. It also provides access to the -[Program ID](dev-guide/addon-development/program-id.html), a value which is -unique for each add-on. - -Note that the `self` module is completely different from the global `self` -object accessible to content scripts, which is used by a content script to -[communicate with the add-on code](dev-guide/addon-development/content-scripts/using-port.html). - -<api name="id"> -@property {string} -This property is a printable string that is unique for each add-on. It comes -from the `id` property set in the `package.json` file in the main package -(i.e. the package in which you run `cfx xpi`). While not generally of use to -add-on code directly, it can be used by internal API code to index local -storage and other resources that are associated with a particular add-on. -Eventually, this ID will be unspoofable (see -[JEP 118](https://wiki.mozilla.org/Labs/Jetpack/Reboot/JEP/118) for details). -</api> - -<api name="name"> -@property {string} -This property contains the add-on's short name. It comes from the `name` -property in the main package's `package.json` file. -</api> - -<api name="version"> -@property {string} -This property contains the add-on's version string. It comes from the -`version` property set in the `package.json` file in the main package. -</api> - -<api name="data"> -@property {object} -The `data` object is used to access data that was bundled with the add-on. -This data lives in the main package's `data/` directory, immediately below -the `package.json` file. All files in this directory will be copied into the -XPI and made available through the `data` object. - -The [Package Specification](dev-guide/addon-development/package-spec.html) -section explains the `package.json` file. - -<api name="data.load"> -@method -The `data.load(NAME)` method returns the contents of an embedded data file, -as a string. It is most useful for data that will be modified or parsed in -some way, such as JSON, XML, plain text, or perhaps an HTML template. For -data that can be displayed directly in a content frame, use `data.url(NAME)`. -@param name {string} The filename to be read, relative to the - package's `data` directory. Each package that uses the `self` module - will see its own `data` directory. -@returns {string} -</api> - -<api name="data.url"> -@method -The `data.url(NAME)` method returns a URL instance that points at an embedded -data file. It is most useful for data that can be displayed directly in a -content frame. The URL instance can be passed to a content frame constructor, -such as the Panel: - - var self = require("self"); - var myPanel = require("panel").Panel({ - contentURL: self.data.url("my-panel-content.html") - }); - myPanel.show(); - -@param name {string} The filename to be read, relative to the - package's `data` directory. Each package that uses the `self` module - will see its own `data` directory. -@returns {URL} -</api> -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/simple-prefs.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/simple-prefs.md deleted file mode 100644 index 824a151..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/simple-prefs.md +++ /dev/null @@ -1,70 +0,0 @@ -<!-- contributed by Erik Vold [erikvvold@gmail.com] --> - -#### *Experimental* - -The `simple-prefs` module lets you easily and persistently store preferences -across application restarts, which can be configured by users in the -Add-ons Manager. - -Introduction ------------- - -With the simple preferences module you can store booleans, integers, and string -values. - - -Inline Options & Default Values -------------------------------- - -In order to have a `options.xul` (for inline options) generated, or a -`defaults/preferences/prefs.js` for default preferences, you will need to -define the preferences in your `package.json`, like so: - - { - "fullName": "Example Add-on", - ... - "preferences": [{ - "name": "somePreference", - "title": "Some preference title", - "type": "string", - "value": "this is the default string value" - }] - } - - -<api name="prefs"> -@property {object} - *experimental* A persistent object private to your add-on. Properties with boolean, - number, and string values will be persisted in the Mozilla preferences system. -</api> - - -<api name="on"> -@function - *experimental* Registers an event `listener` that will be called when a preference is changed. - -**Example:** - - function onPrefChange(prefName) { - console.log("The " + prefName + " preference changed."); - } - require("simple-prefs").on("somePreference", onPrefChange); - require("simple-prefs").on("someOtherPreference", onPrefChange); - - -@param prefName {String} - The name of the preference to watch for changes. -@param listener {Function} - The listener function that processes the event. -</api> - -<api name="removeListener"> -@function - *experimental* Unregisters an event `listener` for the specified preference. - -@param prefName {String} - The name of the preference to watch for changes. -@param listener {Function} - The listener function that processes the event. -</api> - diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/simple-storage.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/simple-storage.md deleted file mode 100644 index e34e333..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/simple-storage.md +++ /dev/null @@ -1,125 +0,0 @@ -The `simple-storage` module lets you easily and persistently store data across -application restarts. If you're familiar with [DOM storage][] on the Web, it's -kind of like that, but for add-ons. - -[DOM storage]: https://developer.mozilla.org/en/DOM/Storage - - -Introduction ------------- - -The simple storage module exports an object called `storage` that is persistent -and private to your add-on. It's a normal JavaScript object, and you can treat -it as you would any other. - -To store a value, just assign it to a property on `storage`: - - var ss = require("simple-storage"); - ss.storage.myArray = [1, 1, 2, 3, 5, 8, 13]; - ss.storage.myBoolean = true; - ss.storage.myNull = null; - ss.storage.myNumber = 3.1337; - ss.storage.myObject = { a: "foo", b: { c: true }, d: null }; - ss.storage.myString = "O frabjous day!"; - -You can store array, boolean, number, object, null, and string values. If you'd -like to store other types of values, you'll first have to convert them to -strings or another one of these types. - -Be careful to set properties on the `storage` object and not the module itself: - - // This is no good! - var ss = require("simple-storage"); - ss.foo = "I will not be saved! :("; - - -Quotas ------- - -The simple storage available to your add-on is limited. Currently this limit is -about five megabytes (5,242,880 bytes). You can choose to be notified when you -go over quota, and you should respond by reducing the amount of data in storage. -If the user quits the application while you are over quota, all data stored -since the last time you were under quota will not be persisted. You should not -let that happen. - -To listen for quota notifications, register a listener for the `"OverQuota"` -event. It will be called when your storage goes over quota. - - function myOnOverQuotaListener() { - console.log("Uh oh."); - } - ss.on("OverQuota", myOnOverQuotaListener); - -Listeners can also be removed: - - ss.removeListener("OverQuota", myOnOverQuotaListener); - -To find out how much of your quota you're using, check the module's `quotaUsage` -property. It indicates the percentage of quota your storage occupies. If -you're within your quota, it's a number from 0 to 1, inclusive, and if you're -over, it's a number greater than 1. - -Therefore, when you're notified that you're over quota, respond by removing -storage until your `quotaUsage` is less than or equal to 1. Which particular -data you remove is up to you. For example: - - ss.storage.myList = [ /* some long array */ ]; - ss.on("OverQuota", function () { - while (ss.quotaUsage > 1) - ss.storage.myList.pop(); - }); - - -Private Browsing ----------------- - -*This section applies only to add-ons running on Firefox.* - -If your storage is related to your users' Web history, personal information, or -other sensitive data, your add-on should respect [private browsing mode][SUMO]. -While private browsing mode is active, you should not store any sensitive data. - -Because any kind of data can be placed into simple storage, support for private -browsing is not built into the module. Instead, use the -[`private-browsing`](packages/addon-kit/docs/private-browsing.html) module to -check private browsing status and respond accordingly. - -For example, the URLs your users visit should not be stored during private -browsing. If your add-on records the URL of the selected tab, here's how you -might handle that: - - ss.storage.history = []; - var privateBrowsing = require("private-browsing"); - if (!privateBrowsing.active) { - var url = getSelectedTabURL(); - ss.storage.history.push(url); - } - -For more information on supporting private browsing, see its [Mozilla Developer -Network documentation][MDN]. While that page does not apply specifically to -SDK-based add-ons (and its code samples don't apply at all), you should follow -its guidance on best practices and policies. - -[SUMO]: http://support.mozilla.com/en-US/kb/Private+Browsing -[MDN]: https://developer.mozilla.org/En/Supporting_private_browsing_mode - - -<api name="storage"> -@property {object} - A persistent object private to your add-on. Properties with array, boolean, - number, object, null, and string values will be persisted. -</api> - -<api name="quotaUsage"> -@property {number} - A number in the range [0, Infinity) that indicates the percentage of quota - occupied by storage. A value in the range [0, 1] indicates that the storage - is within quota. A value greater than 1 indicates that the storage exceeds - quota. -</api> - -<api name="OverQuota"> -@event -The module emits this event when your add-on's storage goes over its quota. -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/tabs.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/tabs.md deleted file mode 100644 index a6a858f..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/tabs.md +++ /dev/null @@ -1,381 +0,0 @@ -<!-- contributed by Dietrich Ayala [dietrich@mozilla.com] --> -<!-- edited by Noelle Murata [fiveinchpixie@gmail.com] --> - -The `tabs` module provides easy access to tabs and tab-related events. - -The module itself can be used like a basic list of all opened -tabs across all windows. In particular, you can enumerate it: - - var tabs = require('tabs'); - for each (var tab in tabs) - console.log(tab.title); - -You can also access individual tabs by index: - - var tabs = require('tabs'); - - tabs.on('ready', function () { - console.log('first: ' + tabs[0].title); - console.log('last: ' + tabs[tabs.length-1].title); - }); - -You can open a new tab, specifying various properties including location: - - var tabs = require("tabs"); - tabs.open("http://www.example.com"); - -You can register event listeners to be notified when tabs open, close, finish -loading DOM content, or are made active or inactive: - - var tabs = require("tabs"); - - // Listen for tab openings. - tabs.on('open', function onOpen(tab) { - myOpenTabs.push(tab); - }); - - // Listen for tab content loads. - tabs.on('ready', function(tab) { - console.log('tab is loaded', tab.title, tab.url) - }); - -You can get and set various properties of tabs (but note that properties - relating to the tab's content, such as the URL, will not contain valid -values until after the tab's `ready` event fires). By setting the `url` -property you can load a new page in the tab: - - var tabs = require("tabs"); - tabs.on('activate', function(tab) { - tab.url = "http://www.example.com"; - }); - -You can attach a [content script](dev-guide/addon-development/web-content.html) -to the page hosted in a tab, and use that to access and manipulate the page's -content: - - var tabs = require("tabs"); - - tabs.on('activate', function(tab) { - tab.attach({ - contentScript: 'self.postMessage(document.body.innerHTML);', - onMessage: function (message) { - console.log(message); - } - }); - }); - -<api name="activeTab"> -@property {Tab} - -The currently active tab in the active window. This property is read-only. To -activate a `Tab` object, call its `activate` method. - -**Example** - - // Get the active tab's title. - var tabs = require("tabs"); - console.log("title of active tab is " + tabs.activeTab.title); -</api> - -<api name="length"> -@property {number} -The number of open tabs across all windows. -</api> - -<api name="open"> -@function -Opens a new tab. The new tab will open in the active window or in a new window, -depending on the `inNewWindow` option. - -**Example** - - var tabs = require("tabs"); - - // Open a new tab on active window and make tab active. - tabs.open("http://www.mysite.com"); - - // Open a new tab in a new window and make it active. - tabs.open({ - url: "http://www.mysite.com", - inNewWindow: true - }); - - // Open a new tab on active window in the background. - tabs.open({ - url: "http://www.mysite.com", - inBackground: true - }); - - // Open a new tab as an app tab and do something once it's open. - tabs.open({ - url: "http://www.mysite.com", - isPinned: true, - onOpen: function onOpen(tab) { - // do stuff like listen for content - // loading. - } - }); - -@param options {object} -An object containing configurable options for how and where the tab will be -opened, as well as a listeners for the tab events. - -If the only option being used is `url`, then a bare string URL can be passed to -`open` instead of adding at a property of the `options` object. - -@prop [url] {string} -String URL to be opened in the new tab. -This is a required property. - -@prop [inNewWindow] {boolean} -If present and true, a new browser window will be opened and the URL will be -opened in the first tab in that window. This is an optional property. - -@prop [inBackground] {boolean} -If present and true, the new tab will be opened to the right of the active tab -and will not be active. This is an optional property. - -@prop [isPinned] {boolean} -If present and true, then the new tab will be pinned as an -[app tab](http://support.mozilla.com/en-US/kb/what-are-app-tabs). - -@prop [onOpen] {function} -A callback function that will be registered for 'open' event. -This is an optional property. -@prop [onClose] {function} -A callback function that will be registered for 'close' event. -This is an optional property. -@prop [onReady] {function} -A callback function that will be registered for 'ready' event. -This is an optional property. -@prop [onActivate] {function} -A callback function that will be registered for 'activate' event. -This is an optional property. -@prop [onDeactivate] {function} -A callback function that will be registered for 'deactivate' event. -This is an optional property. -</api> - -<api name="Tab"> -@class -A `Tab` instance represents a single open tab. It contains various tab -properties, several methods for manipulation, as well as per-tab event -registration. - -Tabs emit all the events described in the Events section. Listeners are -passed the `Tab` object that triggered the event. - -<api name="title"> -@property {string} -The title of the page currently loaded in the tab. -This property can be set to change the tab title. -</api> - -<api name="url"> -@property {String} -The URL of the page currently loaded in the tab. -This property can be set to load a different URL in the tab. -</api> - -<api name="favicon"> -@property {string} -The URL of the favicon for the page currently loaded in the tab. -This property is read-only. -</api> - -<api name="index"> -@property {integer} -The index of the tab relative to other tabs in the application window. -This property can be set to change its relative position. -</api> - -<api name="isPinned"> -@property {boolean} -Whether or not tab is pinned as an [app tab][]. -This property is read-only. -[app tab]:http://support.mozilla.com/en-US/kb/what-are-app-tabs -</api> - -<api name="getThumbnail"> -@property {method} -Returns thumbnail data URI of the page currently loaded in this tab. -</api> - -<api name="pin"> -@method -Pins this tab as an [app tab][]. -[app tab]:http://support.mozilla.com/en-US/kb/what-are-app-tabs -</api> - -<api name="unpin"> -@method -Unpins this tab. -</api> - -<api name="close"> -@method -Closes this tab. - -@param [callback] {function} -A function to be called when the tab finishes its closing process. -This is an optional argument. -</api> - -<api name="reload"> -@method -Reloads this tab. -</api> - -<api name="activate"> -@method -Makes this tab active, which will bring this tab to the foreground. -</api> - -<api name="attach"> -@method - Create a page mod and attach it to the document in the tab. - -**Example** - - var tabs = require("tabs"); - - tabs.on('ready', function(tab) { - tab.attach({ - contentScript: - 'document.body.style.border = "5px solid red";' - }); - }); - -@param options {object} - Options for the page mod, with the following keys: - -@prop [contentScriptFile] {string,array} - The local file URLs of content scripts to load. Content scripts specified - by this option are loaded *before* those specified by the `contentScript` - option. Optional. -@prop [contentScript] {string,array} - The texts of content scripts to load. Content scripts specified by this - option are loaded *after* those specified by the `contentScriptFile` option. - Optional. -@prop [onMessage] {function} - A function called when the page mod receives a message from content scripts. - Listeners are passed a single argument, the message posted from the - content script. - -@returns {Worker} - See [Content Scripts guide](dev-guide/addon-development/web-content.html) - to learn how to use the `Worker` object to communicate with the content script. - -</api> - -<api name="close"> -@event - -This event is emitted when the tab is closed. It's also emitted when the -tab's window is closed. - -@argument {Tab} -Listeners are passed the tab object. -</api> - -<api name="ready"> -@event - -This event is emitted when the DOM for the tab's content is ready. It is -equivalent to the `DOMContentLoaded` event for the given content page. - -A single tab will emit this event every time the DOM is loaded: so it will be -emitted again if the tab's location changes or the content is reloaded. - -After this event has been emitted, all properties relating to the tab's -content can be used. - -@argument {Tab} -Listeners are passed the tab object. -</api> - -<api name="activate"> -@event - -This event is emitted when the tab is made active. - -@argument {Tab} -Listeners are passed the tab object. -</api> - -<api name="deactivate"> -@event - -This event is emitted when the tab is made inactive. - -@argument {Tab} -Listeners are passed the tab object. -</api> - -</api> - -<api name="open"> -@event - -This event is emitted when a new tab is opened. This does not mean that -the content has loaded, only that the browser tab itself is fully visible -to the user. - -Properties relating to the tab's content (for example: `title`, `favicon`, -and `url`) will not be correct at this point. If you need to access these -properties, listen for the `ready` event: - - var tabs = require("tabs"); - tabs.on('open', function(tab){ - tab.on('ready', function(tab){ - console.log(tab.url); - }); - }); - -@argument {Tab} -Listeners are passed the tab object that just opened. -</api> - -<api name="close"> -@event - -This event is emitted when a tab is closed. When a window is closed -this event will be emitted for each of the open tabs in that window. - -@argument {Tab} -Listeners are passed the tab object that has closed. -</api> - -<api name="ready"> -@event - -This event is emitted when the DOM for a tab's content is ready. -It is equivalent to the `DOMContentLoaded` event for the given content page. - -A single tab will emit this event every time the DOM is loaded: so it will be -emitted again if the tab's location changes or the content is reloaded. - -After this event has been emitted, all properties relating to the tab's -content can be used. - -@argument {Tab} -Listeners are passed the tab object that has loaded. -</api> - -<api name="activate"> -@event - -This event is emitted when an inactive tab is made active. - -@argument {Tab} -Listeners are passed the tab object that has become active. -</api> - -<api name="deactivate"> -@event - -This event is emitted when the active tab is made inactive. - -@argument {Tab} -Listeners are passed the tab object that has become inactive. -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/timers.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/timers.md deleted file mode 100644 index bc36750..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/timers.md +++ /dev/null @@ -1,48 +0,0 @@ -<!-- contributed by Drew Willcoxon [adw@mozilla.com] --> -<!-- contributed by Atul Varma [atul@mozilla.com] --> -<!-- edited by Noelle Murata [fiveinchpixie@gmail.com] --> -<!-- contributed by Irakli Gozalishvil [gozala@mozilla.com] --> - -The `timers` module provides access to web-like timing functionality. - -<api name="setTimeout"> -@function - Schedules `callback` to be called in `ms` milliseconds. Any additional - arguments are passed straight through to the callback. -@returns {integer} - An ID that can later be used to undo this scheduling, if `callback` hasn't yet - been called. -@param callback {function} - Function to be called. -@param ms {integer} - Interval in milliseconds after which the function will be called. -</api> - -<api name="clearTimeout"> -@function - Given an ID returned from `setTimeout()`, prevents the callback with the ID - from being called (if it hasn't yet been called). -@param ID {integer} - An ID returned from `setTimeout()`. -</api> - -<api name="setInterval"> -@function - Schedules `callback` to be called repeatedly every `ms` milliseconds. Any - additional arguments are passed straight through to the callback. -@returns {integer} - An ID that can later be used to unschedule the callback. -@param callback {function} - Function to be called. -@param ms {integer} - Interval in milliseconds at which the function will be called. -</api> - -<api name="clearInterval"> -@function - Given an ID returned from `setInterval()`, prevents the callback with the ID - from being called again. -@param ID {integer} - An ID returned from `setInterval()`. -</api> - diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/widget.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/widget.md deleted file mode 100644 index aa12cbe..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/widget.md +++ /dev/null @@ -1,692 +0,0 @@ -<!-- contributed by Dietrich Ayala [dietrich@mozilla.com] --> -<!-- contributed by Drew Willcoxon [adw@mozilla.com] --> -<!-- edited by Noelle Murata [fiveinchpixie@gmail.com] --> - -The `widget` module provides your add-on with a simple user interface that is -consistent with other add-ons and blends in well with Firefox. - -## Introduction ## - -"Widgets" are small pieces of content that live in the Firefox 4 -[add-on bar](https://developer.mozilla.org/en/The_add-on_bar). -They can be simple icons or complex web pages. You can attach -[panels](packages/addon-kit/docs/panel.html) to them that open when they're -clicked, or you can define a custom click handler to perform some other action, -like opening a web page in a tab. - -There are a few advantages to using widgets over an ad hoc user interface. -First, your users will be accustomed to interacting with add-ons via widgets and -the add-on bar. Second, it allows Firefox to treat your interface as a -first-class citizen. For example, in the future Firefox may allow the user to -drag widgets from the add-on bar to other toolbars. By exposing your interface -as a widget, your add-on would automatically inherit such functionality. - -## Creation and Content ## - -Widgets can contain images or arbitrary web content. You can include this -content inline as a string by using the `content` property, or point to content -using a URL with the `contentURL` property. - -For example, this widget contains an image, so it looks like a simple icon: - - require("widget").Widget({ - id: "mozilla-icon", - label: "My Mozilla Widget", - contentURL: "http://www.mozilla.org/favicon.ico" - }); - -Upon creation, the widget is automatically added to the add-on bar. -You can set the width of a widget, but the height is fixed so as to fit in the -add-on bar. If the content is an image, it is automatically scaled to be 16x16 -pixels. - -This widget contains an entire web page: - - require("widget").Widget({ - id: "hello-display", - label: "My Hello Widget", - content: "Hello!", - width: 50 - }); - -Widgets are quite small by default, so this example used the `width` property to -grow it in order to show all the text. - -As with many SDK APIs, communication with the content inside your widgets is -handled by [content scripts](dev-guide/addon-development/web-content.html). -So, for example, to be notified when your widget's content has loaded, you can -make a small script that calls back to the widget when it finishes loading. - -## Attaching Panels to Widgets ## - -You can supply a [panel](packages/addon-kit/docs/panel.html) to the widget's -constructor: if you do this, the panel is automatically displayed when the -user clicks the widget. - -<!-- The icon the widget displays, shown in the screenshot, is taken from the -Circular icon set, http://prothemedesign.com/circular-icons/ which is made -available under the Creative Commons Attribution 2.5 Generic License: -http://creativecommons.org/licenses/by/2.5/ --> - -<img class="image-right" src="static-files/media/screenshots/widget-panel-clock.png" -alt="Panel attached to a widget"> - - data = require("self").data - - var clockPanel = require("panel").Panel({ - width:215, - height:160, - contentURL: data.url("clock.html") - }); - - require("widget").Widget({ - id: "open-clock-btn", - label: "Clock", - contentURL: data.url("History.png"), - panel: clockPanel - }); - -Note that this is, at the moment, the only way you can attach a panel to a widget. - -You must supply the panel in the widget's constructor for it to work. If you -assign the panel to the widget after construction, the panel can still be shown -but will not be anchored to the widget: - - data = require("self").data - - var clockPanel = require("panel").Panel({ - width:215, - height:160, - contentURL: data.url("clock.html") - }); - - widget = require("widget").Widget({ - id: "open-clock-btn", - label: "Clock", - contentURL: data.url("History.png") - }); - - widget.panel = clockPanel; - - // Will not be anchored - widget.panel.show(); - -Also, if you try to call `panel.show()` inside your widget's `click` event -listener, the panel will not be anchored: - - data = require("self").data - - var clockPanel = require("panel").Panel({ - width:215, - height:160, - contentURL: data.url("clock.html") - }); - - require("widget").Widget({ - id: "open-clock-btn", - label: "Clock", - contentURL: data.url("History.png"), - panel: clockPanel, - onClick: function() { - // Will not be anchored - this.panel.show(); - } - }); - -See [bug 638142](https://bugzilla.mozilla.org/show_bug.cgi?id=638142). - -## Examples ## - -For conciseness, these examples create their content scripts as strings and use -the `contentScript` property. In your own add-ons, you will probably want to -create your content scripts in separate files and pass their URLs using the -`contentScriptFile` property. See -[Working with Content Scripts](dev-guide/addon-development/web-content.html) for more -information. - - var widgets = require("widget"); - - // A basic click-able image widget. - widgets.Widget({ - id: "google-link", - label: "Widget with an image and a click handler", - contentURL: "http://www.google.com/favicon.ico", - onClick: function() { - require("tabs").activeTab.url = "http://www.google.com/"; - } - }); -<br> - - // A widget that changes display on mouseover. - widgets.Widget({ - id: "mouseover-effect", - label: "Widget with changing image on mouseover", - contentURL: "http://www.yahoo.com/favicon.ico", - onMouseover: function() { - this.contentURL = "http://www.bing.com/favicon.ico"; - }, - onMouseout: function() { - this.contentURL = "http://www.yahoo.com/favicon.ico"; - } - }); -<br> - - // A widget that updates content on a timer. - widgets.Widget({ - id: "auto-update-widget", - label: "Widget that updates content on a timer", - content: "0", - contentScript: 'setTimeout(function() {' + - ' document.body.innerHTML++;' + - '}, 2000)', - contentScriptWhen: "ready" - }); -<br> - - // A widget that loads a random Flickr photo every 5 minutes. - widgets.Widget({ - id: "random-flickr", - label: "Random Flickr Photo Widget", - contentURL: "http://www.flickr.com/explore/", - contentScriptWhen: "ready", - contentScript: 'postMessage(document.querySelector(".pc_img").src);' + - 'setTimeout(function() {' + - ' document.location = "http://www.flickr.com/explore/";' + - '}, 5 * 60 * 1000);', - onMessage: function(imgSrc) { - this.contentURL = imgSrc; - }, - onClick: function() { - require("tabs").activeTab.url = this.contentURL; - } - }); -<br> - - // A widget created with a specified width, that grows. - let myWidget = widgets.Widget({ - id: "widget-effect", - label: "Wide widget that grows wider on a timer", - content: "I'm getting longer.", - width: 50, - }); - require("timers").setInterval(function() { - myWidget.width += 10; - }, 1000); -<br> - - // A widget communicating bi-directionally with a content script. - let widget = widgets.Widget({ - id: "message-test", - label: "Bi-directional communication!", - content: "<foo>bar</foo>", - contentScriptWhen: "ready", - contentScript: 'on("message", function(message) {' + - ' alert("Got message: " + message);' + - '});' + - 'postMessage("ready");', - onMessage: function(message) { - if (message == "ready") - widget.postMessage("me too"); - } - }); - -<api-name="Widget"> -@class -Represents a widget object. - -<api name="Widget"> -@constructor {options} - Creates a new widget. The widget is immediately added to the add-on bar. - -@param options {object} - An object with the following keys: - - @prop label {string} - A required string description of the widget used for accessibility, - title bars, and error reporting. - - @prop id {string} - Mandatory string used to identify your widget in order to save its - location when the user moves it in the browser. - This string has to be unique and must not be changed over time. - - @prop [content] {string} - An optional string value containing the displayed content of the widget. - It may contain HTML. Widgets must have either the `content` property or the - `contentURL` property set. - - If the content is an image, it is automatically scaled to be 16x16 pixels. - - @prop [contentURL] {string} - An optional string URL to content to load into the widget. This can be - [local content](dev-guide/addon-development/web-content.html) or remote - content, an image or web content. Widgets must have either the `content` - property or the `contentURL` property set. - - If the content is an image, it is automatically scaled to be 16x16 pixels. - - @prop [panel] {Panel} - An optional [panel](packages/addon-kit/docs/panel.html) to open when the - user clicks on the widget. Note: If you also register a "click" listener, - it will be called instead of the panel being opened. However, you can show - the panel from the listener by calling `this.panel.show()`. - - @prop [width] {integer} - Optional width in pixels of the widget. If not given, a default width is - used. - - @prop [onClick] {function} - Include this to listen to the widget's `click` event. - - @prop [onMessage] {function} - Include this to listen to the widget's `message` event. - - @prop [onMouseover] {function} - Include this to listen to the widget's `mouseover` event. - - @prop [onMouseout] {function} - Include this to listen to the widget's `mouseout` event. - - @prop [onAttach] {function} - Include this to listen to the widget's `attach` event. - - @prop [tooltip] {string} - Optional text to show when the user's mouse hovers over the widget. If not - given, the `label` is used. - - @prop [allow] {object} - An optional object describing permissions for the content. It should - contain a single key named `script` whose value is a boolean that indicates - whether or not to execute script in the content. `script` defaults to true. - - @prop [contentScriptFile] {string,array} - A local file URL or an array of local file URLs of content scripts to load. - Content scripts specified by this property are loaded *before* those - specified by the `contentScript` property. - - @prop [contentScript] {string,array} - A string or an array of strings containing the texts of content scripts to - load. Content scripts specified by this property are loaded *after* those - specified by the `contentScriptFile` property. - - @prop [contentScriptWhen="end"] {string} - When to load the content scripts. This may take one of the following - values: - - * "start": load content scripts immediately after the document - element for the widget is inserted into the DOM, but before the DOM content - itself has been loaded - * "ready": load content scripts once DOM content has been loaded, - corresponding to the - [DOMContentLoaded](https://developer.mozilla.org/en/Gecko-Specific_DOM_Events) - event - * "end": load content scripts once all the content (DOM, JS, CSS, - images) for the widget has been loaded, at the time the - [window.onload event](https://developer.mozilla.org/en/DOM/window.onload) - fires - - This property is optional and defaults to "end". - -</api> - -<api name="destroy"> -@method - Removes the widget from the add-on bar. -</api> - -<api name="postMessage"> -@method - Sends a message to the widget's content scripts. -@param data {value} - The message to send. - The message can be any -<a href = "dev-guide/addon-development/content-scripts/using-port.html#json_serializable">JSON-serializable value</a>. -</api> - -<api name="on"> -@method - Registers an event listener with the widget. -@param type {string} - The type of event to listen for. -@param listener {function} - The listener function that handles the event. -</api> - -<api name="removeListener"> -@method - Unregisters an event listener from the widget. -@param type {string} - The type of event for which `listener` was registered. -@param listener {function} - The listener function that was registered. -</api> - -<api name="getView"> -@method - Retrieve a `WidgetView` instance of this widget relative to a browser window. -@param window {BrowserWindow} - The [BrowserWindow](packages/addon-kit/docs/windows.html) instance to match. -@returns {WidgetView} - A `WidgetView` instance associated with the browser window. Any changes - subsequently applied to this object will only be applied to the widget - attached to that window. -</api> - -<api name="label"> -@property {string} - The widget's label. Read-only. -</api> - -<api name="content"> -@property {string} - A string containing the widget's content. It can contain HTML. Setting it - updates the widget's appearance immediately. However, if the widget was - created using `contentURL`, then this property is meaningless, and setting it - has no effect. -</api> - -<api name="contentURL"> -@property {string} - The URL of content to load into the widget. This can be - [local content](dev-guide/addon-development/web-content.html) or remote - content, an image or web content. Setting it updates the widget's appearance - immediately. However, if the widget was created using `content`, then this - property is meaningless, and setting it has no effect. -</api> - -<api name="panel"> -@property {Panel} - A [panel](packages/addon-kit/docs/panel.html) to open when the user clicks on - the widget. -</api> - -<api name="width"> -@property {number} - The widget's width in pixels. Setting it updates the widget's appearance - immediately. -</api> - -<api name="tooltip"> -@property {string} - The text of the tooltip that appears when the user hovers over the widget. -</api> - -<api name="allow"> -@property {object} - A object describing permissions for the content. It contains a single key - named `script` whose value is a boolean that indicates whether or not to - execute script in the content. -</api> - -<api name="contentScriptFile"> -@property {string,array} - A local file URL or an array of local file URLs of content scripts to load. -</api> - -<api name="contentScript"> -@property {string,array} - A string or an array of strings containing the texts of content scripts to - load. -</api> - -<api name="contentScriptWhen"> -@property {string} - When to load the content scripts. This may have one of the following - values: - - * "start": load content scripts immediately after the document - element for the widget is inserted into the DOM, but before the DOM content - itself has been loaded - * "ready": load content scripts once DOM content has been loaded, - corresponding to the - [DOMContentLoaded](https://developer.mozilla.org/en/Gecko-Specific_DOM_Events) - event - * "end": load content scripts once all the content (DOM, JS, CSS, - images) for the widget has been loaded, at the time the - [window.onload event](https://developer.mozilla.org/en/DOM/window.onload) - fires - -</api> - -<api name="port"> -@property {EventEmitter} -[EventEmitter](packages/api-utils/docs/events.html) object that allows you to: - -* send events to the content script using the `port.emit` function -* receive events from the content script using the `port.on` function - -See the guide to -<a href="dev-guide/addon-development/content-scripts/using-port.html"> -communicating using <code>port</code></a> for details. -</api> - -<api name="attach"> -@event -This event is emitted when a new `WidgetView` object is created using the -`getView()` function. -</api> - -<api name="click"> -@event -This event is emitted when the widget is clicked. -</api> - -<api name="message"> -@event -If you listen to this event you can receive message events from content -scripts associated with this widget. When a content script posts a -message using `self.postMessage()`, the message is delivered to the add-on -code in the widget's `message` event. - -@argument {value} -Listeners are passed a single argument which is the message posted -from the content script. The message can be any -<a href = "dev-guide/addon-development/content-scripts/using-port.html#json_serializable">JSON-serializable value</a>. -</api> - -<api name="mouseover"> -@event -This event is emitted when the user moves the mouse over the widget. -</api> - -<api name="mouseout"> -@event -This event is emitted when the user moves the mouse away from the widget. -</api> - -</api> - - -<api-name="WidgetView"> -@class -Represents a widget instance specific to one browser window. - -Anything you do to an instance of this object will only be applied to the -instance attached to its browser window: widget instances attached to other -browser windows will be unaffected. - -By contrast, any changes you make to an instance of the normal `Widget` class -will be applied across all browser windows. - -This class has all the same methods, attributes and events as the `Widget` -class except for the `getView` method and the `attach` event. - -In this example `WidgetView` is used to display different content for -`http` and `https` schemes: - - // A widget that update its content specifically to each window. - let tabs = require("tabs"); - let windows = require("windows").browserWindows; - let widget = widgets.Widget({ - id: "window-specific-test", - label: "Widget with content specific to each window", - content: " ", - width: 50 - }); - // Observe tab switch or document changes in each existing tab: - function updateWidgetState(tab) { - let view = widget.getView(tab.window); - if (!view) return; - // Update widget displayed text: - view.content = tab.url.match(/^https/) ? "Secured" : "Unsafe"; - } - tabs.on('ready', updateWidgetState); - tabs.on('activate', updateWidgetState); - -<api name="destroy"> -@method - Removes the widget view from the add-on bar. -</api> - -<api name="postMessage"> -@method - Sends a message to the widget view's content scripts. -@param data {value} - The message to send. The message can be any -<a href = "dev-guide/addon-development/content-scripts/using-port.html#json_serializable">JSON-serializable value</a>. -</api> - -<api name="on"> -@method - Registers an event listener with the widget view. -@param type {string} - The type of event to listen for. -@param listener {function} - The listener function that handles the event. -</api> - -<api name="removeListener"> -@method - Unregisters an event listener from the widget view. -@param type {string} - The type of event for which `listener` was registered. -@param listener {function} - The listener function that was registered. -</api> - -<api name="label"> -@property {string} - The widget view's label. Read-only. -</api> - -<api name="content"> -@property {string} - A string containing the widget view's content. It can contain HTML. - Setting it updates the widget view's appearance immediately. However, - if the widget view was created using `contentURL`, then this property - is meaningless, and setting it has no effect. -</api> - -<api name="contentURL"> -@property {string} - The URL of content to load into the widget view. This can be - [local content](dev-guide/addon-development/web-content.html) or remote - content, an image or web content. Setting it updates the widget view's - appearance immediately. However, if the widget view was created using - `content`, then this property is meaningless, and setting it has no effect. -</api> - -<api name="panel"> -@property {Panel} - A [panel](packages/addon-kit/docs/panel.html) to open when the user clicks on - the widget view. -</api> - -<api name="width"> -@property {number} - The widget view's width in pixels. Setting it updates the widget view's - appearance immediately. -</api> - -<api name="tooltip"> -@property {string} - The text of the tooltip that appears when the user hovers over the widget - view. -</api> - -<api name="allow"> -@property {object} - A object describing permissions for the content. It contains a single key - named `script` whose value is a boolean that indicates whether or not to - execute script in the content. -</api> - -<api name="contentScriptFile"> -@property {string,array} - A local file URL or an array of local file URLs of content scripts to load. -</api> - -<api name="contentScript"> -@property {string,array} - A string or an array of strings containing the texts of content scripts to - load. -</api> - -<api name="contentScriptWhen"> -@property {string} - When to load the content scripts. This may have one of the following - values: - - * "start": load content scripts immediately after the document - element for the widget view is inserted into the DOM, but before the DOM - content itself has been loaded - * "ready": load content scripts once DOM content has been loaded, - corresponding to the - [DOMContentLoaded](https://developer.mozilla.org/en/Gecko-Specific_DOM_Events) - event - * "end": load content scripts once all the content (DOM, JS, CSS, - images) for the widget view has been loaded, at the time the - [window.onload event](https://developer.mozilla.org/en/DOM/window.onload) - fires - -</api> - -<api name="port"> -@property {EventEmitter} -[EventEmitter](packages/api-utils/docs/events.html) object that allows you to: - -* send events to the content script using the `port.emit` function -* receive events from the content script using the `port.on` - -See the guide to -<a href="dev-guide/addon-development/content-scripts/using-port.html"> -communicating using <code>port</code></a> for details. -</api> - -<api name="detach"> -@event -The `detach` event is fired when the widget view is removed from its related -window. -This can occur if the window is closed, Firefox exits, or the add-on is -disabled. -</api> - -<api name="click"> -@event -This event is emitted when the widget view is clicked. -</api> - -<api name="message"> -@event -If you listen to this event you can receive message events from content -scripts associated with this widget view. When a content script posts a -message using `self.postMessage()`, the message is delivered to the add-on -code in the widget view's `message` event. - -@argument {value} -Listeners are passed a single argument which is the message posted -from the content script. The message can be any -<a href = "dev-guide/addon-development/content-scripts/using-port.html#json_serializable">JSON-serializable value</a>. -</api> - -<api name="mouseover"> -@event -This event is emitted when the user moves the mouse over the widget view. -</api> - -<api name="mouseout"> -@event -This event is emitted when the user moves the mouse away from the widget view. -</api> - -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/docs/windows.md b/tools/addon-sdk-1.4/packages/addon-kit/docs/windows.md deleted file mode 100644 index a5bed95..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/docs/windows.md +++ /dev/null @@ -1,187 +0,0 @@ -<!-- contributed by Felipe Gomes [felipc@gmail.com] --> - - -The `windows` module provides easy access to browser windows, their -tabs, and open/close related functions and events. - -This module currently only supports browser windows and does not provide -access to non-browser windows such as the Bookmarks Library, preferences -or other non-browser windows created via add-ons. - -<api name="browserWindows"> -@property {List} -An object that contains various properties and methods to access -functionality from browser windows, such as opening new windows, accessing -their tabs or switching the current active window. - -`browserWindows` provides access to all the currently open browser windows: - - var windows = require("windows"); - for each (var window in windows.browserWindows) { - console.log(window.title); - } - - console.log(windows.browserWindows.length); - -Object emits all the events listed under "Events" section. - -####Examples#### - - var windows = require("windows").browserWindows; - - // add a listener to the 'open' event - windows.on('open', function(window) { - myOpenWindows.push(window); - }); - - // add a listener to the 'close' event - windows.on('close', function(window) { - console.log("A window was closed."); - }); - -<api name="activeWindow"> -@property {BrowserWindow} - -The currently active window. This property is read-only. - -**Example** - - // get - var windows = require("windows"); - console.log("title of active window is " + - windows.browserWindows.activeWindow.title); - - anotherWindow.activate(); - // set - windows.activeWindow == anotherWindow // true -</api> - -</api> - -<api name="open"> -@function -Open a new window. - - var windows = require("windows").browserWindows; - - // Open a new window. - windows.open("http://www.example.com"); - - // Open a new window and set a listener for "open" event. - windows.open({ - url: "http://www.example.com", - onOpen: function(window) { - // do stuff like listen for content - // loading. - } - }); - -Returns the window that was opened: - - var widgets = require("widget"); - var windows = require("windows").browserWindows; - - var example = windows.open("http://www.example.com"); - - var widget = widgets.Widget({ - id: "close-window", - label: "Close window", - contentURL: "http://www.mozilla.org/favicon.ico", - onClick: function() { - example.close(); - } - }); - -@param options {object} -An object containing configurable options for how this window will be opened, -as well as a callback for being notified when the window has fully opened. - -If the only option being used is `url`, then a bare string URL can be passed to -`open` instead of specifying it as a property of the `options` object. - -@prop url {string} -String URL to be opened in the new window. -This is a required property. - -@prop [onOpen] {function} -A callback function that is called when the window has opened. This does not -mean that the URL content has loaded, only that the window itself is fully -functional and its properties can be accessed. This is an optional property. - -@prop [onClose] {function} -A callback function that is called when the window will be called. -This is an optional property. - -@returns {BrowserWindow} -</api> - -<api name="BrowserWindow"> -@class -A `BrowserWindow` instance represents a single open window. They can be -retrieved from the `browserWindows` property exported by this module. - - var windows = require("windows").browserWindows; - - //Print how many tabs the current window has - console.log("The active window has " + - windows.activeWindow.tabs.length + - " tabs."); - - // Print the title of all browser windows - for each (var window in windows) { - console.log(window.title); - } - - // close the active window - windows.activeWindow.close(); - - windows.activeWindow.close(function() { - console.log("The active window was closed"); - }); - -<api name="title"> -@property {string} -The current title of the window. Usually the title of the active tab, -plus an app identifier. -This property is read-only. -</api> - -<api name="tabs"> -@property {TabList} -A live list of tabs in this window. This object has the same interface as the -[`tabs` API](packages/addon-kit/docs/tabs.html), except it contains only the -tabs in this window, not all tabs in all windows. This property is read-only. -</api> - -<api name="activate"> -@method -Makes window active, which will focus that window and bring it to the -foreground. -</api> - -<api name="close"> -@method -Close the window. - -@param [callback] {function} -A function to be called when the window finishes its closing process. -This is an optional argument. -</api> - -</api> - -<api name="open"> -@event -Event emitted when a new window is open. -This does not mean that the content has loaded, only that the browser window -itself is fully visible to the user. -@argument {Window} -Listeners are passed the `window` object that triggered the event. -</api> - -<api name="close"> -@event -Event emitted when a window is closed. -@argument {Window} -Listeners are passed the `window` object that triggered the event. -</api> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/clipboard.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/clipboard.js deleted file mode 100644 index 24f4641..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/clipboard.js +++ /dev/null @@ -1,266 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Paul O’Shannessy <paul@oshannessy.com> (Original Author) - * Dietrich Ayala <dietrich@mozilla.com> - * Myk Melez <myk@mozilla.org> - * Erik Vold <erikvvold@gmail.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -"use strict"; - -const {Cc,Ci} = require("chrome"); -const errors = require("api-utils/errors"); -const apiUtils = require("api-utils/api-utils"); - -/* -While these data flavors resemble Internet media types, they do -no directly map to them. -*/ -const kAllowableFlavors = [ - "text/unicode", - "text/html" - /* CURRENTLY UNSUPPORTED FLAVORS - "text/plain", - "image/png", - "image/jpg", - "image/gif" - "text/x-moz-text-internal", - "AOLMAIL", - "application/x-moz-file", - "text/x-moz-url", - "text/x-moz-url-data", - "text/x-moz-url-desc", - "text/x-moz-url-priv", - "application/x-moz-nativeimage", - "application/x-moz-nativehtml", - "application/x-moz-file-promise-url", - "application/x-moz-file-promise-dest-filename", - "application/x-moz-file-promise", - "application/x-moz-file-promise-dir" - */ -]; - -/* -Aliases for common flavors. Not all flavors will -get an alias. New aliases must be approved by a -Jetpack API druid. -*/ -const kFlavorMap = [ - { short: "text", long: "text/unicode" }, - { short: "html", long: "text/html" } - // Images are currently unsupported. - //{ short: "image", long: "image/png" }, -]; - -let clipboardService = Cc["@mozilla.org/widget/clipboard;1"]. - getService(Ci.nsIClipboard); - -let clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"]. - getService(Ci.nsIClipboardHelper); - - -exports.set = function(aData, aDataType) { - let options = { - data: aData, - datatype: aDataType || "text" - }; - options = apiUtils.validateOptions(options, { - data: { - is: ["string"] - }, - datatype: { - is: ["string"] - } - }); - - var flavor = fromJetpackFlavor(options.datatype); - - if (!flavor) - throw new Error("Invalid flavor"); - - // Additional checks for using the simple case - if (flavor == "text/unicode") { - clipboardHelper.copyString(options.data); - return true; - } - - // Below are the more complex cases where we actually have to work with a - // nsITransferable object - var xferable = Cc["@mozilla.org/widget/transferable;1"]. - createInstance(Ci.nsITransferable); - if (!xferable) - throw new Error("Couldn't set the clipboard due to an internal error " + - "(couldn't create a Transferable object)."); - - switch (flavor) { - case "text/html": - // add text/html flavor - let (str = Cc["@mozilla.org/supports-string;1"]. - createInstance(Ci.nsISupportsString)) - { - str.data = options.data; - xferable.addDataFlavor(flavor); - xferable.setTransferData(flavor, str, str.data.length * 2); - } - - // add a text/unicode flavor (html converted to plain text) - let (str = Cc["@mozilla.org/supports-string;1"]. - createInstance(Ci.nsISupportsString), - converter = Cc["@mozilla.org/feed-textconstruct;1"]. - createInstance(Ci.nsIFeedTextConstruct)) - { - converter.type = "html"; - converter.text = options.data; - str.data = converter.plainText(); - xferable.addDataFlavor("text/unicode"); - xferable.setTransferData("text/unicode", str, str.data.length * 2); - } - break; - // TODO: images! - default: - throw new Error("Unable to handle the flavor " + flavor + "."); - } - - // TODO: Not sure if this will ever actually throw. -zpao - try { - clipboardService.setData( - xferable, - null, - clipboardService.kGlobalClipboard - ); - } catch (e) { - throw new Error("Couldn't set clipboard data due to an internal error: " + e); - } - return true; -}; - - -exports.get = function(aDataType) { - let options = { - datatype: aDataType || "text" - }; - options = apiUtils.validateOptions(options, { - datatype: { - is: ["string"] - } - }); - - var xferable = Cc["@mozilla.org/widget/transferable;1"]. - createInstance(Ci.nsITransferable); - if (!xferable) - throw new Error("Couldn't set the clipboard due to an internal error " + - "(couldn't create a Transferable object)."); - - var flavor = fromJetpackFlavor(options.datatype); - - // Ensure that the user hasn't requested a flavor that we don't support. - if (!flavor) - throw new Error("Getting the clipboard with the flavor '" + flavor + - "' is > not supported."); - - // TODO: Check for matching flavor first? Probably not worth it. - - xferable.addDataFlavor(flavor); - - // Get the data into our transferable. - clipboardService.getData( - xferable, - clipboardService.kGlobalClipboard - ); - - var data = {}; - var dataLen = {}; - try { - xferable.getTransferData(flavor, data, dataLen); - } catch (e) { - // Clipboard doesn't contain data in flavor, return null. - return null; - } - - // There's no data available, return. - if (data.value === null) - return null; - - // TODO: Add flavors here as we support more in kAllowableFlavors. - switch (flavor) { - case "text/unicode": - case "text/html": - data = data.value.QueryInterface(Ci.nsISupportsString).data; - break; - default: - data = null; - } - - return data; -}; - -exports.__defineGetter__("currentFlavors", function() { - // Loop over kAllowableFlavors, calling hasDataMatchingFlavors for each. - // This doesn't seem like the most efficient way, but we can't get - // confirmation for specific flavors any other way. This is supposed to be - // an inexpensive call, so performance shouldn't be impacted (much). - var currentFlavors = []; - for each (var flavor in kAllowableFlavors) { - var matches = clipboardService.hasDataMatchingFlavors( - [flavor], - 1, - clipboardService.kGlobalClipboard - ); - if (matches) - currentFlavors.push(toJetpackFlavor(flavor)); - } - return currentFlavors; -}); - -// SUPPORT FUNCTIONS //////////////////////////////////////////////////////// - -function toJetpackFlavor(aFlavor) { - for each (let flavorMap in kFlavorMap) - if (flavorMap.long == aFlavor) - return flavorMap.short; - // Return null in the case where we don't match - return null; -} - -function fromJetpackFlavor(aJetpackFlavor) { - // TODO: Handle proper flavors better - for each (let flavorMap in kFlavorMap) - if (flavorMap.short == aJetpackFlavor || flavorMap.long == aJetpackFlavor) - return flavorMap.long; - // Return null in the case where we don't match. - return null; -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/context-menu.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/context-menu.js deleted file mode 100644 index c9f00f9..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/context-menu.js +++ /dev/null @@ -1,1526 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Drew Willcoxon <adw@mozilla.com> (Original Author) - * Irakli Gozalishvili <gozala@mozilla.com> - * Matteo Ferretti <zer0@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -"use strict"; - -const {Ci} = require("chrome"); - -if (!require("api-utils/xul-app").is("Firefox")) { - throw new Error([ - "The context-menu module currently supports only Firefox. In the future ", - "we would like it to support other applications, however. Please see ", - "https://bugzilla.mozilla.org/show_bug.cgi?id=560716 for more information." - ].join("")); -} - -const apiUtils = require("api-utils/api-utils"); -const collection = require("api-utils/collection"); -const { Worker } = require("api-utils/content"); -const url = require("api-utils/url"); -const { MatchPattern } = require("api-utils/match-pattern"); -const { EventEmitterTrait: EventEmitter } = require("api-utils/events"); -const observerServ = require("api-utils/observer-service"); -const jpSelf = require("self"); -const winUtils = require("api-utils/window-utils"); -const { Trait } = require("api-utils/light-traits"); -const { Cortex } = require("api-utils/cortex"); -const timer = require("timer"); - -// All user items we add have this class name. -const ITEM_CLASS = "jetpack-context-menu-item"; - -// Items in the top-level context menu also have this class. -const TOPLEVEL_ITEM_CLASS = "jetpack-context-menu-item-toplevel"; - -// Items in the overflow submenu also have this class. -const OVERFLOW_ITEM_CLASS = "jetpack-context-menu-item-overflow"; - -// The ID of the menu separator that separates standard context menu items from -// our user items. -const SEPARATOR_ID = "jetpack-context-menu-separator"; - -// If more than this number of items are added to the context menu, all items -// overflow into a "Jetpack" submenu. -const OVERFLOW_THRESH_DEFAULT = 10; -const OVERFLOW_THRESH_PREF = - "extensions.addon-sdk.context-menu.overflowThreshold"; - -// The label of the overflow sub-xul:menu. -// -// TODO: Localize this. -const OVERFLOW_MENU_LABEL = "Add-ons"; - -// The ID of the overflow sub-xul:menu. -const OVERFLOW_MENU_ID = "jetpack-content-menu-overflow-menu"; - -// The ID of the overflow submenu's xul:menupopup. -const OVERFLOW_POPUP_ID = "jetpack-content-menu-overflow-popup"; - -// These are used by PageContext.isCurrent below. If the popupNode or any of -// its ancestors is one of these, Firefox uses a tailored context menu, and so -// the page context doesn't apply. -const NON_PAGE_CONTEXT_ELTS = [ - Ci.nsIDOMHTMLAnchorElement, - Ci.nsIDOMHTMLAppletElement, - Ci.nsIDOMHTMLAreaElement, - Ci.nsIDOMHTMLButtonElement, - Ci.nsIDOMHTMLCanvasElement, - Ci.nsIDOMHTMLEmbedElement, - Ci.nsIDOMHTMLImageElement, - Ci.nsIDOMHTMLInputElement, - Ci.nsIDOMHTMLMapElement, - Ci.nsIDOMHTMLMediaElement, - Ci.nsIDOMHTMLMenuElement, - Ci.nsIDOMHTMLObjectElement, - Ci.nsIDOMHTMLOptionElement, - Ci.nsIDOMHTMLSelectElement, - Ci.nsIDOMHTMLTextAreaElement, -]; - -// This is used to access private properties of Item and Menu instances. -const PRIVATE_PROPS_KEY = { - valueOf: function valueOf() "private properties key" -}; - -// Used as an internal ID for items and as part of a public ID for item DOM -// elements. Careful: This number is not necessarily unique to any one instance -// of the module. For each module instance, when the first item is created this -// number will be 0, when the second is created it will be 1, and so on. -let nextItemID = 0; - -// The number of items that haven't finished initializing yet. See -// AIT__finishActiveItemInit(). -let numItemsWithUnfinishedInit = 0; - -exports.Item = Item; -exports.Menu = Menu; -exports.Separator = Separator; - - -// A word about traits and privates. `this` inside of traits methods is an -// object private to the implementation. It should never be publicly leaked. -// We use Cortex in the exported menu item constructors to create public -// reflections of the private objects that hide private properties -- those -// prefixed with an underscore. Public reflections are attached to the private -// objects via the `_public` property. -// -// All item objects passed into the implementation by the client will be public -// reflections, not private objects. Likewise, all item objects passed out of -// the implementation to the client must be public, not private. Mixing up -// public and private is bad and easy to do, so not only are private objects -// restricted to the implementation, but as much as possible we try to restrict -// them to the Item, Menu, and Separator traits and constructors. Everybody -// else in the implementation should expect to be passed public reflections, and -// they must specifically request private objects via privateItem(). - -// Item, Menu, and Separator are composed of this trait. -const ItemBaseTrait = Trait({ - - _initBase: function IBT__initBase(opts, optRules, optsToNotSet) { - this._optRules = optRules; - for (let optName in optRules) - if (optsToNotSet.indexOf(optName) < 0) - this[optName] = opts[optName]; - optsToNotSet.forEach(function (opt) validateOpt(opts[opt], optRules[opt])); - this._isInited = true; - - this._id = nextItemID++; - this._parentMenu = null; - - // This makes the private properties accessible to anyone with access to - // PRIVATE_PROPS_KEY. Barring loader tricks, only this file has has access - // to it, so only this file has access to the private properties. - const self = this; - this.valueOf = function IBT_valueOf(key) { - return key === PRIVATE_PROPS_KEY ? self : self._public; - }; - }, - - destroy: function IBT_destroy() { - if (this._wasDestroyed) - return; - if (this.parentMenu) - this.parentMenu.removeItem(this._public); - else if (!(this instanceof Separator) && this._hasFinishedInit) - browserManager.removeTopLevelItem(this._public); - browserManager.unregisterItem(this._public); - this._wasDestroyed = true; - }, - - get parentMenu() { - return this._parentMenu; - }, - - set parentMenu(val) { - throw new Error("The 'parentMenu' property is not intended to be set. " + - "Use menu.addItem(item) instead."); - }, - - set _isTopLevel(val) { - if (val) - this._workerReg = new WorkerRegistry(this._public); - else { - this._workerReg.destroy(); - delete this._workerReg; - } - }, - - get _topLevelItem() { - let topLevelItem = this._public; - let parentMenu = this.parentMenu; - while (parentMenu) { - topLevelItem = parentMenu; - parentMenu = parentMenu.parentMenu; - } - return topLevelItem; - } -}); - -// Item and Menu are composed of this trait. -const ActiveItemTrait = Trait.compose(ItemBaseTrait, EventEmitter, Trait({ - - _initActiveItem: function AIT__initActiveItem(opts, optRules, optsToNotSet) { - this._initBase(opts, optRules, - optsToNotSet.concat(["onMessage", "context"])); - - if ("onMessage" in opts) - this.on("message", opts.onMessage); - - // When a URL context is removed (by calling context.remove(urlContext)), we - // may need to create workers for windows containing pages that the item now - // matches. Likewise, when a URL context is added, we need to destroy - // workers for windows containing pages that the item now does not match. - // - // collection doesn't provide a way to listen for removals. utils/registry - // does, but it doesn't allow its elements to be enumerated. So as a hack, - // use a collection for item.context and replace its add and remove methods. - collection.addCollectionProperty(this, "context"); - if (opts.context) - this.context.add(opts.context); - - const self = this; - - let add = this.context.add; - this.context.add = function itemContextAdd() { - let args = Array.slice(arguments); - add.apply(self.context, args); - if (self._workerReg && args.some(function (a) a instanceof URLContext)) - self._workerReg.destroyUnneededWorkers(); - }; - - let remove = this.context.remove; - this.context.remove = function itemContextRemove() { - let args = Array.slice(arguments); - remove.apply(self.context, args); - if (self._workerReg && args.some(function (a) a instanceof URLContext)) - self._workerReg.createNeededWorkers(); - }; - }, - - // Workers are only created for top-level menu items. When a top-level item - // is later added to a Menu, its workers are destroyed. Well, all items start - // out as top-level because there is, unfortunately, no contextMenu.add(). So - // when an item is created and immediately added to a Menu, workers for it are - // needlessly created and destroyed. The point of this timeout is to avoid - // that. Items that are created and added to Menus in the same turn of the - // event loop won't have workers created for them. - _finishActiveItemInit: function AIT__finishActiveItemInit() { - numItemsWithUnfinishedInit++; - const self = this; - timer.setTimeout(function AIT__finishActiveItemInitTimeout() { - if (!self.parentMenu && !self._wasDestroyed) - browserManager.addTopLevelItem(self._public); - self._hasFinishedInit = true; - numItemsWithUnfinishedInit--; - }, 0); - }, - - get label() { - return this._label; - }, - - set label(val) { - this._label = validateOpt(val, this._optRules.label); - if (this._isInited) - browserManager.setItemLabel(this, this._label); - return this._label; - }, - - get image() { - return this._image; - }, - - set image(val) { - this._image = validateOpt(val, this._optRules.image); - if (this._isInited) - browserManager.setItemImage(this, this._image); - return this._image; - }, - - get contentScript() { - return this._contentScript; - }, - - set contentScript(val) { - this._contentScript = validateOpt(val, this._optRules.contentScript); - return this._contentScript; - }, - - get contentScriptFile() { - return this._contentScriptFile; - }, - - set contentScriptFile(val) { - this._contentScriptFile = - validateOpt(val, this._optRules.contentScriptFile); - return this._contentScriptFile; - } -})); - -// Item is composed of this trait. -const ItemTrait = Trait.compose(ActiveItemTrait, Trait({ - - _initItem: function IT__initItem(opts, optRules) { - this._initActiveItem(opts, optRules, []); - }, - - get data() { - return this._data; - }, - - set data(val) { - this._data = validateOpt(val, this._optRules.data); - if (this._isInited) - browserManager.setItemData(this, this._data); - return this._data; - }, - - toString: function IT_toString() { - return '[object Item "' + this.label + '"]'; - } -})); - -// The exported Item constructor. -function Item(options) { - let optRules = optionsRules(); - optRules.data = { - map: function (v) v.toString(), - is: ["string", "undefined"] - }; - - let item = ItemTrait.create(Item.prototype); - item._initItem(options, optRules); - - item._public = Cortex(item); - browserManager.registerItem(item._public); - item._finishActiveItemInit(); - - return item._public; -} - -// Menu is composed of this trait. -const MenuTrait = Trait.compose( - ActiveItemTrait.resolve({ destroy: "_destroyThisItem" }), - Trait({ - - _initMenu: function MT__initMenu(opts, optRules, optsToNotSet) { - this._items = []; - this._initActiveItem(opts, optRules, optsToNotSet); - }, - - destroy: function MT_destroy() { - while (this.items.length) - this.items[0].destroy(); - this._destroyThisItem(); - }, - - get items() { - return this._items; - }, - - set items(val) { - let newItems = validateOpt(val, this._optRules.items); - while (this.items.length) - this.items[0].destroy(); - newItems.forEach(function (i) this.addItem(i), this); - return newItems; - }, - - addItem: function MT_addItem(item) { - // First, remove the item from its current parent. - let privates = privateItem(item); - if (item.parentMenu) - item.parentMenu.removeItem(item); - else if (!(item instanceof Separator) && privates._hasFinishedInit) - browserManager.removeTopLevelItem(item); - - // Now add the item to this menu. - this._items.push(item); - privates._parentMenu = this._public; - browserManager.addItemToMenu(item, this._public); - }, - - removeItem: function MT_removeItem(item) { - let idx = this._items.indexOf(item); - if (idx < 0) - return; - this._items.splice(idx, 1); - privateItem(item)._parentMenu = null; - browserManager.removeItemFromMenu(item, this._public); - }, - - toString: function MT_toString() { - return '[object Menu "' + this.label + '"]'; - } -})); - -// The exported Menu constructor. -function Menu(options) { - let optRules = optionsRules(); - optRules.items = { - is: ["array"], - ok: function (v) { - return v.every(function (item) { - return (item instanceof Item) || - (item instanceof Menu) || - (item instanceof Separator); - }); - }, - msg: "items must be an array, and each element in the array must be an " + - "Item, Menu, or Separator." - }; - - let menu = MenuTrait.create(Menu.prototype); - - // We can't rely on _initBase to set the `items` property, because the menu - // needs to be registered with and added to the browserManager before any - // child items are added to it. - menu._initMenu(options, optRules, ["items"]); - - menu._public = Cortex(menu); - browserManager.registerItem(menu._public); - menu.items = options.items; - menu._finishActiveItemInit(); - - return menu._public; -} - -// The exported Separator constructor. -function Separator() { - let sep = ItemBaseTrait.create(Separator.prototype); - sep._initBase({}, {}, []); - - sep._public = Cortex(sep); - browserManager.registerItem(sep._public); - sep._hasFinishedInit = true; - return sep._public; -} - - -function Context() {} - -function PageContext() { - this.isCurrent = function PageContext_isCurrent(popupNode) { - let win = popupNode.ownerDocument.defaultView; - if (win && !win.getSelection().isCollapsed) - return false; - - let cursor = popupNode; - while (cursor && !(cursor instanceof Ci.nsIDOMHTMLHtmlElement)) { - if (NON_PAGE_CONTEXT_ELTS.some(function (iface) cursor instanceof iface)) - return false; - cursor = cursor.parentNode; - } - return true; - }; -} - -PageContext.prototype = new Context(); - -function SelectorContext(selector) { - let opts = apiUtils.validateOptions({ selector: selector }, { - selector: { - is: ["string"], - msg: "selector must be a string." - } - }); - - this.adjustPopupNode = function SelectorContext_adjustPopupNode(node) { - return closestMatchingAncestor(node); - }; - - this.isCurrent = function SelectorContext_isCurrent(popupNode) { - return !!closestMatchingAncestor(popupNode); - }; - - // Returns node if it matches selector, or the closest ancestor of node that - // matches, or null if node and none of its ancestors matches. - function closestMatchingAncestor(node) { - let cursor = node; - while (cursor) { - if (cursor.mozMatchesSelector(selector)) - return cursor; - if (cursor instanceof Ci.nsIDOMHTMLHtmlElement) - break; - cursor = cursor.parentNode; - } - return null; - } -} - -SelectorContext.prototype = new Context(); - -function SelectionContext() { - this.isCurrent = function SelectionContext_isCurrent(popupNode) { - let win = popupNode.ownerDocument.defaultView; - if (!win) - return false; - - let hasSelection = !win.getSelection().isCollapsed; - if (!hasSelection) { - // window.getSelection doesn't return a selection for text selected in a - // form field (see bug 85686), so before returning false we want to check - // if the popupNode is a text field. - let { selectionStart, selectionEnd } = popupNode; - hasSelection = !isNaN(selectionStart) && - !isNaN(selectionEnd) && - selectionStart !== selectionEnd; - } - return hasSelection; - }; -} - -SelectionContext.prototype = new Context(); - -function URLContext(patterns) { - let opts = apiUtils.validateOptions({ patterns: patterns }, { - patterns: { - map: function (v) apiUtils.getTypeOf(v) === "array" ? v : [v], - ok: function (v) v.every(function (p) typeof(p) === "string"), - msg: "patterns must be a string or an array of strings." - } - }); - try { - patterns = opts.patterns.map(function (p) new MatchPattern(p)); - } - catch (err) { - console.error("Error creating URLContext match pattern:"); - throw err; - } - - const self = this; - - this.isCurrent = function URLContext_isCurrent(popupNode) { - return self.isCurrentForURL(popupNode.ownerDocument.URL); - }; - - this.isCurrentForURL = function URLContext_isCurrentForURL(url) { - return patterns.some(function (p) p.test(url)); - }; -} - -URLContext.prototype = new Context(); - -exports.PageContext = apiUtils.publicConstructor(PageContext); -exports.SelectorContext = apiUtils.publicConstructor(SelectorContext); -exports.SelectionContext = apiUtils.publicConstructor(SelectionContext); -exports.URLContext = apiUtils.publicConstructor(URLContext); - - -// Returns a version of opt validated against the given rule. -function validateOpt(opt, rule) { - return apiUtils.validateOptions({ opt: opt }, { opt: rule }).opt; -} - -// Returns rules for apiUtils.validateOptions() common to Item and Menu. -function optionsRules() { - return { - context: { - is: ["undefined", "object", "array"], - ok: function (v) { - if (!v) - return true; - let arr = apiUtils.getTypeOf(v) === "array" ? v : [v]; - return arr.every(function (o) o instanceof Context); - }, - msg: "The 'context' option must be a Context object or an array of " + - "Context objects." - }, - label: { - map: function (v) v.toString(), - is: ["string"], - ok: function (v) !!v, - msg: "The item must have a non-empty string label." - }, - image: { - map: function (v) v.toString(), - is: ["string", "undefined", "null"] - }, - contentScript: { - is: ["string", "array", "undefined"], - ok: function (v) { - return apiUtils.getTypeOf(v) !== "array" || - v.every(function (s) typeof(s) === "string"); - } - }, - contentScriptFile: { - is: ["string", "array", "undefined"], - ok: function (v) { - if (!v) - return true; - let arr = apiUtils.getTypeOf(v) === "array" ? v : [v]; - try { - return arr.every(function (s) { - return apiUtils.getTypeOf(s) === "string" && url.toFilename(s); - }); - } - catch (err) {} - return false; - }, - msg: "The 'contentScriptFile' option must be a local file URL or " + - "an array of local file URLs." - }, - onMessage: { - is: ["function", "undefined"] - } - }; -} - -// Does a binary search on elts, a NodeList, and returns the DOM element -// before which an item with targetLabel should be inserted. null is returned -// if the new item should be inserted at the end. -function insertionPoint(targetLabel, elts) { - let from = 0; - let to = elts.length - 1; - - while (from <= to) { - let i = Math.floor((from + to) / 2); - let comp = targetLabel.localeCompare(elts[i].getAttribute("label")); - if (comp < 0) - to = i - 1; - else if (comp > 0) - from = i + 1; - else - return elts[i]; - } - return elts[from] || null; -} - -// Builds an ID suitable for a DOM element from the given item ID. -// isInOverflowSubtree should be true if the returned element will be inserted -// into the DOM subtree rooted at the overflow menu. -function domEltIDFromItemID(itemID, isInOverflowSubtree) { - let suffix = isInOverflowSubtree ? "-overflow" : ""; - return jpSelf.id + "-context-menu-item-" + itemID + suffix; -} - -// Parses the item ID out of the given DOM element ID and returns it. If the -// element's ID is malformed or it indicates that the element was not created by -// the instance of the module calling this function, returns -1. -function itemIDFromDOMEltID(domEltID) { - let match = /^(.+?)-context-menu-item-([0-9]+)[-a-z]*$/.exec(domEltID); - return !match || match[1] !== jpSelf.id ? -1 : match[2]; -} - -// Returns the private version of the given public reflection. -function privateItem(publicItem) { - return publicItem.valueOf(PRIVATE_PROPS_KEY); -} - - -// A type of Worker tailored to our uses. -const ContextMenuWorker = Worker.compose({ - destroy: Worker.required, - - // Returns true if any context listeners are defined in the worker's port. - anyContextListeners: function CMW_anyContextListeners() { - return this._contentWorker._listeners("context").length > 0; - }, - - // Returns the first string or truthy value returned by a context listener in - // the worker's port. If none return a string or truthy value or if there are - // no context listeners, returns false. popupNode is the node that was - // context-clicked. - isAnyContextCurrent: function CMW_isAnyContextCurrent(popupNode) { - let listeners = this._contentWorker._listeners("context"); - for (let i = 0; i < listeners.length; i++) { - try { - let val = listeners[i].call(this._contentWorker._sandbox, popupNode); - if (typeof(val) === "string" || val) - return val; - } - catch (err) { - console.exception(err); - } - } - return false; - }, - - // Emits a click event in the worker's port. popupNode is the node that was - // context-clicked, and clickedItemData is the data of the item that was - // clicked. - fireClick: function CMW_fireClick(popupNode, clickedItemData) { - this._contentWorker._asyncEmit("click", popupNode, clickedItemData); - } -}); - - -// This class creates and stores content workers for pairs of menu items and -// content windows. Use one instance for each item. Not all pairs need a -// worker: if an item has a URL context that does not match a window's page, -// then no worker is created for the pair. -function WorkerRegistry(item) { - this.item = item; - - // inner window ID => { win, worker } - this.winWorkers = {}; - - // inner window ID => content window - this.winsWithoutWorkers = {}; -} - -WorkerRegistry.prototype = { - - // Registers a content window, creating a worker for it if it needs one. - registerContentWin: function WR_registerContentWin(win) { - let innerWinID = winUtils.getInnerId(win); - if ((innerWinID in this.winWorkers) || - (innerWinID in this.winsWithoutWorkers)) - return; - if (this._doesURLNeedWorker(win.document.URL)) - this.winWorkers[innerWinID] = { win: win, worker: this._makeWorker(win) }; - else - this.winsWithoutWorkers[innerWinID] = win; - }, - - // Unregisters a content window, destroying its related worker if it has one. - unregisterContentWin: function WR_unregisterContentWin(innerWinID) { - if (innerWinID in this.winWorkers) { - let winWorker = this.winWorkers[innerWinID]; - winWorker.worker.destroy(); - delete winWorker.worker; - delete winWorker.win; - delete this.winWorkers[innerWinID]; - } - else - delete this.winsWithoutWorkers[innerWinID]; - }, - - // Creates a worker for each window that needs a worker but doesn't have one. - createNeededWorkers: function WR_createNeededWorkers() { - for (let [innerWinID, win] in Iterator(this.winsWithoutWorkers)) { - delete this.winsWithoutWorkers[innerWinID]; - this.registerContentWin(win); - } - }, - - // Destroys the worker for each window that has a worker but doesn't need it. - destroyUnneededWorkers: function WR_destroyUnneededWorkers() { - for (let [innerWinID, winWorker] in Iterator(this.winWorkers)) { - if (!this._doesURLNeedWorker(winWorker.win.document.URL)) { - this.unregisterContentWin(innerWinID); - this.winsWithoutWorkers[innerWinID] = winWorker.win; - } - } - }, - - // Returns the worker for the item-window pair or null if none exists. - find: function WR_find(contentWin) { - let innerWinID = winUtils.getInnerId(contentWin); - return (innerWinID in this.winWorkers) ? - this.winWorkers[innerWinID].worker : - null; - }, - - // Unregisters all content windows from the registry, which destroys all - // workers. - destroy: function WR_destroy() { - for (let innerWinID in this.winWorkers) - this.unregisterContentWin(innerWinID); - for (let innerWinID in this.winsWithoutWorkers) - this.unregisterContentWin(innerWinID); - }, - - // Returns false if the item has a URL context that does not match the given - // URL. - _doesURLNeedWorker: function WR__doesURLNeedWorker(url) { - for (let ctxt in this.item.context) - if ((ctxt instanceof URLContext) && !ctxt.isCurrentForURL(url)) - return false; - return true; - }, - - _makeWorker: function WR__makeWorker(win) { - let worker = ContextMenuWorker({ - window: win, - contentScript: this.item.contentScript, - contentScriptFile: this.item.contentScriptFile, - onError: function (err) console.exception(err) - }); - let item = this.item; - worker.on("message", function workerOnMessage(msg) { - try { - privateItem(item)._emitOnObject(item, "message", msg); - } - catch (err) { - console.exception(err); - } - }); - return worker; - } -}; - - -// Mirrors state across all browser windows. Also responsible for detecting -// all content window loads and unloads. -let browserManager = { - topLevelItems: [], - browserWins: [], - - // inner window ID => content window - contentWins: {}, - - // Call this when a new item is created, top-level or not. - registerItem: function BM_registerItem(item) { - this.browserWins.forEach(function (w) w.registerItem(item)); - }, - - // Call this when an item is destroyed and won't be used again, top-level or - // not. - unregisterItem: function BM_unregisterItem(item) { - this.browserWins.forEach(function (w) w.unregisterItem(item)); - }, - - addTopLevelItem: function BM_addTopLevelItem(item) { - this.topLevelItems.push(item); - this.browserWins.forEach(function (w) w.addTopLevelItem(item)); - - // Create the item's worker registry and register all currently loaded - // content windows with it. - let privates = privateItem(item); - privates._isTopLevel = true; - for each (let win in this.contentWins) - privates._workerReg.registerContentWin(win); - }, - - removeTopLevelItem: function BM_removeTopLevelItem(item) { - let idx = this.topLevelItems.indexOf(item); - if (idx < 0) - throw new Error("Internal error: item not in top-level menu: " + item); - this.topLevelItems.splice(idx, 1); - this.browserWins.forEach(function (w) w.removeTopLevelItem(item)); - privateItem(item)._isTopLevel = false; - }, - - addItemToMenu: function BM_addItemToMenu(item, parentMenu) { - this.browserWins.forEach(function (w) w.addItemToMenu(item, parentMenu)); - }, - - removeItemFromMenu: function BM_removeItemFromMenu(item, parentMenu) { - this.browserWins.forEach(function (w) w.removeItemFromMenu(item, - parentMenu)); - }, - - setItemLabel: function BM_setItemLabel(item, label) { - this.browserWins.forEach(function (w) w.setItemLabel(item, label)); - }, - - setItemImage: function BM_setItemImage(item, imageURL) { - this.browserWins.forEach(function (w) w.setItemImage(item, imageURL)); - }, - - setItemData: function BM_setItemData(item, data) { - this.browserWins.forEach(function (w) w.setItemData(item, data)); - }, - - // Note that calling this method will cause onTrack to be called immediately - // for each currently open browser window. - init: function BM_init() { - require("api-utils/unload").ensure(this); - let windowTracker = new winUtils.WindowTracker(this); - - // Register content windows on content-document-global-created and - // unregister them on inner-window-destroyed. For rationale, see bug 667957 - // for the former and bug 642004 for the latter. - observerServ.add("content-document-global-created", - this._onDocGlobalCreated, this); - observerServ.add("inner-window-destroyed", - this._onInnerWinDestroyed, this); - }, - - _onDocGlobalCreated: function BM__onDocGlobalCreated(contentWin) { - let doc = contentWin.document; - if (doc.readyState == "loading") { - const self = this; - doc.addEventListener("readystatechange", function onReadyStateChange(e) { - if (e.target != doc || doc.readyState != "complete") - return; - doc.removeEventListener("readystatechange", onReadyStateChange, false); - self._registerContentWin(contentWin); - }, false); - } - else if (doc.readyState == "complete") - this._registerContentWin(contentWin); - }, - - _onInnerWinDestroyed: function BM__onInnerWinDestroyed(subj) { - this._unregisterContentWin( - subj.QueryInterface(Ci.nsISupportsPRUint64).data); - }, - - // Stores the given content window with the manager and registers it with each - // top-level item's worker registry. - _registerContentWin: function BM__registerContentWin(win) { - let innerID = winUtils.getInnerId(win); - - // It's an error to call this method for the same window more than once, but - // we allow it in one case: when onTrack races _onDocGlobalCreated. (See - // the comment in onTrack.) Make sure the window is registered only once. - if (innerID in this.contentWins) - return; - - this.contentWins[innerID] = win; - this.topLevelItems.forEach(function (item) { - privateItem(item)._workerReg.registerContentWin(win); - }); - }, - - // Removes the given content window from the manager and unregisters it from - // each top-level item's worker registry. - _unregisterContentWin: function BM__unregisterContentWin(innerID) { - delete this.contentWins[innerID]; - this.topLevelItems.forEach(function (item) { - privateItem(item)._workerReg.unregisterContentWin(innerID); - }); - }, - - unload: function BM_unload() { - // The window tracker is unloaded at the same time this method is called, - // which causes onUntrack to be called for each open browser window, so - // there's no need to clean up browser windows here. - - while (this.topLevelItems.length) { - let item = this.topLevelItems[0]; - this.removeTopLevelItem(item); - this.unregisterItem(item); - } - delete this.contentWins; - }, - - // Registers a browser window with the manager. This is a WindowTracker - // callback. Note that this is called in two cases: for each newly opened - // chrome window, and for each chrome window that is open when the loader - // loads this module. - onTrack: function BM_onTrack(window) { - if (!this._isBrowserWindow(window)) - return; - - let browserWin = new BrowserWindow(window); - this.browserWins.push(browserWin); - - // Register all loaded content windows in the browser window. Be sure to - // include frames and iframes. If onTrack is called as a result of a new - // browser window being opened, as opposed to the module being loaded, then - // this will race the content-document-global-created notification. That's - // OK, since _registerContentWin will not register the same content window - // more than once. - window.gBrowser.browsers.forEach(function (browser) { - let topContentWin = browser.contentWindow; - let allContentWins = Array.slice(topContentWin.frames); - allContentWins.push(topContentWin); - allContentWins.forEach(function (contentWin) { - if (contentWin.document.readyState == "complete") - this._registerContentWin(contentWin); - }, this); - }, this); - - // Add all top-level items and, recursively, their child items to the new - // browser window. - function addItemTree(item, parentMenu) { - browserWin.registerItem(item); - if (parentMenu) - browserWin.addItemToMenu(item, parentMenu); - else - browserWin.addTopLevelItem(item); - if (item instanceof Menu) - item.items.forEach(function (subitem) addItemTree(subitem, item)); - } - this.topLevelItems.forEach(function (item) addItemTree(item, null)); - }, - - // Unregisters a browser window from the manager. This is a WindowTracker - // callback. Note that this is called in two cases: for each newly closed - // chrome window, and for each chrome window that is open when this module is - // unloaded. - onUntrack: function BM_onUntrack(window) { - if (!this._isBrowserWindow(window)) - return; - - // Remove the window from the window list. - let idx = 0; - for (; idx < this.browserWins.length; idx++) - if (this.browserWins[idx].window == window) - break; - if (idx == this.browserWins.length) - throw new Error("Internal error: browser window not found"); - let browserWin = this.browserWins.splice(idx, 1)[0]; - - // Remove all top-level items from the window. - this.topLevelItems.forEach(function (i) browserWin.removeTopLevelItem(i)); - browserWin.destroy(); - }, - - _isBrowserWindow: function BM__isBrowserWindow(win) { - let winType = win.document.documentElement.getAttribute("windowtype"); - return winType === "navigator:browser"; - } -}; - - -// Responsible for creating and managing context menu item DOM elements for a -// browser window. Also responsible for providing a description of the window's -// current context and determining whether an item matches the current context. -// -// TODO: If other apps besides Firefox want to support the context menu in -// whatever way is appropriate for them, plugging in a substitute for or an -// adapter to this class should be the way to do it. Make it easy for them. -// See bug 560716. -function BrowserWindow(window) { - this.window = window; - this.doc = window.document; - - let popupDOMElt = this.doc.getElementById("contentAreaContextMenu"); - if (!popupDOMElt) - throw new Error("Internal error: Context menu popup not found."); - this.contextMenuPopup = new ContextMenuPopup(popupDOMElt, this); - - // item ID => { item, domElt, overflowDOMElt, popup, overflowPopup } - // item may or may not be top-level. domElt is the item's DOM element - // contained in the subtree rooted in the top-level context menu. - // overflowDOMElt is the item's DOM element contained in the subtree rooted in - // the overflow submenu. popup and overflowPopup are only defined if the item - // is a Menu; they're the Popup instances containing the Menu's child items, - // with the aforementioned distinction between top-level and overflow - // subtrees. - this.items = {}; -} - -BrowserWindow.prototype = { - - // Creates and stores DOM elements for the given item, top-level or not. - registerItem: function BW_registerItem(item) { - // this.items[id] is referenced by _makeMenu, so it needs to be defined - // before _makeDOMElt is called. - let props = { item: item }; - this.items[privateItem(item)._id] = props; - props.domElt = this._makeDOMElt(item, false); - props.overflowDOMElt = this._makeDOMElt(item, true); - }, - - // Removes the given item's DOM elements from the store. - unregisterItem: function BW_unregisterItem(item) { - delete this.items[privateItem(item)._id]; - }, - - addTopLevelItem: function BW_addTopLevelItem(item) { - this.contextMenuPopup.addItem(item); - }, - - removeTopLevelItem: function BW_removeTopLevelItem(item) { - this.contextMenuPopup.removeItem(item); - }, - - addItemToMenu: function BW_addItemToMenu(item, parentMenu) { - let { popup, overflowPopup } = this.items[privateItem(parentMenu)._id]; - popup.addItem(item); - overflowPopup.addItem(item); - }, - - removeItemFromMenu: function BW_removeItemFromMenu(item, parentMenu) { - let { popup, overflowPopup } = this.items[privateItem(parentMenu)._id]; - popup.removeItem(item); - overflowPopup.removeItem(item); - }, - - setItemLabel: function BW_setItemLabel(item, label) { - let privates = privateItem(item); - let { domElt, overflowDOMElt } = this.items[privates._id]; - this._setDOMEltLabel(domElt, label); - this._setDOMEltLabel(overflowDOMElt, label); - if (!item.parentMenu && privates._hasFinishedInit) - this.contextMenuPopup.itemLabelDidChange(item); - }, - - _setDOMEltLabel: function BW__setDOMEltLabel(domElt, label) { - domElt.setAttribute("label", label); - }, - - setItemImage: function BW_setItemImage(item, imageURL) { - let { domElt, overflowDOMElt } = this.items[privateItem(item)._id]; - let isMenu = item instanceof Menu; - this._setDOMEltImage(domElt, imageURL, isMenu); - this._setDOMEltImage(overflowDOMElt, imageURL, isMenu); - }, - - _setDOMEltImage: function BW__setDOMEltImage(domElt, imageURL, isMenu) { - if (!imageURL) { - domElt.removeAttribute("image"); - domElt.classList.remove("menu-iconic"); - domElt.classList.remove("menuitem-iconic"); - } - else { - domElt.setAttribute("image", imageURL); - domElt.classList.add(isMenu ? "menu-iconic" : "menuitem-iconic"); - } - }, - - setItemData: function BW_setItemData(item, data) { - let { domElt, overflowDOMElt } = this.items[privateItem(item)._id]; - this._setDOMEltData(domElt, data); - this._setDOMEltData(overflowDOMElt, data); - }, - - _setDOMEltData: function BW__setDOMEltData(domElt, data) { - domElt.setAttribute("value", data); - }, - - // The context specified for a top-level item may not match exactly the real - // context that triggers it. For example, if the user context-clicks a span - // inside an anchor, we want items that specify an anchor context to be - // triggered, but the real context will indicate that the span was clicked, - // not the anchor. Where the real context and an item's context conflict, - // clients should be given the item's context, and this method can be used to - // make such adjustments. Returns an adjusted popupNode. - adjustPopupNode: function BW_adjustPopupNode(popupNode, topLevelItem) { - for (let ctxt in topLevelItem.context) { - if (typeof(ctxt.adjustPopupNode) === "function") { - let ctxtNode = ctxt.adjustPopupNode(popupNode); - if (ctxtNode) { - popupNode = ctxtNode; - break; - } - } - } - return popupNode; - }, - - // Returns true if all of item's contexts are current in the window. - areAllContextsCurrent: function BW_areAllContextsCurrent(item, popupNode) { - let win = popupNode.ownerDocument.defaultView; - let worker = privateItem(item)._workerReg.find(win); - - // If the worker for the item-window pair doesn't exist (e.g., because the - // page hasn't loaded yet), we can't really make a good decision since the - // content script may have a context listener. So just don't show the item - // at all. - if (!worker) - return false; - - // If there are no contexts given at all, the page context applies. - let hasContentContext = worker.anyContextListeners(); - if (!hasContentContext && !item.context.length) - return new PageContext().isCurrent(popupNode); - - // Otherwise, determine if all given contexts are current. Evaluate the - // declarative contexts first and the worker's context listeners last. That - // way the listener might be able to avoid some work. - let curr = true; - for (let ctxt in item.context) { - curr = curr && ctxt.isCurrent(popupNode); - if (!curr) - return false; - } - return !hasContentContext || worker.isAnyContextCurrent(popupNode); - }, - - // Sets this.popupNode to the node the user context-clicked to invoke the - // context menu. For Gecko 2.0 and later, triggerNode is this node; if it's - // falsey, document.popupNode is used. Returns the popupNode. - capturePopupNode: function BW_capturePopupNode(triggerNode) { - this.popupNode = triggerNode || this.doc.popupNode; - if (!this.popupNode) - console.warn("popupNode is null."); - return this.popupNode; - }, - - destroy: function BW_destroy() { - this.contextMenuPopup.destroy(); - delete this.window; - delete this.doc; - delete this.items; - }, - - // Emits a click event in the port of the content worker related to given top- - // level item and popupNode's content window. Listeners will be passed - // popupNode and clickedItemData. - fireClick: function BW_fireClick(topLevelItem, popupNode, clickedItemData) { - let win = popupNode.ownerDocument.defaultView; - let worker = privateItem(topLevelItem)._workerReg.find(win); - if (worker) - worker.fireClick(popupNode, clickedItemData); - }, - - _makeDOMElt: function BW__makeDOMElt(item, isInOverflowSubtree) { - let elt = item instanceof Item ? this._makeMenuitem(item) : - item instanceof Menu ? this._makeMenu(item, isInOverflowSubtree) : - item instanceof Separator ? this._makeSeparator() : - null; - if (!elt) - throw new Error("Internal error: can't make element, unknown item type"); - - elt.id = domEltIDFromItemID(privateItem(item)._id, isInOverflowSubtree); - elt.classList.add(ITEM_CLASS); - return elt; - }, - - // Returns a new xul:menu representing the menu. - _makeMenu: function BW__makeMenu(menu, isInOverflowSubtree) { - let menuElt = this.doc.createElement("menu"); - this._setDOMEltLabel(menuElt, menu.label); - if (menu.image) - this._setDOMEltImage(menuElt, menu.image, true); - let popupElt = this.doc.createElement("menupopup"); - menuElt.appendChild(popupElt); - - let popup = new Popup(popupElt, this, isInOverflowSubtree); - let props = this.items[privateItem(menu)._id]; - if (isInOverflowSubtree) - props.overflowPopup = popup; - else - props.popup = popup; - - return menuElt; - }, - - // Returns a new xul:menuitem representing the item. - _makeMenuitem: function BW__makeMenuitem(item) { - let elt = this.doc.createElement("menuitem"); - this._setDOMEltLabel(elt, item.label); - if (item.image) - this._setDOMEltImage(elt, item.image, false); - if (item.data) - this._setDOMEltData(elt, item.data); - return elt; - }, - - // Returns a new xul:menuseparator. - _makeSeparator: function BW__makeSeparator() { - return this.doc.createElement("menuseparator"); - } -}; - - -// Responsible for adding DOM elements to and removing them from poupDOMElt. -function Popup(popupDOMElt, browserWin, isInOverflowSubtree) { - this.popupDOMElt = popupDOMElt; - this.browserWin = browserWin; - this.isInOverflowSubtree = isInOverflowSubtree; -} - -Popup.prototype = { - - addItem: function Popup_addItem(item) { - let props = this.browserWin.items[privateItem(item)._id]; - let elt = this.isInOverflowSubtree ? props.overflowDOMElt : props.domElt; - this.popupDOMElt.appendChild(elt); - }, - - removeItem: function Popup_removeItem(item) { - let props = this.browserWin.items[privateItem(item)._id]; - let elt = this.isInOverflowSubtree ? props.overflowDOMElt : props.domElt; - this.popupDOMElt.removeChild(elt); - } -}; - - -// Represents a browser window's context menu popup. Responsible for hiding and -// showing items according to the browser window's current context and for -// handling item clicks. -function ContextMenuPopup(popupDOMElt, browserWin) { - this.popupDOMElt = popupDOMElt; - this.browserWin = browserWin; - this.doc = popupDOMElt.ownerDocument; - - // item ID => item - // Calling this variable "topLevelItems" is redundant, since Popup and - // ContextMenuPopup are only responsible for their child items, not all their - // descendant items. But calling it "items" might encourage one to believe - // otherwise, so topLevelItems it is. - this.topLevelItems = {}; - - popupDOMElt.addEventListener("popupshowing", this, false); - popupDOMElt.addEventListener("command", this, false); -} - -ContextMenuPopup.prototype = { - - addItem: function CMP_addItem(item) { - this._ensureStaticEltsExist(); - let itemID = privateItem(item)._id; - this.topLevelItems[itemID] = item; - let props = this.browserWin.items[itemID]; - props.domElt.classList.add(TOPLEVEL_ITEM_CLASS); - props.overflowDOMElt.classList.add(OVERFLOW_ITEM_CLASS); - this._insertItemInSortedOrder(item); - }, - - removeItem: function CMP_removeItem(item) { - let itemID = privateItem(item)._id; - delete this.topLevelItems[itemID]; - let { domElt, overflowDOMElt } = this.browserWin.items[itemID]; - domElt.classList.remove(TOPLEVEL_ITEM_CLASS); - overflowDOMElt.classList.remove(OVERFLOW_ITEM_CLASS); - this.popupDOMElt.removeChild(domElt); - this._overflowPopup.removeChild(overflowDOMElt); - }, - - // Call this after the item's label changes. This re-inserts the item into - // the popup so that it remains in sorted order. - itemLabelDidChange: function CMP_itemLabelDidChange(item) { - let itemID = privateItem(item)._id; - let { domElt, overflowDOMElt } = this.browserWin.items[itemID]; - this.popupDOMElt.removeChild(domElt); - this._overflowPopup.removeChild(overflowDOMElt); - this._insertItemInSortedOrder(item); - }, - - destroy: function CMP_destroy() { - // If there are no more items from any instance of the module, remove the - // separator and overflow submenu, if they exist. - let elts = this._topLevelElts; - if (!elts.length) { - let submenu = this._overflowMenu; - if (submenu) - this.popupDOMElt.removeChild(submenu); - - let sep = this._separator; - if (sep) - this.popupDOMElt.removeChild(sep); - } - - this.popupDOMElt.removeEventListener("popupshowing", this, false); - this.popupDOMElt.removeEventListener("command", this, false); - }, - - handleEvent: function CMP_handleEvent(event) { - try { - if (event.type === "command") - this._handleClick(event.target); - else if (event.type === "popupshowing" && - event.target === this.popupDOMElt) - this._handlePopupShowing(); - } - catch (err) { - console.exception(err); - } - }, - - // command events bubble to the context menu's top-level xul:menupopup and are - // caught here. - _handleClick: function CMP__handleClick(clickedDOMElt) { - if (!clickedDOMElt.classList.contains(ITEM_CLASS)) - return; - let itemID = itemIDFromDOMEltID(clickedDOMElt.id); - if (itemID < 0) - return; - let { item, domElt, overflowDOMElt } = this.browserWin.items[itemID]; - - // Bail if the DOM element was not created by this module instance. In - // real-world add-ons, the itemID < 0 check above is sufficient, but for the - // unit test the JID never changes, making this necessary. - if (clickedDOMElt != domElt && clickedDOMElt != overflowDOMElt) - return; - - let topLevelItem = privateItem(item)._topLevelItem; - let popupNode = this.browserWin.adjustPopupNode(this.browserWin.popupNode, - topLevelItem); - this.browserWin.fireClick(topLevelItem, popupNode, item.data); - }, - - // popupshowing is used to show top-level items that match the browser - // window's current context and hide items that don't. Each module instance - // is responsible for showing and hiding the items it owns. - _handlePopupShowing: function CMP__handlePopupShowing() { - // If there are items queued up to finish initializing, let them go first. - // Otherwise the overflow submenu and menu separator may end up in an - // inappropriate state when those items are later added to the menu. - if (numItemsWithUnfinishedInit) { - const self = this; - timer.setTimeout(function popupShowingTryAgain() { - self._handlePopupShowing(); - }, 0); - return; - } - - // popupDOMElt.triggerNode was added in Gecko 2.0 by bug 383930. The || is - // to avoid a Spidermonkey strict warning on earlier versions. - let triggerNode = this.popupDOMElt.triggerNode || undefined; - let popupNode = this.browserWin.capturePopupNode(triggerNode); - - // Show and hide items. Set a "jetpackContextCurrent" property on the - // DOM elements to signal which of our items match the current context. - for (let [itemID, item] in Iterator(this.topLevelItems)) { - let areContextsCurr = - this.browserWin.areAllContextsCurrent(item, popupNode); - - // Change the item's label if the return value was a string. - if (typeof(areContextsCurr) === "string") { - item.label = areContextsCurr; - areContextsCurr = true; - } - - let { domElt, overflowDOMElt } = this.browserWin.items[itemID]; - domElt.jetpackContextCurrent = areContextsCurr; - domElt.hidden = !areContextsCurr; - overflowDOMElt.jetpackContextCurrent = areContextsCurr; - overflowDOMElt.hidden = !areContextsCurr; - } - - // Get the total number of items that match the current context. It's a - // little tricky: There may be other instances of this module loaded, - // each hiding and showing their items. So we can't base this number on - // only our items, or on the hidden state of items. That's why we set - // the jetpackContextCurrent property above. The last instance to run - // will leave the menupopup in the correct state. - let elts = this._topLevelElts; - let numShown = Array.reduce(elts, function (total, elt) { - return total + (elt.jetpackContextCurrent ? 1 : 0); - }, 0); - - // If too many items are shown, show the submenu and hide the top-level - // items. Otherwise, hide the submenu and show the top-level items. - let overflow = numShown > this._overflowThreshold; - if (overflow) - Array.forEach(elts, function (e) e.hidden = true); - - let submenu = this._overflowMenu; - if (submenu) - submenu.hidden = !overflow; - - // If no items are shown, hide the menu separator. - let sep = this._separator; - if (sep) - sep.hidden = numShown === 0; - }, - - // Adds the menu separator and overflow submenu if they don't exist. - _ensureStaticEltsExist: function CMP__ensureStaticEltsExist() { - let sep = this._separator; - if (!sep) { - sep = this._makeSeparator(); - this.popupDOMElt.appendChild(sep); - } - - let submenu = this._overflowMenu; - if (!submenu) { - submenu = this._makeOverflowMenu(); - submenu.hidden = true; - this.popupDOMElt.insertBefore(submenu, sep.nextSibling); - } - }, - - // Inserts the given item's DOM element into the popup in sorted order. - _insertItemInSortedOrder: function CMP__insertItemInSortedOrder(item) { - let props = this.browserWin.items[privateItem(item)._id]; - this.popupDOMElt.insertBefore( - props.domElt, insertionPoint(item.label, this._topLevelElts)); - this._overflowPopup.insertBefore( - props.overflowDOMElt, insertionPoint(item.label, this._overflowElts)); - }, - - // Creates and returns the xul:menu that's shown when too many items are added - // to the popup. - _makeOverflowMenu: function CMP__makeOverflowMenu() { - let submenu = this.doc.createElement("menu"); - submenu.id = OVERFLOW_MENU_ID; - submenu.setAttribute("label", OVERFLOW_MENU_LABEL); - let popup = this.doc.createElement("menupopup"); - popup.id = OVERFLOW_POPUP_ID; - submenu.appendChild(popup); - return submenu; - }, - - // Creates and returns the xul:menuseparator that separates the standard - // context menu items from our items. - _makeSeparator: function CMP__makeSeparator() { - let elt = this.doc.createElement("menuseparator"); - elt.id = SEPARATOR_ID; - return elt; - }, - - // Returns the item elements contained in the overflow menu, a NodeList. - get _overflowElts() { - return this._overflowPopup.getElementsByClassName(OVERFLOW_ITEM_CLASS); - }, - - // Returns the overflow xul:menu. - get _overflowMenu() { - return this.doc.getElementById(OVERFLOW_MENU_ID); - }, - - // Returns the overflow xul:menupopup. - get _overflowPopup() { - return this.doc.getElementById(OVERFLOW_POPUP_ID); - }, - - // Returns the OVERFLOW_THRESH_PREF pref value if it exists or - // OVERFLOW_THRESH_DEFAULT if it doesn't. - get _overflowThreshold() { - let prefs = require("api-utils/preferences-service"); - return prefs.get(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT); - }, - - // Returns the xul:menuseparator. - get _separator() { - return this.doc.getElementById(SEPARATOR_ID); - }, - - // Returns the item elements contained in the top-level menu, a NodeList. - get _topLevelElts() { - return this.popupDOMElt.getElementsByClassName(TOPLEVEL_ITEM_CLASS); - } -}; - - -// Init the browserManager only after setting prototypes and such above, because -// it will cause browserManager.onTrack to be called immediately if there are -// open windows. -browserManager.init(); diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/hotkeys.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/hotkeys.js deleted file mode 100644 index f8c6434..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/hotkeys.js +++ /dev/null @@ -1,71 +0,0 @@ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Irakli Gozalishvili <gozala@mozilla.com> (Original Author) - * Henri Wiechers <hwiechers@gmail.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -"use strict"; - -const INVALID_HOTKEY = "Hotkey must have at least one modifier."; - -const { toJSON: jsonify, toString: stringify, - isFunctionKey } = require("api-utils/keyboard/utils"); -const { register, unregister } = require("api-utils/keyboard/hotkeys"); - -const Hotkey = exports.Hotkey = function Hotkey(options) { - if (!(this instanceof Hotkey)) - return new Hotkey(options); - - // Parsing key combination string. - let hotkey = jsonify(options.combo); - if (!isFunctionKey(hotkey.key) && !hotkey.modifiers.length) { - throw new TypeError(INVALID_HOTKEY); - } - - this.onPress = options.onPress; - this.toString = stringify.bind(null, hotkey); - // Registering listener on keyboard combination enclosed by this hotkey. - // Please note that `this.toString()` is a normalized version of - // `options.combination` where order of modifiers is sorted and `accel` is - // replaced with platform specific key. - register(this.toString(), this.onPress); - // We freeze instance before returning it in order to make it's properties - // read-only. - return Object.freeze(this); -}; -Hotkey.prototype.destroy = function destroy() { - unregister(this.toString(), this.onPress); -}; diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/notifications.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/notifications.js deleted file mode 100644 index f2a4ea2..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/notifications.js +++ /dev/null @@ -1,112 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim:set ts=2 sw=2 sts=2 et filetype=javascript - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Drew Willcoxon <adw@mozilla.com> (Original Author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -"use strict"; - -const { Cc, Ci, Cr } = require("chrome"); -const apiUtils = require("api-utils/api-utils"); -const errors = require("api-utils/errors"); - -try { - let alertServ = Cc["@mozilla.org/alerts-service;1"]. - getService(Ci.nsIAlertsService); - - // The unit test sets this to a mock notification function. - var notify = alertServ.showAlertNotification.bind(alertServ); -} -catch (err) { - // An exception will be thrown if the platform doesn't provide an alert - // service, e.g., if Growl is not installed on OS X. In that case, use a - // mock notification function that just logs to the console. - notify = notifyUsingConsole; -} - -exports.notify = function notifications_notify(options) { - let valOpts = validateOptions(options); - let clickObserver = !valOpts.onClick ? null : { - observe: function notificationClickObserved(subject, topic, data) { - if (topic === "alertclickcallback") - errors.catchAndLog(valOpts.onClick).call(exports, valOpts.data); - } - }; - function notifyWithOpts(notifyFn) { - notifyFn(valOpts.iconURL, valOpts.title, valOpts.text, !!clickObserver, - valOpts.data, clickObserver); - } - try { - notifyWithOpts(notify); - } - catch (err if err instanceof Ci.nsIException && - err.result == Cr.NS_ERROR_FILE_NOT_FOUND) { - console.warn("The notification icon named by " + valOpts.iconURL + - " does not exist. A default icon will be used instead."); - delete valOpts.iconURL; - notifyWithOpts(notify); - } - catch (err) { - notifyWithOpts(notifyUsingConsole); - } -}; - -function notifyUsingConsole(iconURL, title, text) { - title = title ? "[" + title + "]" : ""; - text = text || ""; - let str = [title, text].filter(function (s) s).join(" "); - console.log(str); -} - -function validateOptions(options) { - return apiUtils.validateOptions(options, { - data: { - is: ["string", "undefined"] - }, - iconURL: { - is: ["string", "undefined"] - }, - onClick: { - is: ["function", "undefined"] - }, - text: { - is: ["string", "undefined"] - }, - title: { - is: ["string", "undefined"] - } - }); -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/page-mod.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/page-mod.js deleted file mode 100644 index d511464..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/page-mod.js +++ /dev/null @@ -1,229 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack Packages. - * - * The Initial Developer of the Original Code is Nickolay Ponomarev. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Nickolay Ponomarev <asqueella@gmail.com> (Original Author) - * Irakli Gozalishvili <gozala@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -"use strict"; - -const observers = require("api-utils/observer-service"); -const { Worker, Loader } = require('api-utils/content'); -const { EventEmitter } = require('api-utils/events'); -const { List } = require('api-utils/list'); -const { Registry } = require('api-utils/utils/registry'); -const xulApp = require("api-utils/xul-app"); -const { MatchPattern } = require('api-utils/match-pattern'); - -// Whether or not the host application dispatches a document-element-inserted -// notification when the document element is inserted into the DOM of a page. -// The notification was added in Gecko 2.0b6, it's a better time to attach -// scripts with contentScriptWhen "start" than content-document-global-created, -// since libraries like jQuery assume the presence of the document element. -const HAS_DOCUMENT_ELEMENT_INSERTED = - xulApp.versionInRange(xulApp.platformVersion, "2.0b6", "*"); -const ON_CONTENT = HAS_DOCUMENT_ELEMENT_INSERTED ? 'document-element-inserted' : - 'content-document-global-created'; - -// Workaround bug 642145: document-element-inserted is fired multiple times. -// This bug is fixed in Firefox 4.0.1, but we want to keep FF 4.0 compatibility -// Tracking bug 641457. To be removed when 4.0 has disappeared from earth. -const HAS_BUG_642145_FIXED = - xulApp.versionInRange(xulApp.platformVersion, "2.0.1", "*"); - -// rules registry -const RULES = {}; - -const Rules = EventEmitter.resolve({ toString: null }).compose(List, { - add: function() Array.slice(arguments).forEach(function onAdd(rule) { - if (this._has(rule)) - return; - // registering rule to the rules registry - if (!(rule in RULES)) - RULES[rule] = new MatchPattern(rule); - this._add(rule); - this._emit('add', rule); - }.bind(this)), - remove: function() Array.slice(arguments).forEach(function onRemove(rule) { - if (!this._has(rule)) - return; - this._remove(rule); - this._emit('remove', rule); - }.bind(this)), -}); - -/** - * PageMod constructor (exported below). - * @constructor - */ -const PageMod = Loader.compose(EventEmitter, { - on: EventEmitter.required, - _listeners: EventEmitter.required, - contentScript: Loader.required, - contentScriptFile: Loader.required, - contentScriptWhen: Loader.required, - include: null, - constructor: function PageMod(options) { - this._onContent = this._onContent.bind(this); - options = options || {}; - - if ('contentScript' in options) - this.contentScript = options.contentScript; - if ('contentScriptFile' in options) - this.contentScriptFile = options.contentScriptFile; - if ('contentScriptWhen' in options) - this.contentScriptWhen = options.contentScriptWhen; - if ('onAttach' in options) - this.on('attach', options.onAttach); - if ('onError' in options) - this.on('error', options.onError); - - let include = options.include; - let rules = this.include = Rules(); - rules.on('add', this._onRuleAdd = this._onRuleAdd.bind(this)); - rules.on('remove', this._onRuleRemove = this._onRuleRemove.bind(this)); - - if (Array.isArray(include)) - rules.add.apply(null, include); - else - rules.add(include); - - this.on('error', this._onUncaughtError = this._onUncaughtError.bind(this)); - pageModManager.add(this._public); - - this._loadingWindows = []; - }, - - destroy: function destroy() { - for each (let rule in this.include) - this.include.remove(rule); - pageModManager.remove(this._public); - this._loadingWindows = []; - }, - - _loadingWindows: [], - - _onContent: function _onContent(window) { - // not registered yet - if (!pageModManager.has(this)) - return; - - if (!HAS_BUG_642145_FIXED) { - if (this._loadingWindows.indexOf(window) != -1) - return; - this._loadingWindows.push(window); - } - - if ('start' == this.contentScriptWhen) { - this._createWorker(window); - return; - } - - let eventName = 'end' == this.contentScriptWhen ? 'load' : 'DOMContentLoaded'; - let self = this; - window.addEventListener(eventName, function onReady(event) { - if (event.target.defaultView != window) - return; - window.removeEventListener(eventName, onReady, true); - - self._createWorker(window); - }, true); - }, - _createWorker: function _createWorker(window) { - let worker = Worker({ - window: window, - contentScript: this.contentScript, - contentScriptFile: this.contentScriptFile, - onError: this._onUncaughtError - }); - this._emit('attach', worker); - let self = this; - worker.once('detach', function detach() { - worker.destroy(); - - if (!HAS_BUG_642145_FIXED) { - let idx = self._loadingWindows.indexOf(window); - if (idx != -1) - self._loadingWindows.splice(idx, 1); - } - }); - }, - _onRuleAdd: function _onRuleAdd(url) { - pageModManager.on(url, this._onContent); - }, - _onRuleRemove: function _onRuleRemove(url) { - pageModManager.off(url, this._onContent); - }, - _onUncaughtError: function _onUncaughtError(e) { - if (this._listeners('error').length == 1) - console.exception(e); - } -}); -exports.PageMod = function(options) PageMod(options) -exports.PageMod.prototype = PageMod.prototype; - -const PageModManager = Registry.resolve({ - constructor: '_init', - _destructor: '_registryDestructor' -}).compose({ - constructor: function PageModRegistry(constructor) { - this._init(PageMod); - observers.add( - ON_CONTENT, this._onContentWindow = this._onContentWindow.bind(this) - ); - }, - _destructor: function _destructor() { - observers.remove(ON_CONTENT, this._onContentWindow); - for (let rule in RULES) { - this._removeAllListeners(rule); - delete RULES[rule]; - } - this._registryDestructor(); - }, - _onContentWindow: function _onContentWindow(domObj) { - let window = HAS_DOCUMENT_ELEMENT_INSERTED ? domObj.defaultView : domObj; - // XML documents don't have windows, and we don't yet support them. - if (!window) - return; - for (let rule in RULES) - if (RULES[rule].test(window.document.URL)) - this._emit(rule, window); - }, - off: function off(topic, listener) { - this.removeListener(topic, listener); - if (!this._listeners(topic).length) - delete RULES[topic]; - } -}); -const pageModManager = PageModManager(); diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/page-worker.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/page-worker.js deleted file mode 100644 index 93750a1..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/page-worker.js +++ /dev/null @@ -1,101 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Felipe Gomes <felipc@gmail.com> (Original Author) - * Myk Melez <myk@mozilla.org> - * Irakli Gozalishvili <gozala@mozilla.com> - * Drew Willcoxon <adw@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -"use strict"; - -const { Symbiont } = require("api-utils/content"); -const { Trait } = require("api-utils/traits"); - -if (!require("api-utils/xul-app").isOneOf(["Firefox", "Thunderbird"])) { - throw new Error([ - "The page-worker module currently supports only Firefox and Thunderbird. ", - "In the future, we would like it to support other applications, however. ", - "Please see https://bugzilla.mozilla.org/show_bug.cgi?id=546740 for more ", - "information." - ].join("")); -} - -const Page = Trait.compose( - Symbiont.resolve({ - constructor: '_initSymbiont' - }), - { - _frame: Trait.required, - _initFrame: Trait.required, - postMessage: Symbiont.required, - on: Symbiont.required, - destroy: Symbiont.required, - - constructor: function Page(options) { - options = options || {}; - - this.contentURL = 'contentURL' in options ? options.contentURL - : 'about:blank'; - if ('contentScriptWhen' in options) - this.contentScriptWhen = options.contentScriptWhen; - if ('contentScriptFile' in options) - this.contentScriptFile = options.contentScriptFile; - if ('contentScript' in options) - this.contentScript = options.contentScript; - if ('allow' in options) - this.allow = options.allow; - if ('onError' in options) - this.on('error', options.onError); - if ('onMessage' in options) - this.on('message', options.onMessage); - - this.on('propertyChange', this._onChange.bind(this)); - - this._initSymbiont(); - }, - - _onChange: function _onChange(e) { - if ('contentURL' in e && this._frame) { - // Cleanup the worker before injecting the content script in the new - // document - this._workerCleanup(); - this._initFrame(this._frame); - } - } - } -); -exports.Page = function(options) Page(options); -exports.Page.prototype = Page.prototype; diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/panel.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/panel.js deleted file mode 100644 index 442f6a9..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/panel.js +++ /dev/null @@ -1,403 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Myk Melez <myk@mozilla.org> (Original Author) - * Irakli Gozalishvili <gozala@mazilla.com> - * Mihai Sucan <mihai.sucan@gmail.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -"use strict"; - -if (!require("api-utils/xul-app").is("Firefox")) { - throw new Error([ - "The panel module currently supports only Firefox. In the future ", - "we would like it to support other applications, however. Please see ", - "https://bugzilla.mozilla.org/show_bug.cgi?id=jetpack-panel-apps ", - "for more information." - ].join("")); -} - -const { Cc, Ci } = require("chrome"); - -const { validateOptions: valid } = require("api-utils/api-utils"); -const { Symbiont } = require("api-utils/content"); -const { EventEmitter } = require('api-utils/events'); -const timer = require("api-utils/timer"); -const runtime = require("api-utils/runtime"); - -const windowMediator = Cc['@mozilla.org/appshell/window-mediator;1']. - getService(Ci.nsIWindowMediator); - -const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", - ON_SHOW = 'popupshown', - ON_HIDE = 'popuphidden', - validNumber = { is: ['number', 'undefined', 'null'] }; - -/** - * Emits show and hide events. - */ -const Panel = Symbiont.resolve({ - constructor: '_init', - _onInit: '_onSymbiontInit', - destroy: '_symbiontDestructor', - _documentUnload: '_workerDocumentUnload' -}).compose({ - _frame: Symbiont.required, - _init: Symbiont.required, - _onSymbiontInit: Symbiont.required, - _symbiontDestructor: Symbiont.required, - _emit: Symbiont.required, - _asyncEmit: Symbiont.required, - on: Symbiont.required, - removeListener: Symbiont.required, - - _inited: false, - - /** - * If set to `true` frame loaders between xul panel frame and - * hidden frame are swapped. If set to `false` frame loaders are - * set back to normal. Setting the value that was already set will - * have no effect. - */ - set _frameLoadersSwapped(value) { - if (this.__frameLoadersSwapped == value) return; - this._frame.QueryInterface(Ci.nsIFrameLoaderOwner) - .swapFrameLoaders(this._viewFrame); - this.__frameLoadersSwapped = value; - }, - __frameLoadersSwapped: false, - - constructor: function Panel(options) { - this._onShow = this._onShow.bind(this); - this._onHide = this._onHide.bind(this); - this.on('inited', this._onSymbiontInit.bind(this)); - - options = options || {}; - if ('onShow' in options) - this.on('show', options.onShow); - if ('onHide' in options) - this.on('hide', options.onHide); - if ('width' in options) - this.width = options.width; - if ('height' in options) - this.height = options.height; - if ('contentURL' in options) - this.contentURL = options.contentURL; - - this._init(options); - }, - _destructor: function _destructor() { - this.hide(); - this._removeAllListeners('show'); - // defer cleanup to be performed after panel gets hidden - this._xulPanel = null; - this._symbiontDestructor(this); - this._removeAllListeners(this, 'hide'); - }, - destroy: function destroy() { - this._destructor(); - }, - /* Public API: Panel.width */ - get width() this._width, - set width(value) - this._width = valid({ $: value }, { $: validNumber }).$ || this._width, - _width: 320, - /* Public API: Panel.height */ - get height() this._height, - set height(value) - this._height = valid({ $: value }, { $: validNumber }).$ || this._height, - _height: 240, - - /* Public API: Panel.isShowing */ - get isShowing() !!this._xulPanel && this._xulPanel.state == "open", - - /* Public API: Panel.show */ - show: function show(anchor) { - anchor = anchor || null; - let document = getWindow(anchor).document; - let xulPanel = this._xulPanel; - if (!xulPanel) { - xulPanel = this._xulPanel = document.createElementNS(XUL_NS, 'panel'); - xulPanel.setAttribute("type", "arrow"); - - // One anonymous node has a big padding that doesn't work well with - // Jetpack, as we would like to display an iframe that completely fills - // the panel. - // -> Use a XBL wrapper with inner stylesheet to remove this padding. - let css = ".panel-inner-arrowcontent, .panel-arrowcontent {padding: 0;}"; - let originalXBL = "chrome://global/content/bindings/popup.xml#arrowpanel"; - let binding = - '<bindings xmlns="http://www.mozilla.org/xbl">' + - '<binding id="id" extends="' + originalXBL + '">' + - '<resources>' + - '<stylesheet src="data:text/css,' + - document.defaultView.encodeURIComponent(css) + '"/>' + - '</resources>' + - '</binding>' + - '</bindings>'; - xulPanel.style.MozBinding = 'url("data:text/xml,' + - document.defaultView.encodeURIComponent(binding) + '")'; - - let frame = document.createElementNS(XUL_NS, 'iframe'); - frame.setAttribute('type', 'content'); - frame.setAttribute('flex', '1'); - frame.setAttribute('transparent', 'transparent'); - if (runtime.OS === "Darwin") { - frame.style.borderRadius = "6px"; - frame.style.padding = "1px"; - } - - // Load an empty document in order to have an immediatly loaded iframe, - // so swapFrameLoaders is going to work without having to wait for load. - frame.setAttribute("src","data:,"); - - xulPanel.appendChild(frame); - document.getElementById("mainPopupSet").appendChild(xulPanel); - } - let { width, height } = this, x, y, position; - - if (!anchor) { - // Open the popup in the middle of the window. - x = document.documentElement.clientWidth / 2 - width / 2; - y = document.documentElement.clientHeight / 2 - height / 2; - position = null; - } - else { - // Open the popup by the anchor. - let rect = anchor.getBoundingClientRect(); - - let window = anchor.ownerDocument.defaultView; - - let zoom = window.mozScreenPixelsPerCSSPixel; - let screenX = rect.left + window.mozInnerScreenX * zoom; - let screenY = rect.top + window.mozInnerScreenY * zoom; - - // Set up the vertical position of the popup relative to the anchor - // (always display the arrow on anchor center) - let horizontal, vertical; - if (screenY > window.screen.availHeight / 2 + height) - vertical = "top"; - else - vertical = "bottom"; - - if (screenY > window.screen.availWidth / 2 + width) - horizontal = "left"; - else - horizontal = "right"; - - let verticalInverse = vertical == "top" ? "bottom" : "top"; - position = vertical + "center " + verticalInverse + horizontal; - - // Allow panel to flip itself if the panel can't be displayed at the - // specified position (useful if we compute a bad position or if the - // user moves the window and panel remains visible) - xulPanel.setAttribute("flip","both"); - } - - // Resize the iframe instead of using panel.sizeTo - // because sizeTo doesn't work with arrow panels - xulPanel.firstChild.style.width = width + "px"; - xulPanel.firstChild.style.height = height + "px"; - - // Wait for the XBL binding to be constructed - function waitForBinding() { - if (!xulPanel.openPopup) { - timer.setTimeout(waitForBinding, 50); - return; - } - xulPanel.openPopup(anchor, position, x, y); - } - waitForBinding(); - - return this._public; - }, - /* Public API: Panel.hide */ - hide: function hide() { - // The popuphiding handler takes care of swapping back the frame loaders - // and removing the XUL panel from the application window, we just have to - // trigger it by hiding the popup. - // XXX Sometimes I get "TypeError: xulPanel.hidePopup is not a function" - // when quitting the host application while a panel is visible. To suppress - // them, this now checks for "hidePopup" in xulPanel before calling it. - // It's not clear if there's an actual issue or the error is just normal. - let xulPanel = this._xulPanel; - if (xulPanel && "hidePopup" in xulPanel) - xulPanel.hidePopup(); - return this._public; - }, - - /* Public API: Panel.resize */ - resize: function resize(width, height) { - this.width = width; - this.height = height; - // Resize the iframe instead of using panel.sizeTo - // because sizeTo doesn't work with arrow panels - let xulPanel = this._xulPanel; - if (xulPanel) { - xulPanel.firstChild.style.width = width + "px"; - xulPanel.firstChild.style.height = height + "px"; - } - }, - - // While the panel is visible, this is the XUL <panel> we use to display it. - // Otherwise, it's null. - get _xulPanel() this.__xulPanel, - set _xulPanel(value) { - let xulPanel = this.__xulPanel; - if (value === xulPanel) return; - if (xulPanel) { - xulPanel.removeEventListener(ON_HIDE, this._onHide, false); - xulPanel.removeEventListener(ON_SHOW, this._onShow, false); - xulPanel.parentNode.removeChild(xulPanel); - } - if (value) { - value.addEventListener(ON_HIDE, this._onHide, false); - value.addEventListener(ON_SHOW, this._onShow, false); - } - this.__xulPanel = value; - }, - __xulPanel: null, - get _viewFrame() this.__xulPanel.children[0], - /** - * When the XUL panel becomes hidden, we swap frame loaders back to move - * the content of the panel to the hidden frame & remove panel element. - */ - _onHide: function _onHide() { - try { - this._frameLoadersSwapped = false; - this._xulPanel = null; - this._emit('hide'); - } catch(e) { - this._emit('error', e); - } - }, - /** - * When the XUL panel becomes shown, we swap frame loaders between panel - * frame and hidden frame to preserve state of the content dom. - */ - _onShow: function _onShow() { - try { - if (!this._inited) { // defer if not initialized yet - this.on('inited', this._onShow.bind(this)); - } else { - this._frameLoadersSwapped = true; - - // Retrieve computed text color style in order to apply to the iframe - // document. As MacOS background is dark gray, we need to use skin's - // text color. - let win = this._xulPanel.ownerDocument.defaultView; - let node = win.document.getAnonymousElementByAttribute(this._xulPanel, - "class", "panel-inner-arrowcontent"); - let textColor = win.getComputedStyle(node).getPropertyValue("color"); - let doc = this._xulPanel.firstChild.contentDocument; - let style = doc.createElement("style"); - style.textContent = "body { color: " + textColor + "; }"; - let container = doc.head ? doc.head : doc.documentElement; - - if (container.firstChild) - container.insertBefore(style, container.firstChild); - else - container.appendChild(style); - - this._emit('show'); - } - } catch(e) { - this._emit('error', e); - } - }, - /** - * Notification that panel was fully initialized. - */ - _onInit: function _onInit() { - this._inited = true; - - // Avoid panel document from resizing the browser window - // New platform capability added through bug 635673 - if ("allowWindowControl" in this._frame.docShell) - this._frame.docShell.allowWindowControl = false; - - // perform all deferred tasks like initSymbiont, show, hide ... - // TODO: We're publicly exposing a private event here; this - // 'inited' event should really be made private, somehow. - this._emit('inited'); - }, - - // Catch document unload event in order to rebind load event listener with - // Symbiont._initFrame if Worker._documentUnload destroyed the worker - _documentUnload: function(subject, topic, data) { - if (this._workerDocumentUnload(subject, topic, data)) { - this._initFrame(this._frame); - return true; - } - return false; - } -}); -exports.Panel = function(options) Panel(options) -exports.Panel.prototype = Panel.prototype; - -function getWindow(anchor) { - let window; - - if (anchor) { - let anchorWindow = anchor.ownerDocument.defaultView.top; - let anchorDocument = anchorWindow.document; - - let enumerator = windowMediator.getEnumerator("navigator:browser"); - while (enumerator.hasMoreElements()) { - let enumWindow = enumerator.getNext(); - - // Check if the anchor is in this browser window. - if (enumWindow == anchorWindow) { - window = anchorWindow; - break; - } - - // Check if the anchor is in a browser tab in this browser window. - let browser = enumWindow.gBrowser.getBrowserForDocument(anchorDocument); - if (browser) { - window = enumWindow; - break; - } - - // Look in other subdocuments (sidebar, etc.)? - } - } - - // If we didn't find the anchor's window (or we have no anchor), - // return the most recent browser window. - if (!window) - window = windowMediator.getMostRecentWindow("navigator:browser"); - - return window; -} - diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/passwords.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/passwords.js deleted file mode 100644 index 8225da9..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/passwords.js +++ /dev/null @@ -1,92 +0,0 @@ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Irakli Gozalishvili <gozala@mozilla.com> (Original Author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -"use strict"; -const { Trait } = require("api-utils/light-traits"); -const utils = require("api-utils/passwords/utils"); -const defer = require("api-utils/utils/function").Enqueued; - -/** - * Utility function that returns `onComplete` and `onError` callbacks form the - * given `options` objects. Also properties are removed from the passed - * `options` objects. - * @param {Object} options - * Object that is passed to the exported functions of this module. - * @returns {Function[]} - * Array with two elements `onComplete` and `onError` functions. - */ -function getCallbacks(options) { - let value = [ - 'onComplete' in options ? options.onComplete : null, - 'onError' in options ? defer(options.onError) : console.exception - ]; - - delete options.onComplete; - delete options.onError; - - return value; -}; - -/** - * Creates a wrapper function that tries to call `onComplete` with a return - * value of the wrapped function or falls back to `onError` if wrapped function - * throws an exception. - */ -function createWrapperMethod(wrapped) { - return function (options) { - let [ onComplete, onError ] = getCallbacks(options); - try { - let value = wrapped(options); - if (onComplete) { - defer(function() { - try { - onComplete(value); - } catch (exception) { - onError(exception); - } - })(); - } - } catch (exception) { - onError(exception); - } - }; -} - -exports.search = createWrapperMethod(utils.search); -exports.store = createWrapperMethod(utils.store); -exports.remove = createWrapperMethod(utils.remove); diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/private-browsing.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/private-browsing.js deleted file mode 100644 index 8336e7b..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/private-browsing.js +++ /dev/null @@ -1,102 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Paul O’Shannessy <paul@oshannessy.com> - * Irakli Gozalishvili <gozala@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -"use strict"; - -const {Cc,Ci} = require("chrome"); -const observers = require("api-utils/observer-service"); -const { EventEmitter } = require("api-utils/events"); -const { setTimeout } = require("api-utils/timer"); -const unload = require("api-utils/unload"); - -const ON_START = "start"; -const ON_STOP = "stop"; -const ON_TRANSITION = "private-browsing-transition-complete"; - -let pbService; -// Currently, only Firefox implements the private browsing service. -if (require("api-utils/xul-app").is("Firefox")) { - pbService = Cc["@mozilla.org/privatebrowsing;1"]. - getService(Ci.nsIPrivateBrowsingService); -} - -function toggleMode(value) pbService.privateBrowsingEnabled = !!value - -const privateBrowsing = EventEmitter.compose({ - constructor: function PrivateBrowsing() { - // Binding method to instance since it will be used with `setTimeout`. - this._emitOnObject = this._emitOnObject.bind(this); - this.unload = this.unload.bind(this); - // Report unhandled errors from listeners - this.on("error", console.exception.bind(console)); - unload.ensure(this); - // We only need to add observers if `pbService` exists. - if (pbService) { - observers.add(ON_TRANSITION, this.onTransition.bind(this)); - this._isActive = pbService.privateBrowsingEnabled; - } - }, - unload: function _destructor() { - this._removeAllListeners(ON_START); - this._removeAllListeners(ON_STOP); - }, - // We don't need to do anything with cancel here. - onTransition: function onTransition() { - let isActive = this._isActive = pbService.privateBrowsingEnabled; - setTimeout(this._emitOnObject, 0, exports, isActive ? ON_START : ON_STOP); - }, - get isActive() this._isActive, - set isActive(value) { - if (pbService) - // We toggle private browsing mode asynchronously in order to work around - // bug 659629. Since private browsing transitions are asynchronous - // anyway, this doesn't significantly change the behavior of the API. - setTimeout(toggleMode, 0, value); - }, - _isActive: false -})() - -Object.defineProperty(exports, "isActive", { - get: function() privateBrowsing.isActive -}); -exports.activate = function activate() privateBrowsing.isActive = true; -exports.deactivate = function deactivate() privateBrowsing.isActive = false; -exports.on = privateBrowsing.on; -exports.once = privateBrowsing.once; -exports.removeListener = privateBrowsing.removeListener; - diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/request.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/request.js deleted file mode 100644 index a72b28c..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/request.js +++ /dev/null @@ -1,309 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Paul O’Shannessy <paul@oshannessy.com> (Original Author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -"use strict"; -const xpcom = require("api-utils/xpcom"); -const xhr = require("api-utils/xhr"); -const errors = require("api-utils/errors"); -const apiUtils = require("api-utils/api-utils"); - -// Ugly but will fix with: https://bugzilla.mozilla.org/show_bug.cgi?id=596248 -const EventEmitter = require('api-utils/events').EventEmitter.compose({ - constructor: function EventEmitter() this -}); - -// Instead of creating a new validator for each request, just make one and reuse it. -const validator = new OptionsValidator({ - url: { - //XXXzpao should probably verify that url is a valid url as well - is: ["string"] - }, - headers: { - map: function (v) v || {}, - is: ["object"], - }, - content: { - map: function (v) v || null, - is: ["string", "object", "null"], - }, - contentType: { - map: function (v) v || "application/x-www-form-urlencoded", - is: ["string"], - }, - overrideMimeType: { - map: function(v) v || null, - is: ["string", "null"], - } -}); - -const REUSE_ERROR = "This request object has been used already. You must " + - "create a new one to make a new request." - -function Request(options) { - const self = EventEmitter(), - _public = self._public; - // request will hold the actual XHR object - let request; - let response; - - if ('onComplete' in options) - self.on('complete', options.onComplete) - options = validator.validateOptions(options); - - // function to prep the request since it's the same between GET and POST - function makeRequest(mode) { - // If this request has already been used, then we can't reuse it. Throw an error. - if (request) { - throw new Error(REUSE_ERROR); - } - - request = new xhr.XMLHttpRequest(); - - let url = options.url; - // Build the data to be set. For GET requests, we want to append that to - // the URL before opening the request. - let data = makeQueryString(options.content); - if (mode == "GET" && data) { - // If the URL already has ? in it, then we want to just use & - url = url + (/\?/.test(url) ? "&" : "?") + data; - } - - // open the request - request.open(mode, url); - - // request header must be set after open, but before send - request.setRequestHeader("Content-Type", options.contentType); - - // set other headers - for (let k in options.headers) { - request.setRequestHeader(k, options.headers[k]); - } - - // set overrideMimeType - if (options.overrideMimeType) { - request.overrideMimeType(options.overrideMimeType); - } - - // handle the readystate, create the response, and call the callback - request.onreadystatechange = function () { - if (request.readyState == 4) { - response = new Response(request); - errors.catchAndLog(function () { - self._emit('complete', response); - })(); - } - } - - // actually send the request. we only want to send data on POST requests - request.send(mode == "POST" ? data : null); - } - - // Map these setters/getters to the options - ["url", "headers", "content", "contentType"].forEach(function (k) { - _public.__defineGetter__(k, function () options[k]); - _public.__defineSetter__(k, function (v) { - // This will automatically rethrow errors from apiUtils.validateOptions. - return options[k] = validator.validateSingleOption(k, v); - }); - }); - - // response should be available as a getter - _public.__defineGetter__("response", function () response); - - _public.get = function () { - makeRequest("GET"); - return this; - }; - - _public.post = function () { - makeRequest("POST"); - return this; - }; - - return _public; -} -exports.Request = Request; - -// Converts an object of unordered key-vals to a string that can be passed -// as part of a request -function makeQueryString(content) { - // Explicitly return null if we have null, and empty string, or empty object. - if (!content) { - return null; - } - - // If content is already a string, just return it as is. - if (typeof(content) == "string") { - return content; - } - - // At this point we have a k:v object. Iterate over it and encode each value. - // Arrays and nested objects will get encoded as needed. For example... - // - // { foo: [1, 2, { omg: "bbq", "all your base!": "are belong to us" }], bar: "baz" } - // - // will be encoded as - // - // foo[0]=1&foo[1]=2&foo[2][omg]=bbq&foo[2][all+your+base!]=are+belong+to+us&bar=baz - // - // Keys (including "[" and "]") and values will be encoded with - // fixedEncodeURIComponent before returning. - // - // Execution was inspired by jQuery, but some details have changed and numeric - // array keys are included (whereas they are not in jQuery). - - let encodedContent = []; - function add(key, val) { - encodedContent.push(fixedEncodeURIComponent(key) + "=" + - fixedEncodeURIComponent(val)); - } - - function make(key, val) { - if (typeof(val) === "object" && val !== null) { - for ([k, v] in Iterator(val)) { - make(key + "[" + k + "]", v); - } - } - else { - add(key, val) - } - } - for ([k, v] in Iterator(content)) { - make(k, v); - } - return encodedContent.join("&"); - - //XXXzpao In theory, we can just use a FormData object on 1.9.3, but I had - // trouble getting that working. It would also be nice to stay - // backwards-compat as long as possible. Keeping this in for now... - // let formData = Cc["@mozilla.org/files/formdata;1"]. - // createInstance(Ci.nsIDOMFormData); - // for ([k, v] in Iterator(content)) { - // formData.append(k, v); - // } - // return formData; -} - - -// encodes a string safely for application/x-www-form-urlencoded -// adheres to RFC 3986 -// see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Functions/encodeURIComponent -function fixedEncodeURIComponent (str) { - return encodeURIComponent(str).replace(/%20/g, "+").replace(/!/g, "%21"). - replace(/'/g, "%27").replace(/\(/g, "%28"). - replace(/\)/g, "%29").replace(/\*/g, "%2A"); -} - -function Response(request) { - // Define the straight mappings of our value to original request value - xpcom.utils.defineLazyGetter(this, "text", function () request.responseText); - xpcom.utils.defineLazyGetter(this, "xml", function () { - throw new Error("Sorry, the 'xml' property is no longer available. " + - "see bug 611042 for more information."); - }); - xpcom.utils.defineLazyGetter(this, "status", function () request.status); - xpcom.utils.defineLazyGetter(this, "statusText", function () request.statusText); - - // this.json should be the JS object, so we need to attempt to parse it. - xpcom.utils.defineLazyGetter(this, "json", function () { - let _json = null; - try { - _json = JSON.parse(this.text); - } - catch (e) {} - return _json; - }); - - // this.headers also should be a JS object, so we need to split up the raw - // headers string provided by the request. - xpcom.utils.defineLazyGetter(this, "headers", function () { - let _headers = {}; - let lastKey; - // Since getAllResponseHeaders() will return null if there are no headers, - // defend against it by defaulting to "" - let rawHeaders = request.getAllResponseHeaders() || ""; - rawHeaders.split("\n").forEach(function (h) { - // According to the HTTP spec, the header string is terminated by an empty - // line, so we can just skip it. - if (!h.length) { - return; - } - - let index = h.indexOf(":"); - // The spec allows for leading spaces, so instead of assuming a single - // leading space, just trim the values. - let key = h.substring(0, index).trim(), - val = h.substring(index + 1).trim(); - - // For empty keys, that means that the header value spanned multiple lines. - // In that case we should append the value to the value of lastKey with a - // new line. We'll assume lastKey will be set because there should never - // be an empty key on the first pass. - if (key) { - _headers[key] = val; - lastKey = key; - } - else { - _headers[lastKey] += "\n" + val; - } - }); - return _headers; - }) -} - -// apiUtils.validateOptions doesn't give the ability to easily validate single -// options, so this is a wrapper that provides that ability. -function OptionsValidator(rules) { - this.rules = rules; - - this.validateOptions = function (options) { - return apiUtils.validateOptions(options, this.rules); - } - - this.validateSingleOption = function (field, value) { - // We need to create a single rule object from our listed rules. To avoid - // JavaScript String warnings, check for the field & default to an empty object. - let singleRule = {}; - if (field in this.rules) { - singleRule[field] = this.rules[field]; - } - let singleOption = {}; - singleOption[field] = value; - // This should throw if it's invalid, which will bubble up & out. - return apiUtils.validateOptions(singleOption, singleRule)[field]; - } -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/selection.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/selection.js deleted file mode 100644 index 48db7fc..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/selection.js +++ /dev/null @@ -1,448 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Eric H. Jung <eric.jung@yahoo.com> - * Irakli Gozalishivili <gozala@mozilla.com> - * Matteo Ferretti <zer0@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -"use strict"; - -if (!require("api-utils/xul-app").is("Firefox")) { - throw new Error([ - "The selection module currently supports only Firefox. In the future ", - "we would like it to support other applications, however. Please see ", - "https://bugzilla.mozilla.org/show_bug.cgi?id=560716 for more information." - ].join("")); -} - -let { Ci } = require("chrome"), - { setTimeout } = require("api-utils/timer"), - { EventEmitter } = require("api-utils/events"); - -// The selection type HTML -const HTML = 0x01; - -// The selection type TEXT -const TEXT = 0x02; - -// The selection type DOM (internal use only) -const DOM = 0x03; - -// A more developer-friendly message than the caught exception when is not -// possible change a selection. -const ERR_CANNOT_CHANGE_SELECTION = - "It isn't possible to change the selection, as there isn't currently a selection"; - -/** - * Creates an object from which a selection can be set, get, etc. Each - * object has an associated with a range number. Range numbers are the - * 0-indexed counter of selection ranges as explained at - * https://developer.mozilla.org/en/DOM/Selection. - * - * @param rangeNumber - * The zero-based range index into the selection - */ -function Selection(rangeNumber) { - - // In order to hide the private rangeNumber argument from API consumers while - // still enabling Selection getters/setters to access it, the getters/setters - // are defined as lexical closures in the Selector constructor. - - this.__defineGetter__("text", function () getSelection(TEXT, rangeNumber)); - this.__defineSetter__("text", function (str) setSelection(str, rangeNumber)); - - this.__defineGetter__("html", function () getSelection(HTML, rangeNumber)); - this.__defineSetter__("html", function (str) setSelection(str, rangeNumber)); - - this.__defineGetter__("isContiguous", function () { - let sel = getSelection(DOM); - - // If there are multiple ranges, the selection is definitely discontiguous. - // It returns `false` also if there are no selection; and `true` if there is - // a single non empty range, or a selection in a text field - contiguous or - // not (text field selection APIs doesn't support multiple selections). - - if (sel.rangeCount > 1) - return false; - - return !!(safeGetRange(sel, 0) || getElementWithSelection()); - }); -} - -require("api-utils/xpcom").utils.defineLazyServiceGetter(this, "windowMediator", - "@mozilla.org/appshell/window-mediator;1", "nsIWindowMediator"); - -/** - * Returns the most recent content window - */ -function context() { - // Overlay names should probably go into the xul-app module instead of here - return windowMediator.getMostRecentWindow("navigator:browser").document. - commandDispatcher.focusedWindow; -} - -/** - * Returns the current selection from most recent content window. Depending on - * the specified |type|, the value returned can be a string of text, stringified - * HTML, or a DOM selection object as described at - * https://developer.mozilla.org/en/DOM/Selection. - * - * @param type - * Specifies the return type of the selection. Valid values are the one - * of the constants HTML, TEXT, or DOM. - * - * @param rangeNumber - * Specifies the zero-based range index of the returned selection. - */ -function getSelection(type, rangeNumber) { - let window, selection; - try { - window = context(); - selection = window.getSelection(); - } - catch (e) { - return null; - } - - // Get the selected content as the specified type - if (type == DOM) - return selection; - else if (type == TEXT) { - let range = safeGetRange(selection, rangeNumber); - - if (range) - return range.toString(); - - let node = getElementWithSelection(window); - - if (!node) - return null; - - return node.value.substring(node.selectionStart, node.selectionEnd); - } - else if (type == HTML) { - let range = safeGetRange(selection, rangeNumber); - // Another way, but this includes the xmlns attribute for all elements in - // Gecko 1.9.2+ : - // return Cc["@mozilla.org/xmlextras/xmlserializer;1"]. - // createInstance(Ci.nsIDOMSerializer).serializeToSTring(range. - // cloneContents()); - if (!range) - return null; - let node = window.document.createElement("span"); - node.appendChild(range.cloneContents()); - return node.innerHTML; - } - throw new Error("Type " + type + " is unrecognized."); -} - -/** - * Returns the specified range in a selection without throwing an exception. - * - * @param selection - * A selection object as described at - * https://developer.mozilla.org/en/DOM/Selection - * - * @param rangeNumber - * Specifies the zero-based range index of the returned selection. - */ -function safeGetRange(selection, rangeNumber) { - try { - let range = selection.getRangeAt(rangeNumber); - if (!range || range.toString() == "") - return null; - return range; - } - catch (e) { - return null; - } -} - -/** - * Returns a reference of the DOM's active element for the window given, if it - * supports the text field selection API and has a text selected. - * - * Note: - * we need this method because window.getSelection doesn't return a selection - * for text selected in a form field (see bug 85686) - * - * @param {nsIWindow} [window] - * A reference to a window - */ -function getElementWithSelection(window) { - let element; - - try { - element = (window || context()).document.activeElement; - } - catch (e) { - element = null; - } - - if (!element) - return null; - - let { value, selectionStart, selectionEnd } = element; - - let hasSelection = typeof value === "string" && - !isNaN(selectionStart) && - !isNaN(selectionEnd) && - selectionStart !== selectionEnd; - - return hasSelection ? element : null; -} -/** - * Sets the current selection of the most recent content document by changing - * the existing selected text/HTML range to the specified value. - * - * @param val - * The value for the new selection - * - * @param rangeNumber - * The zero-based range index of the selection to be set - * - */ -function setSelection(val, rangeNumber) { - // Make sure we have a window context & that there is a current selection. - // Selection cannot be set unless there is an existing selection. - let window, selection; - - try { - window = context(); - selection = window.getSelection(); - } - catch (e) { - throw new Error(ERR_CANNOT_CHANGE_SELECTION); - } - - let range = safeGetRange(selection, rangeNumber); - - if (range) { - // Get rid of the current selection and insert our own - range.deleteContents(); - let node = window.document.createElement("span"); - range.surroundContents(node); - - // Some relevant JEP-111 requirements: - - // Setting the text property replaces the selection with the value to - // which the property is set and sets the html property to the same value - // to which the text property is being set. - - // Setting the html property replaces the selection with the value to - // which the property is set and sets the text property to the text version - // of the HTML value. - - // This sets both the HTML and text properties. - node.innerHTML = val; - } else { - let node = getElementWithSelection(window); - - if (!node) - throw new Error(ERR_CANNOT_CHANGE_SELECTION); - - let { value, selectionStart, selectionEnd } = node; - - let newSelectionEnd = selectionStart + val.length; - - node.value = value.substring(0, selectionStart) + - val + - value.substring(selectionEnd, value.length); - - node.setSelectionRange(selectionStart, newSelectionEnd); - } -} - -function onLoad(event) { - SelectionListenerManager.onLoad(event); -} - -function onUnload(event) { - SelectionListenerManager.onUnload(event); -} - -function onSelect() { - SelectionListenerManager.onSelect(); -} - -let SelectionListenerManager = { - QueryInterface: require("api-utils/xpcom").utils. - generateQI([Ci.nsISelectionListener]), - - // The collection of listeners wanting to be notified of selection changes - listeners: EventEmitter.compose({ - emit: function emit(type) this._emitOnObject(exports, type), - off: function() this._removeAllListeners.apply(this, arguments) - })(), - /** - * This is the nsISelectionListener implementation. This function is called - * by Gecko when a selection is changed interactively. - * - * We only pay attention to the SELECTALL, KEYPRESS, and MOUSEUP selection - * reasons. All reasons are listed here: - * - * http://mxr.mozilla.org/mozilla1.9.2/source/content/base/public/ - * nsISelectionListener.idl - * - * The other reasons (NO_REASON, DRAG_REASON, MOUSEDOWN_REASON) aren't - * applicable to us. - */ - notifySelectionChanged: function notifySelectionChanged(document, selection, - reason) { - if (!["SELECTALL", "KEYPRESS", "MOUSEUP"].some(function(type) reason & - Ci.nsISelectionListener[type + "_REASON"]) || selection.toString() == "") - return; - - this.onSelect(); - }, - - onSelect : function onSelect() { - setTimeout(this.listeners.emit, 0, "select"); - }, - - /** - * Part of the Tracker implementation. This function is called by the - * tabs module when a browser is being tracked. Often, that means a new tab - * has been opened, but it can also mean an addon has been installed while - * tabs are already opened. In that case, this function is called for those - * already-opened tabs. - * - * @param browser - * The browser being tracked - */ - onTrack: function onTrack(browser) { - browser.addEventListener("load", onLoad, true); - browser.addEventListener("unload", onUnload, true); - }, - - onLoad: function onLoad(event) { - // Nothing to do without a useful window - let window = event.target.defaultView; - if (!window) - return; - - // Wrap the add selection call with some number of setTimeout 0 because some - // reason it's possible to add a selection listener "too early". 2 sometimes - // works for gmail, and more consistently with 3, so make it 5 to be safe. - let count = 0; - let self = this; - function wrap(count, func) { - if (count-- > 0) - require("api-utils/timer").setTimeout(wrap, 0); - else - self.addSelectionListener(window); - } - wrap(); - }, - - addSelectionListener: function addSelectionListener(window) { - if (window.jetpack_core_selection_listener) - return; - let selection = window.getSelection(); - if (selection instanceof Ci.nsISelectionPrivate) - selection.addSelectionListener(this); - - // nsISelectionListener implementation seems not fire a notification if - // a selection is in a text field, therefore we need to add a listener to - // window.onselect, that is fired only for text fields. - // https://developer.mozilla.org/en/DOM/window.onselect - window.addEventListener("select", onSelect, true); - - window.jetpack_core_selection_listener = true; - }, - - onUnload: function onUnload(event) { - // Nothing to do without a useful window - let window = event.target.defaultView; - if (!window) - return; - this.removeSelectionListener(window); - this.listeners.off('error'); - this.listeners.off('selection'); - }, - - removeSelectionListener: function removeSelectionListener(window) { - if (!window.jetpack_core_selection_listener) - return; - let selection = window.getSelection(); - if (selection instanceof Ci.nsISelectionPrivate) - selection.removeSelectionListener(this); - - window.removeEventListener("select", onSelect); - - window.jetpack_core_selection_listener = false; - }, - - /** - * Part of the TabTracker implementation. This function is called by the - * tabs module when a browser is being untracked. Usually, that means a tab - * has been closed. - * - * @param browser - * The browser being untracked - */ - onUntrack: function onUntrack(browser) { - browser.removeEventListener("load", onLoad, true); - browser.removeEventListener("unload", onUnload, true); - } -}; -SelectionListenerManager.listeners.on('error', console.error); - -/** - * Install |SelectionListenerManager| as tab tracker in order to watch - * tab opening/closing - */ -require("api-utils/tab-browser").Tracker(SelectionListenerManager); - -/** - * Exports an iterator so that discontiguous selections can be iterated. - * - * If discontiguous selections are in a text field, only the first one - * is returned because the text field selection APIs doesn't support - * multiple selections. - */ -exports.__iterator__ = function __iterator__() { - let sel = getSelection(DOM); - let rangeCount = sel.rangeCount || (getElementWithSelection() ? 1 : 0); - - for (let i = 0; i < rangeCount; i++) - yield new Selection(i); -}; - -exports.on = SelectionListenerManager.listeners.on; -exports.removeListener = SelectionListenerManager.listeners.removeListener; - -// Export the Selection singleton. Its rangeNumber is always zero. -Selection.call(exports, 0); - diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/simple-prefs.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/simple-prefs.js deleted file mode 100644 index c7a059b..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/simple-prefs.js +++ /dev/null @@ -1,107 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Hernan Rodriguez Colmeiro <colmeiro@gmail.com> (Original Author) - * Erik Vold <erikvvold@gmail.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -const { Cc, Ci } = require("chrome"); -const observers = require("observer-service"); -const { EventEmitter } = require("events"); -const unload = require("unload"); -const prefService = require("preferences-service"); -const { jetpackID } = require("@packaging"); - -const ADDON_BRANCH = "extensions." + jetpackID + "."; -const BUTTON_PRESSED = jetpackID + "-cmdPressed"; - -// XXX Currently, only Firefox implements the inline preferences. -if (!require("xul-app").is("Firefox")) - throw Error("This API is only supported in Firefox"); - -let branch = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefService). - getBranch(ADDON_BRANCH). - QueryInterface(Ci.nsIPrefBranch2); - -const events = EventEmitter.compose({ - constructor: function Prefs() { - // Log unhandled errors. - this.on("error", console.exception.bind(console)); - - // Make sure we remove all the listeners - unload.ensure(this); - - this._prefObserver = this._prefObserver.bind(this); - this._buttonObserver = this._buttonObserver.bind(this); - - // Listen to changes in the preferences - branch.addObserver("", this._prefObserver, false); - - // Listen to clicks on buttons - observers.add(BUTTON_PRESSED, this._buttonObserver, this); - }, - _prefObserver: function PrefsPrefObserver(subject, topic, prefName) { - if (topic == "nsPref:changed") { - this._emit(prefName, prefName); - } - }, - _buttonObserver: function PrefsButtonObserver(subject, data) { - this._emit(data); - }, - unload: function manager_unload() { - this._removeAllListeners("error"); - branch.removeObserver("", this._prefObserver); - }, -})(); - -const simple = Proxy.create({ - get: function(receiver, pref) { - return prefService.get(ADDON_BRANCH + pref); - }, - set: function(receiver, pref, val) { - prefService.set(ADDON_BRANCH + pref, val); - }, - delete: function(pref) { - prefService.reset(ADDON_BRANCH + pref); - return true; - }, - has: function(pref) { - return prefService.has(ADDON_BRANCH + pref); - } -}); - -exports.on = events.on; -exports.removeListener = events.removeListener; -exports.prefs = simple; diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/simple-storage.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/simple-storage.js deleted file mode 100644 index b719e27..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/simple-storage.js +++ /dev/null @@ -1,263 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim:set ts=2 sw=2 sts=2 et filetype=javascript - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Drew Willcoxon <adw@mozilla.com> (Original Author) - * Irakli Gozalishvili <gozala@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -"use strict"; - -const {Cc,Ci} = require("chrome"); -const file = require("api-utils/file"); -const prefs = require("api-utils/preferences-service"); -const jpSelf = require("self"); -const timer = require("api-utils/timer"); -const unload = require("api-utils/unload"); -const { EventEmitter } = require("api-utils/events"); -const { Trait } = require("api-utils/traits"); - -const WRITE_PERIOD_PREF = "extensions.addon-sdk.simple-storage.writePeriod"; -const WRITE_PERIOD_DEFAULT = 300000; // 5 minutes - -const QUOTA_PREF = "extensions.addon-sdk.simple-storage.quota"; -const QUOTA_DEFAULT = 5242880; // 5 MiB - -const JETPACK_DIR_BASENAME = "jetpack"; - - -// simpleStorage.storage -exports.__defineGetter__("storage", function () manager.root); -exports.__defineSetter__("storage", function (val) manager.root = val); - -// simpleStorage.quotaUsage -exports.__defineGetter__("quotaUsage", function () manager.quotaUsage); - -// A generic JSON store backed by a file on disk. This should be isolated -// enough to move to its own module if need be... -function JsonStore(options) { - this.filename = options.filename; - this.quota = options.quota; - this.writePeriod = options.writePeriod; - this.onOverQuota = options.onOverQuota; - this.onWrite = options.onWrite; - - unload.ensure(this); - - this.writeTimer = timer.setInterval(this.write.bind(this), - this.writePeriod); -} - -JsonStore.prototype = { - // The store's root. - get root() { - return this.isRootInited ? this._root : {}; - }, - - // Performs some type checking. - set root(val) { - let types = ["array", "boolean", "null", "number", "object", "string"]; - if (types.indexOf(typeof(val)) < 0) { - throw new Error("storage must be one of the following types: " + - types.join(", ")); - } - this._root = val; - return val; - }, - - // True if the root has ever been set (either via the root setter or by the - // backing file's having been read). - get isRootInited() { - return this._root !== undefined; - }, - - // Percentage of quota used, as a number [0, Inf). > 1 implies over quota. - // Undefined if there is no quota. - get quotaUsage() { - return this.quota > 0 ? - JSON.stringify(this.root).length / this.quota : - undefined; - }, - - // Removes the backing file and all empty subdirectories. - purge: function JsonStore_purge() { - try { - // This'll throw if the file doesn't exist. - file.remove(this.filename); - let parentPath = this.filename; - do { - parentPath = file.dirname(parentPath); - // This'll throw if the dir isn't empty. - file.rmdir(parentPath); - } while (file.basename(parentPath) !== JETPACK_DIR_BASENAME); - } - catch (err) {} - }, - - // Initializes the root by reading the backing file. - read: function JsonStore_read() { - try { - let str = file.read(this.filename); - - // Ideally we'd log the parse error with console.error(), but logged - // errors cause tests to fail. Supporting "known" errors in the test - // harness appears to be non-trivial. Maybe later. - this.root = JSON.parse(str); - } - catch (err) { - this.root = {}; - } - }, - - // If the store is under quota, writes the root to the backing file. - // Otherwise quota observers are notified and nothing is written. - write: function JsonStore_write() { - if (this.quotaUsage > 1) - this.onOverQuota(this); - else - this._write(); - }, - - // Cleans up on unload. If unloading because of uninstall, the store is - // purged; otherwise it's written. - unload: function JsonStore_unload(reason) { - timer.clearInterval(this.writeTimer); - this.writeTimer = null; - - if (reason === "uninstall") - this.purge(); - else - this._write(); - }, - - // True if the root is an empty object. - get _isEmpty() { - if (this.root && typeof(this.root) === "object") { - let empty = true; - for (let key in this.root) { - empty = false; - break; - } - return empty; - } - return false; - }, - - // Writes the root to the backing file, notifying write observers when - // complete. If the store is over quota or if it's empty and the store has - // never been written, nothing is written and write observers aren't notified. - _write: function JsonStore__write() { - // Don't write if the root is uninitialized or if the store is empty and the - // backing file doesn't yet exist. - if (!this.isRootInited || (this._isEmpty && !file.exists(this.filename))) - return; - - // If the store is over quota, don't write. The current under-quota state - // should persist. - if (this.quotaUsage > 1) - return; - - // Finally, write. - let stream = file.open(this.filename, "w"); - try { - stream.writeAsync(JSON.stringify(this.root), function writeAsync(err) { - if (err) - console.error("Error writing simple storage file: " + this.filename); - else if (this.onWrite) - this.onWrite(this); - }.bind(this)); - } - catch (err) { - // writeAsync closes the stream after it's done, so only close on error. - stream.close(); - } - } -}; - - -// This manages a JsonStore singleton and tailors its use to simple storage. -// The root of the JsonStore is lazy-loaded: The backing file is only read the -// first time the root's gotten. -let manager = Trait.compose(EventEmitter, Trait.compose({ - jsonStore: null, - - // The filename of the store, based on the profile dir and extension ID. - get filename() { - let storeFile = Cc["@mozilla.org/file/directory_service;1"]. - getService(Ci.nsIProperties). - get("ProfD", Ci.nsIFile); - storeFile.append(JETPACK_DIR_BASENAME); - storeFile.append(jpSelf.id); - storeFile.append("simple-storage"); - file.mkpath(storeFile.path); - storeFile.append("store.json"); - return storeFile.path; - }, - - get quotaUsage() { - return this.jsonStore.quotaUsage; - }, - - get root() { - if (!this.jsonStore.isRootInited) - this.jsonStore.read(); - return this.jsonStore.root; - }, - - set root(val) { - return this.jsonStore.root = val; - }, - - unload: function manager_unload() { - this._removeAllListeners("OverQuota"); - this._removeAllListeners("error"); - }, - - constructor: function manager_constructor() { - // Log unhandled errors. - this.on("error", console.exception.bind(console)); - unload.ensure(this); - - this.jsonStore = new JsonStore({ - filename: this.filename, - writePeriod: prefs.get(WRITE_PERIOD_PREF, WRITE_PERIOD_DEFAULT), - quota: prefs.get(QUOTA_PREF, QUOTA_DEFAULT), - onOverQuota: this._emitOnObject.bind(this, exports, "OverQuota") - }); - } -}))(); - -exports.on = manager.on; -exports.removeListener = manager.removeListener; diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/tabs.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/tabs.js deleted file mode 100644 index 81681d6..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/tabs.js +++ /dev/null @@ -1,62 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Dietrich Ayala <dietrich@mozilla.com> (Original author) - * Felipe Gomes <felipc@gmail.com> - * Irakli Gozalishvili <gozala@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -"use strict"; - -if (!require("api-utils/xul-app").is("Firefox")) { - throw new Error([ - "The tabs module currently supports only Firefox. In the future ", - "we would like it to support other applications, however. Please see ", - "https://bugzilla.mozilla.org/show_bug.cgi?id=560716 for more information." - ].join("")); -} - -const { browserWindows } = require("./windows"); -const { tabs } = require("api-utils/windows/tabs"); - -Object.defineProperties(tabs, { - open: { value: function open(options) { - if (options.inNewWindow) - // `tabs` option is under review and may be removed. - return browserWindows.open({ tabs: [ options ] }); - // Open in active window if new window was not required. - return browserWindows.activeWindow.tabs.open(options); - }} -}); -// It's a hack but we will be able to remove it once will implement CommonJS -// feature that would allow us to override exports. -exports.__proto__ = tabs; diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/timers.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/timers.js deleted file mode 100644 index 9373dea..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/timers.js +++ /dev/null @@ -1,40 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Irakli Gozalishvili <gozala@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -"use strict"; - -// This module just proxies to the low level equivalent "timer" in "api-utils". -module.exports = require("api-utils/timer"); diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/widget.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/widget.js deleted file mode 100644 index 9a169f4..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/widget.js +++ /dev/null @@ -1,947 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Dietrich Ayala <dietrich@mozilla.com> (Original Author) - * Drew Willcoxon <adw@mozilla.com> - * Irakli Gozalishvili <gozala@mozilla.com> - * Alexandre Poirot <apoirot@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -"use strict"; - -const {Cc, Ci} = require("chrome"); - -// Widget content types -const CONTENT_TYPE_URI = 1; -const CONTENT_TYPE_HTML = 2; -const CONTENT_TYPE_IMAGE = 3; - -const ERR_CONTENT = "No content or contentURL property found. Widgets must " - + "have one or the other.", - ERR_LABEL = "The widget must have a non-empty label property.", - ERR_ID = "You have to specify a unique value for the id property of " + - "your widget in order for the application to remember its " + - "position.", - ERR_DESTROYED = "The widget has been destroyed and can no longer be used."; - -// Supported events, mapping from DOM event names to our event names -const EVENTS = { - "click": "click", - "mouseover": "mouseover", - "mouseout": "mouseout", -}; - -if (!require("api-utils/xul-app").is("Firefox")) { - throw new Error([ - "The widget module currently supports only Firefox. In the future ", - "it will support other applications. Please see ", - "https://bugzilla.mozilla.org/show_bug.cgi?id=560716 for more information." - ].join("")); -} - -const { validateOptions } = require("api-utils/api-utils"); -const panels = require("./panel"); -const { EventEmitter, EventEmitterTrait } = require("api-utils/events"); -const { Trait } = require("api-utils/traits"); -const LightTrait = require('api-utils/light-traits').Trait; -const { Loader, Symbiont } = require("api-utils/content"); -const timer = require("api-utils/timer"); -const { Cortex } = require('api-utils/cortex'); -const windowsAPI = require("./windows"); -const unload = require("api-utils/unload"); - -// Data types definition -const valid = { - number: { is: ["null", "undefined", "number"] }, - string: { is: ["null", "undefined", "string"] }, - id: { - is: ["string"], - ok: function (v) v.length > 0, - msg: ERR_ID, - readonly: true - }, - label: { - is: ["string"], - ok: function (v) v.length > 0, - msg: ERR_LABEL - }, - panel: { - is: ["null", "undefined", "object"], - ok: function(v) !v || v instanceof panels.Panel - }, - width: { - is: ["null", "undefined", "number"], - map: function (v) { - if (null === v || undefined === v) v = 16; - return v; - }, - defaultValue: 16 - }, - allow: { - is: ["null", "undefined", "object"], - map: function (v) { - if (!v) v = { script: true }; - return v; - }, - get defaultValue() ({ script: true }) - }, -}; - -// Widgets attributes definition -let widgetAttributes = { - label: valid.label, - id: valid.id, - tooltip: valid.string, - width: valid.width, - content: valid.string, - panel: valid.panel, - allow: valid.allow -}; - -// Import data definitions from loader, but don't compose with it as Model -// functions allow us to recreate easily all Loader code. -let loaderAttributes = require("api-utils/content/loader").validationAttributes; -for (let i in loaderAttributes) - widgetAttributes[i] = loaderAttributes[i]; - -widgetAttributes.contentURL.optional = true; - -// Widgets public events list, that are automatically binded in options object -const WIDGET_EVENTS = [ - "click", - "mouseover", - "mouseout", - "error", - "message", - "attach" -]; - -// `Model` utility functions that help creating these various Widgets objects -let model = { - - // Validate one attribute using api-utils.js:validateOptions function - _validate: function _validate(name, suspect, validation) { - let $1 = {}; - $1[name] = suspect; - let $2 = {}; - $2[name] = validation; - return validateOptions($1, $2)[name]; - }, - - /** - * This method has two purposes: - * 1/ Validate and define, on a given object, a set of attribute - * 2/ Emit a "change" event on this object when an attribute is changed - * - * @params {Object} object - * Object on which we can bind attributes on and watch for their changes. - * This object must have an EventEmitter interface, or, at least `_emit` - * method - * @params {Object} attrs - * Dictionary of attributes definition following api-utils:validateOptions - * scheme - * @params {Object} values - * Dictionary of attributes default values - */ - setAttributes: function setAttributes(object, attrs, values) { - let properties = {}; - for (let name in attrs) { - let value = values[name]; - let req = attrs[name]; - - // Retrieve default value from typedef if the value is not defined - if ((typeof value == "undefined" || value == null) && req.defaultValue) - value = req.defaultValue; - - // Check for valid value if value is defined or mandatory - if (!req.optional || typeof value != "undefined") - value = model._validate(name, value, req); - - // In any case, define this property on `object` - let property = null; - if (req.readonly) { - property = { - value: value, - writable: false, - enumerable: true, - configurable: false - }; - } - else { - property = model._createWritableProperty(name, value); - } - - properties[name] = property; - } - Object.defineProperties(object, properties); - }, - - // Generate ES5 property definition for a given attribute - _createWritableProperty: function _createWritableProperty(name, value) { - return { - get: function () { - return value; - }, - set: function (newValue) { - value = newValue; - // The main goal of all this Model stuff is here: - // We want to forward all changes to some listeners - this._emit("change", name, value); - }, - enumerable: true, - configurable: false - }; - }, - - /** - * Automagically register listeners in options dictionary - * by detecting listener attributes with name starting with `on` - * - * @params {Object} object - * Target object that need to follow EventEmitter interface, or, at least, - * having `on` method. - * @params {Array} events - * List of events name to automatically bind. - * @params {Object} listeners - * Dictionary of event listener functions to register. - */ - setEvents: function setEvents(object, events, listeners) { - for (let i = 0, l = events.length; i < l; i++) { - let name = events[i]; - let onName = "on" + name[0].toUpperCase() + name.substr(1); - if (!listeners[onName]) - continue; - object.on(name, listeners[onName].bind(object)); - } - } - -}; - - -/** - * Main Widget class: entry point of the widget API - * - * Allow to control all widget across all existing windows with a single object. - * Widget.getView allow to retrieve a WidgetView instance to control a widget - * specific to one window. - */ -const WidgetTrait = LightTrait.compose(EventEmitterTrait, LightTrait({ - - _initWidget: function _initWidget(options) { - model.setAttributes(this, widgetAttributes, options); - - browserManager.validate(this); - - // We must have at least content or contentURL defined - if (!(this.content || this.contentURL)) - throw new Error(ERR_CONTENT); - - this._views = []; - - // Set tooltip to label value if we don't have tooltip defined - if (!this.tooltip) - this.tooltip = this.label; - - model.setEvents(this, WIDGET_EVENTS, options); - - this.on('change', this._onChange.bind(this)); - - let self = this; - this._port = EventEmitterTrait.create({ - emit: function () { - let args = arguments; - self._views.forEach(function(v) v.port.emit.apply(v.port, args)); - } - }); - // expose wrapped port, that exposes only public properties. - this._port._public = Cortex(this._port); - - // Register this widget to browser manager in order to create new widget on - // all new windows - browserManager.addItem(this); - }, - - _onChange: function _onChange(name, value) { - // Set tooltip to label value if we don't have tooltip defined - if (name == 'tooltip' && !value) { - // we need to change tooltip again in order to change the value of the - // attribute itself - this.tooltip = this.label; - return; - } - - // Forward attributes changes to WidgetViews - if (['width', 'tooltip', 'content', 'contentURL'].indexOf(name) != -1) { - this._views.forEach(function(v) v[name] = value); - } - }, - - _onEvent: function _onEvent(type, eventData) { - this._emit(type, eventData); - }, - - _createView: function _createView() { - // Create a new WidgetView instance - let view = WidgetView(this); - - // Keep a reference to it - this._views.push(view); - - // Emit an `attach` event with a WidgetView instance without private attrs - this._emit("attach", view._public); - - return view; - }, - - // a WidgetView instance is destroyed - _onViewDestroyed: function _onViewDestroyed(view) { - let idx = this._views.indexOf(view); - this._views.splice(idx, 1); - }, - - /** - * Called on browser window closed, to destroy related WidgetViews - * @params {ChromeWindow} window - * Window that has been closed - */ - _onWindowClosed: function _onWindowClosed(window) { - for each (let view in this._views) { - if (view._isInChromeWindow(window)) { - view.destroy(); - break; - } - } - }, - - /** - * Get the WidgetView instance related to a BrowserWindow instance - * @params {BrowserWindow} window - * BrowserWindow reference from "windows" module - */ - getView: function getView(window) { - for each (let view in this._views) { - if (view._isInWindow(window)) { - return view._public; - } - } - return null; - }, - - get port() this._port._public, - set port(v) {}, // Work around Cortex failure with getter without setter - // See bug 653464 - _port: null, - - postMessage: function postMessage(message) { - this._views.forEach(function(v) v.postMessage(message)); - }, - - destroy: function destroy() { - if (this.panel) - this.panel.destroy(); - - // Dispatch destroy calls to views - // we need to go backward as we remove items from this array in - // _onViewDestroyed - for (let i = this._views.length - 1; i >= 0; i--) - this._views[i].destroy(); - - // Unregister widget to stop creating it over new windows - // and allow creation of new widget with same id - browserManager.removeItem(this); - } - -})); - -// Widget constructor -const Widget = function Widget(options) { - let w = WidgetTrait.create(Widget.prototype); - w._initWidget(options); - - // Return a Cortex of widget in order to hide private attributes like _onEvent - let _public = Cortex(w); - unload.ensure(_public, "destroy"); - return _public; -} -exports.Widget = Widget; - - - -/** - * WidgetView is an instance of a widget for a specific window. - * - * This is an external API that can be retrieved by calling Widget.getView or - * by watching `attach` event on Widget. - */ -const WidgetViewTrait = LightTrait.compose(EventEmitterTrait, LightTrait({ - - // Reference to the matching WidgetChrome - // set right after constructor call - _chrome: null, - - // Public interface of the WidgetView, passed in `attach` event or in - // Widget.getView - _public: null, - - _initWidgetView: function WidgetView__initWidgetView(baseWidget) { - this._baseWidget = baseWidget; - - model.setAttributes(this, widgetAttributes, baseWidget); - - this.on('change', this._onChange.bind(this)); - - let self = this; - this._port = EventEmitterTrait.create({ - emit: function () { - if (!self._chrome) - throw new Error(ERR_DESTROYED); - self._chrome.update(self._baseWidget, "emit", arguments); - } - }); - // expose wrapped port, that exposes only public properties. - this._port._public = Cortex(this._port); - - this._public = Cortex(this); - }, - - _onChange: function WidgetView__onChange(name, value) { - if (name == 'tooltip' && !value) { - this.tooltip = this.label; - return; - } - - // Forward attributes changes to WidgetChrome instance - if (['width', 'tooltip', 'content', 'contentURL'].indexOf(name) != -1) { - this._chrome.update(this._baseWidget, name, value); - } - }, - - _onEvent: function WidgetView__onEvent(type, eventData, domNode) { - // Dispatch event in view - this._emit(type, eventData); - - // And forward it to the main Widget object - if ("click" == type || type.indexOf("mouse") == 0) - this._baseWidget._onEvent(type, this._public); - else - this._baseWidget._onEvent(type, eventData); - - // Special case for click events: if the widget doesn't have a click - // handler, but it does have a panel, display the panel. - if ("click" == type && !this._listeners("click").length && this.panel) - this.panel.show(domNode); - }, - - _isInWindow: function WidgetView__isInWindow(window) { - return windowsAPI.BrowserWindow({ - window: this._chrome.window - }) == window; - }, - - _isInChromeWindow: function WidgetView__isInChromeWindow(window) { - return this._chrome.window == window; - }, - - _onPortEvent: function WidgetView__onPortEvent(args) { - let port = this._port; - port._emit.apply(port, args); - let basePort = this._baseWidget._port; - basePort._emit.apply(basePort, args); - }, - - get port() this._port._public, - set port(v) {}, // Work around Cortex failure with getter without setter - // See bug 653464 - _port: null, - - postMessage: function WidgetView_postMessage(message) { - if (!this._chrome) - throw new Error(ERR_DESTROYED); - this._chrome.update(this._baseWidget, "postMessage", message); - }, - - destroy: function WidgetView_destroy() { - this._chrome.destroy(); - delete this._chrome; - this._baseWidget._onViewDestroyed(this); - this._emit("detach"); - } - -})); - -const WidgetView = function WidgetView(baseWidget) { - let w = WidgetViewTrait.create(WidgetView.prototype); - w._initWidgetView(baseWidget); - return w; -} - - - -/** - * Keeps track of all browser windows. - * Exposes methods for adding/removing widgets - * across all open windows (and future ones). - * Create a new instance of BrowserWindow per window. - */ -let browserManager = { - items: [], - windows: [], - - // Registers the manager to listen for window openings and closings. Note - // that calling this method can cause onTrack to be called immediately if - // there are open windows. - init: function () { - let windowTracker = new (require("api-utils/window-utils").WindowTracker)(this); - unload.ensure(windowTracker); - }, - - // Registers a window with the manager. This is a WindowTracker callback. - onTrack: function browserManager_onTrack(window) { - if (this._isBrowserWindow(window)) { - let win = new BrowserWindow(window); - win.addItems(this.items); - this.windows.push(win); - } - }, - - // Unregisters a window from the manager. It's told to undo all - // modifications. This is a WindowTracker callback. Note that when - // WindowTracker is unloaded, it calls onUntrack for every currently opened - // window. The browserManager therefore doesn't need to specially handle - // unload itself, since unloading the browserManager means untracking all - // currently opened windows. - onUntrack: function browserManager_onUntrack(window) { - if (this._isBrowserWindow(window)) { - this.items.forEach(function(i) i._onWindowClosed(window)); - for (let i = 0; i < this.windows.length; i++) { - if (this.windows[i].window == window) { - this.windows.splice(i, 1)[0]; - return; - } - } - - } - }, - - // Used to validate widget by browserManager before adding it, - // in order to check input very early in widget constructor - validate : function (item) { - let idx = this.items.indexOf(item); - if (idx > -1) - throw new Error("The widget " + item + " has already been added."); - if (item.id) { - let sameId = this.items.filter(function(i) i.id == item.id); - if (sameId.length > 0) - throw new Error("This widget ID is already used: " + item.id); - } else { - item.id = this.items.length; - } - }, - - // Registers an item with the manager. It's added to all currently registered - // windows, and when new windows are registered it will be added to them, too. - addItem: function browserManager_addItem(item) { - this.items.push(item); - this.windows.forEach(function (w) w.addItems([item])); - }, - - // Unregisters an item from the manager. It's removed from all windows that - // are currently registered. - removeItem: function browserManager_removeItem(item) { - let idx = this.items.indexOf(item); - if (idx > -1) - this.items.splice(idx, 1); - }, - - _isBrowserWindow: function browserManager__isBrowserWindow(win) { - let winType = win.document.documentElement.getAttribute("windowtype"); - return winType === "navigator:browser"; - } -}; - - - -/** - * Keeps track of a single browser window. - * - * This is where the core of how a widget's content is added to a window lives. - */ -function BrowserWindow(window) { - this.window = window; - this.doc = window.document; -} - -BrowserWindow.prototype = { - - // Adds an array of items to the window. - addItems: function BW_addItems(items) { - items.forEach(this._addItemToWindow, this); - }, - - _addItemToWindow: function BW__addItemToWindow(baseWidget) { - // Create a WidgetView instance - let widget = baseWidget._createView(); - - // Create a WidgetChrome instance - let item = new WidgetChrome({ - widget: widget, - doc: this.doc, - window: this.window - }); - - widget._chrome = item; - - this._insertNodeInToolbar(item.node); - - // We need to insert Widget DOM Node before finishing widget view creation - // (because fill creates an iframe and tries to access its docShell) - item.fill(); - }, - - _insertNodeInToolbar: function BW__insertNodeInToolbar(node) { - // Add to the customization palette - let toolbox = this.doc.getElementById("navigator-toolbox"); - let palette = toolbox.palette; - palette.appendChild(node); - - // Search for widget toolbar by reading toolbar's currentset attribute - let container = null; - let toolbars = this.doc.getElementsByTagName("toolbar"); - let id = node.getAttribute("id"); - for (let i = 0, l = toolbars.length; i < l; i++) { - let toolbar = toolbars[i]; - if (toolbar.getAttribute("currentset").indexOf(id) == -1) - continue; - container = toolbar; - } - - // if widget isn't in any toolbar, add it to the addon-bar - // TODO: we may want some "first-launch" module to do this only on very - // first execution - if (!container) { - container = this.doc.getElementById("addon-bar"); - // TODO: find a way to make the following code work when we use "cfx run": - // http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#8586 - // until then, force display of addon bar directly from sdk code - // https://bugzilla.mozilla.org/show_bug.cgi?id=627484 - if (container.collapsed) - this.window.toggleAddonBar(); - } - - // Now retrieve a reference to the next toolbar item - // by reading currentset attribute on the toolbar - let nextNode = null; - let currentSet = container.getAttribute("currentset"); - let ids = (currentSet == "__empty") ? [] : currentSet.split(","); - let idx = ids.indexOf(id); - if (idx != -1) { - for (let i = idx; i < ids.length; i++) { - nextNode = this.doc.getElementById(ids[i]); - if (nextNode) - break; - } - } - - // Finally insert our widget in the right toolbar and in the right position - container.insertItem(id, nextNode, null, false); - - // Update DOM in order to save position if we remove/readd the widget - container.setAttribute("currentset", container.currentSet); - // Save DOM attribute in order to save position on new window opened - this.window.document.persist(container.id, "currentset"); - } -} - - -/** - * Final Widget class that handles chrome DOM Node: - * - create initial DOM nodes - * - receive instruction from WidgetView through update method and update DOM - * - watch for DOM events and forward them to WidgetView - */ -function WidgetChrome(options) { - this.window = options.window; - this._doc = options.doc; - this._widget = options.widget; - this._symbiont = null; // set later - this.node = null; // set later - - this._createNode(); -} - -// Update a property of a widget. -WidgetChrome.prototype.update = function WC_update(updatedItem, property, value) { - switch(property) { - case "contentURL": - case "content": - this.setContent(); - break; - case "width": - this.node.style.minWidth = value + "px"; - this.node.querySelector("iframe").style.width = value + "px"; - break; - case "tooltip": - this.node.setAttribute("tooltiptext", value); - break; - case "postMessage": - this._symbiont.postMessage(value); - break; - case "emit": - let port = this._symbiont.port; - port.emit.apply(port, value); - break; - } -} - -// Add a widget to this window. -WidgetChrome.prototype._createNode = function WC__createNode() { - // XUL element container for widget - let node = this._doc.createElement("toolbaritem"); - let guid = require("api-utils/xpcom").makeUuid().toString(); - - // Temporary work around require("self") failing on unit-test execution ... - let jetpackID = "testID"; - try { - jetpackID = require("self").id; - } catch(e) {} - - // Compute an unique and stable widget id with jetpack id and widget.id - let id = "widget:" + jetpackID + "-" + this._widget.id; - node.setAttribute("id", id); - node.setAttribute("label", this._widget.label); - node.setAttribute("tooltiptext", this._widget.tooltip); - node.setAttribute("align", "center"); - - // TODO move into a stylesheet, configurable by consumers. - // Either widget.style, exposing the style object, or a URL - // (eg, can load local stylesheet file). - node.setAttribute("style", [ - "overflow: hidden; margin: 1px 2px 1px 2px; padding: 0px;", - "min-height: 16px;", - ].join("")); - - node.style.minWidth = this._widget.width + "px"; - - this.node = node; -} - -// Initial population of a widget's content. -WidgetChrome.prototype.fill = function WC_fill() { - // Create element - var iframe = this._doc.createElement("iframe"); - iframe.setAttribute("type", "content"); - iframe.setAttribute("transparent", "transparent"); - iframe.style.overflow = "hidden"; - iframe.style.height = "16px"; - iframe.style.maxHeight = "16px"; - iframe.style.width = this._widget.width + "px"; - iframe.setAttribute("flex", "1"); - iframe.style.border = "none"; - iframe.style.padding = "0px"; - - // Do this early, because things like contentWindow are null - // until the node is attached to a document. - this.node.appendChild(iframe); - - // add event handlers - this.addEventHandlers(); - - // set content - this.setContent(); -} - -// Get widget content type. -WidgetChrome.prototype.getContentType = function WC_getContentType() { - if (this._widget.content) - return CONTENT_TYPE_HTML; - return (this._widget.contentURL && /\.(jpg|gif|png|ico)$/.test(this._widget.contentURL)) - ? CONTENT_TYPE_IMAGE : CONTENT_TYPE_URI; -} - -// Set widget content. -WidgetChrome.prototype.setContent = function WC_setContent() { - let type = this.getContentType(); - let contentURL = null; - - switch (type) { - case CONTENT_TYPE_HTML: - contentURL = "data:text/html," + encodeURIComponent(this._widget.content); - break; - case CONTENT_TYPE_URI: - contentURL = this._widget.contentURL; - break; - case CONTENT_TYPE_IMAGE: - let imageURL = this._widget.contentURL; - contentURL = "data:text/html,<html><body><img src='" + - encodeURI(imageURL) + "'></body></html>"; - break; - default: - throw new Error("The widget's type cannot be determined."); - } - - let iframe = this.node.firstElementChild; - - let self = this; - // Cleanup previously created symbiont (in case we are update content) - if (this._symbiont) - this._symbiont.destroy(); - - this._symbiont = Trait.compose(Symbiont.resolve({ - _onContentScriptEvent: "_onContentScriptEvent-not-used" - }), { - _onContentScriptEvent: function () { - // Redirect events to WidgetView - self._widget._onPortEvent(arguments); - } - })({ - frame: iframe, - contentURL: contentURL, - contentScriptFile: this._widget.contentScriptFile, - contentScript: this._widget.contentScript, - contentScriptWhen: this._widget.contentScriptWhen, - allow: this._widget.allow, - onMessage: function(message) { - timer.setTimeout(function() { - self._widget._onEvent("message", message); - }, 0); - } - }); -} - -// Detect if document consists of a single image. -WidgetChrome._isImageDoc = function WC__isImageDoc(doc) { - return doc.body.childNodes.length == 1 && - doc.body.firstElementChild && - doc.body.firstElementChild.tagName == "IMG"; -} - -// Set up all supported events for a widget. -WidgetChrome.prototype.addEventHandlers = function WC_addEventHandlers() { - let contentType = this.getContentType(); - - let self = this; - let listener = function(e) { - // Ignore event firings that target the iframe. - if (e.target == self.node.firstElementChild) - return; - - // The widget only supports left-click for now, - // so ignore right-clicks. - if (e.type == "click" && e.button == 2) - return; - - // Proxy event to the widget - timer.setTimeout(function() { - self._widget._onEvent(EVENTS[e.type], null, self.node); - }, 0); - }; - - this.eventListeners = {}; - let iframe = this.node.firstElementChild; - for (let [type, method] in Iterator(EVENTS)) { - iframe.addEventListener(type, listener, true, true); - - // Store listeners for later removal - this.eventListeners[type] = listener; - } - - // On document load, make modifications required for nice default - // presentation. - let self = this; - function loadListener(e) { - // Ignore event firings that target the iframe - if (e.target == iframe) - return; - // Ignore about:blank loads - if (e.type == "load" && e.target.location == "about:blank") - return; - - // We may have had an unload event before that cleaned up the symbiont - if (!self._symbiont) - self.setContent(); - - let doc = e.target; - if (contentType == CONTENT_TYPE_IMAGE || WidgetChrome._isImageDoc(doc)) { - // Force image content to size. - // Add-on authors must size their images correctly. - doc.body.firstElementChild.style.width = self._widget.width + "px"; - doc.body.firstElementChild.style.height = "16px"; - } - - // Allow all content to fill the box by default. - doc.body.style.margin = "0"; - } - iframe.addEventListener("load", loadListener, true); - this.eventListeners["load"] = loadListener; - - // Register a listener to unload symbiont if the toolbaritem is moved - // on user toolbars customization - function unloadListener(e) { - if (e.target.location == "about:blank") - return; - self._symbiont.destroy(); - self._symbiont = null; - // This may fail but not always, it depends on how the node is - // moved or removed - try { - self.setContent(); - } catch(e) {} - - } - - iframe.addEventListener("unload", unloadListener, true); - this.eventListeners["unload"] = unloadListener; -} - -// Remove and unregister the widget from everything -WidgetChrome.prototype.destroy = function WC_destroy(removedItems) { - // remove event listeners - for (let [type, listener] in Iterator(this.eventListeners)) - this.node.firstElementChild.removeEventListener(type, listener, true); - // remove dom node - this.node.parentNode.removeChild(this.node); - // cleanup symbiont - this._symbiont.destroy(); - // cleanup itself - this.eventListeners = null; - this._widget = null; - this._symbiont = null; -} - -// Init the browserManager only after setting prototypes and such above, because -// it will cause browserManager.onTrack to be called immediately if there are -// open windows. -browserManager.init(); diff --git a/tools/addon-sdk-1.4/packages/addon-kit/lib/windows.js b/tools/addon-sdk-1.4/packages/addon-kit/lib/windows.js deleted file mode 100644 index e9e097b..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/lib/windows.js +++ /dev/null @@ -1,238 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Felipe Gomes <felipc@gmail.com> (Original author) - * Irakli Gozalishvili <gozala@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -"use strict"; - -if (!require("api-utils/xul-app").is("Firefox")) { - throw new Error([ - "The windows module currently supports only Firefox. In the future", - " we would like it to support other applications, however. Please see ", - "https://bugzilla.mozilla.org/show_bug.cgi?id=571449 for more information." - ].join("")); -} - -const { Cc, Ci } = require('chrome'), - { Trait } = require('api-utils/traits'), - { List } = require('api-utils/list'), - { EventEmitter } = require('api-utils/events'), - { WindowTabs, WindowTabTracker } = require('api-utils/windows/tabs'), - { WindowDom } = require('api-utils/windows/dom'), - { WindowLoader } = require('api-utils/windows/loader'), - { WindowTrackerTrait } = require('api-utils/window-utils'), - { Options } = require('api-utils/tabs/tab'), - { utils } = require('api-utils/xpcom'), - apiUtils = require('api-utils/api-utils'), - unload = require('api-utils/unload'), - - WM = Cc['@mozilla.org/appshell/window-mediator;1']. - getService(Ci.nsIWindowMediator), - - BROWSER = 'navigator:browser'; - -/** - * Window trait composes safe wrappers for browser window that are E10S - * compatible. - */ -const BrowserWindowTrait = Trait.compose( - EventEmitter, - WindowDom.resolve({ close: '_close' }), - WindowTabs, - WindowTabTracker, - WindowLoader, - /* WindowSidebars, */ - Trait.compose({ - _emit: Trait.required, - _close: Trait.required, - _load: Trait.required, - /** - * Constructor returns wrapper of the specified chrome window. - * @param {nsIWindow} window - */ - constructor: function BrowserWindow(options) { - // Register this window ASAP, in order to avoid loop that would try - // to create this window instance over and over (see bug 648244) - windows.push(this); - - // make sure we don't have unhandled errors - this.on('error', console.exception.bind(console)); - - if ('onOpen' in options) - this.on('open', options.onOpen); - if ('onClose' in options) - this.on('close', options.onClose); - if ('window' in options) - this._window = options.window; - if ('tabs' in options) { - this._tabOptions = Array.isArray(options.tabs) ? - options.tabs.map(Options) : - [ Options(options.tabs) ]; - } - else if ('url' in options) { - this._tabOptions = [ Options(options.url) ]; - } - this._load(); - return this; - }, - _tabOptions: [], - _onLoad: function() { - try { - this._initWindowTabTracker(); - } catch(e) { - this._emit('error', e) - } - this._emitOnObject(browserWindows, 'open', this._public); - }, - _onUnload: function() { - this._destroyWindowTabTracker(); - this._emitOnObject(browserWindows, 'close', this._public); - this._window = null; - // Removing reference from the windows array. - windows.splice(windows.indexOf(this), 1); - this._removeAllListeners('close'); - this._removeAllListeners('open'); - this._removeAllListeners('ready'); - }, - close: function close(callback) { - // maybe we should deprecate this with message ? - if (callback) this.on('close', callback); - return this._close(); - } - }) -); -/** - * Wrapper for `BrowserWindowTrait`. Creates new instance if wrapper for - * window doesn't exists yet. If wrapper already exists then returns it - * instead. - * @params {Object} options - * Options that are passed to the the `BrowserWindowTrait` - * @returns {BrowserWindow} - * @see BrowserWindowTrait - */ -function BrowserWindow(options) { - let chromeWindow = options.window; - for each (let window in windows) { - if (chromeWindow == window._window) - return window._public - } - let window = BrowserWindowTrait(options); - return window._public; -} -// to have proper `instanceof` behavior will go away when #596248 is fixed. -BrowserWindow.prototype = BrowserWindowTrait.prototype; -exports.BrowserWindow = BrowserWindow -const windows = []; -/** - * `BrowserWindows` trait is composed out of `List` trait and it represents - * "live" list of currently open browser windows. Instance mutates itself - * whenever new browser window gets opened / closed. - */ -// Very stupid to resolve all `toStrings` but this will be fixed by #596248 -const browserWindows = Trait.resolve({ toString: null }).compose( - List.resolve({ constructor: '_initList' }), - EventEmitter.resolve({ toString: null }), - WindowTrackerTrait.resolve({ constructor: '_initTracker', toString: null }), - Trait.compose({ - _emit: Trait.required, - _add: Trait.required, - _remove: Trait.required, - - // public API - - /** - * Constructor creates instance of `Windows` that represents live list of open - * windows. - */ - constructor: function BrowserWindows() { - this._trackedWindows = []; - this._initList(); - this._initTracker(); - unload.ensure(this, "_destructor"); - }, - _destructor: function _destructor() { - this._removeAllListeners('open'); - this._removeAllListeners('close'); - }, - /** - * This property represents currently active window. - * Property is non-enumerable, in order to preserve array like enumeration. - * @type {Window|null} - */ - get activeWindow() { - let window = WM.getMostRecentWindow(BROWSER); - return this._isBrowser(window) ? BrowserWindow({ window: window }) : null; - }, - open: function open(options) { - if (typeof options === "string") - // `tabs` option is under review and may be removed. - options = { tabs: [Options(options)] }; - return BrowserWindow(options); - }, - /** - * Returns true if specified window is a browser window. - * @param {nsIWindow} window - * @returns {Boolean} - */ - _isBrowser: function _isBrowser(window) - BROWSER === window.document.documentElement.getAttribute("windowtype") - , - /** - * Internal listener which is called whenever new window gets open. - * Creates wrapper and adds to this list. - * @param {nsIWindow} chromeWindow - */ - _onTrack: function _onTrack(chromeWindow) { - if (!this._isBrowser(chromeWindow)) return; - let window = BrowserWindow({ window: chromeWindow }); - this._add(window); - this._emit('open', window); - }, - /** - * Internal listener which is called whenever window gets closed. - * Cleans up references and removes wrapper from this list. - * @param {nsIWindow} window - */ - _onUntrack: function _onUntrack(chromeWindow) { - if (!this._isBrowser(chromeWindow)) return; - let window = BrowserWindow({ window: chromeWindow }); - // `_onUnload` method of the `BrowserWindow` will remove `chromeWindow` - // from the `windows` array. - this._remove(window); - this._emit('close', window); - } - }).resolve({ toString: null }) -)(); -exports.browserWindows = browserWindows; - diff --git a/tools/addon-sdk-1.4/packages/addon-kit/package.json b/tools/addon-sdk-1.4/packages/addon-kit/package.json deleted file mode 100644 index 9c62ae8..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "addon-kit", - "description": "Add-on development made easy.", - "keywords": ["javascript", "engine", "platform", "xulrunner"], - "author": "Atul Varma (http://toolness.com/) <atul@mozilla.com>", - "contributors": [ - "Myk Melez (http://melez.com/) <myk@mozilla.org>", - "Daniel Aquino <mr.danielaquino@gmail.com>" - ], - "license": "MPL 1.1/GPL 2.0/LGPL 2.1", - "dependencies": ["api-utils"] -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/helpers.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/helpers.js deleted file mode 100644 index bbfe911..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/helpers.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; - -const { Loader } = require("@loader"); - -exports.Loader = function(module, globals) { - var options = JSON.parse(JSON.stringify(require("@packaging"))); - options.globals = globals; - let loader = Loader.new(options); - return Object.create(loader, { - require: { value: Loader.require.bind(loader, module.path) }, - sandbox: { value: function sandbox(id) { - let path = options.manifest[module.path].requirements[id].path; - return loader.sandboxes[path].sandbox; - }}, - unload: { value: function unload(reason, callback) { - loader.unload(reason, callback); - }} - }) -}; diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/pagemod-test-helpers.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/pagemod-test-helpers.js deleted file mode 100644 index 7e87a85..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/pagemod-test-helpers.js +++ /dev/null @@ -1,63 +0,0 @@ -"use strict"; - -const {Cc,Ci} = require("chrome"); -const timer = require("timer"); -const xulApp = require("xul-app"); -const { Loader } = require('./helpers'); - -/** - * A helper function that creates a PageMod, then opens the specified URL - * and checks the effect of the page mod on 'onload' event via testCallback. - */ -exports.testPageMod = function testPageMod(test, testURL, pageModOptions, - testCallback, timeout) { - if (!xulApp.versionInRange(xulApp.platformVersion, "1.9.3a3", "*") && - !xulApp.versionInRange(xulApp.platformVersion, "1.9.2.7", "1.9.2.*")) { - test.pass("Note: not testing PageMod, as it doesn't work on this platform version"); - return null; - } - - var wm = Cc['@mozilla.org/appshell/window-mediator;1'] - .getService(Ci.nsIWindowMediator); - var browserWindow = wm.getMostRecentWindow("navigator:browser"); - if (!browserWindow) { - test.pass("page-mod tests: could not find the browser window, so " + - "will not run. Use -a firefox to run the pagemod tests.") - return null; - } - - if (timeout !== undefined) - test.waitUntilDone(timeout); - else - test.waitUntilDone(); - - let loader = Loader(module); - let pageMod = loader.require("page-mod"); - - var pageMods = [new pageMod.PageMod(opts) for each(opts in pageModOptions)]; - - var tabBrowser = browserWindow.gBrowser; - var newTab = tabBrowser.addTab(testURL); - tabBrowser.selectedTab = newTab; - var b = tabBrowser.getBrowserForTab(newTab); - - function onPageLoad() { - b.removeEventListener("load", onPageLoad, true); - // Delay callback execute as page-mod content scripts may be executed on - // load event. So page-mod actions may not be already done. - // If we delay even more contentScriptWhen:'end', we may want to modify - // this code again. - timer.setTimeout(testCallback, 0, - b.contentWindow.wrappedJSObject, - function done() { - pageMods.forEach(function(mod) mod.destroy()); - // XXX leaks reported if we don't close the tab? - tabBrowser.removeTab(newTab); - loader.unload(); - test.done(); - }); - } - b.addEventListener("load", onPageLoad, true); - - return pageMods; -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-clipboard.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-clipboard.js deleted file mode 100644 index 5f61d48..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-clipboard.js +++ /dev/null @@ -1,60 +0,0 @@ - -// Test the typical use case, setting & getting with no flavors specified -exports.testWithNoFlavor = function(test) { - var contents = "hello there"; - var flavor = "text"; - var fullFlavor = "text/unicode"; - var clip = require("clipboard"); - // Confirm we set the clipboard - test.assert(clip.set(contents)); - // Confirm flavor is set - test.assertEqual(clip.currentFlavors[0], flavor); - // Confirm we set the clipboard - test.assertEqual(clip.get(), contents); - // Confirm we can get the clipboard using the flavor - test.assertEqual(clip.get(flavor), contents); - // Confirm we can still get the clipboard using the full flavor - test.assertEqual(clip.get(fullFlavor), contents); -}; - -// Test the slightly less common case where we specify the flavor -exports.testWithFlavor = function(test) { - var contents = "<b>hello there</b>"; - var contentsText = "hello there"; - var flavor = "html"; - var fullFlavor = "text/html"; - var unicodeFlavor = "text"; - var unicodeFullFlavor = "text/unicode"; - var clip = require("clipboard"); - test.assert(clip.set(contents, flavor)); - test.assertEqual(clip.currentFlavors[0], unicodeFlavor); - test.assertEqual(clip.currentFlavors[1], flavor); - test.assertEqual(clip.get(), contentsText); - test.assertEqual(clip.get(flavor), contents); - test.assertEqual(clip.get(fullFlavor), contents); - test.assertEqual(clip.get(unicodeFlavor), contentsText); - test.assertEqual(clip.get(unicodeFullFlavor), contentsText); -}; - -// Test that the typical case still works when we specify the flavor to set -exports.testWithRedundantFlavor = function(test) { - var contents = "<b>hello there</b>"; - var flavor = "text"; - var fullFlavor = "text/unicode"; - var clip = require("clipboard"); - test.assert(clip.set(contents, flavor)); - test.assertEqual(clip.currentFlavors[0], flavor); - test.assertEqual(clip.get(), contents); - test.assertEqual(clip.get(flavor), contents); - test.assertEqual(clip.get(fullFlavor), contents); -}; - -exports.testNotInFlavor = function(test) { - var contents = "hello there"; - var flavor = "html"; - var clip = require("clipboard"); - test.assert(clip.set(contents)); - // If there's nothing on the clipboard with this flavor, should return null - test.assertEqual(clip.get(flavor), null); -}; -// TODO: Test error cases. diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-context-menu.html b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-context-menu.html deleted file mode 100644 index a0fb5cb..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-context-menu.html +++ /dev/null @@ -1,78 +0,0 @@ -<!-- ***** BEGIN LICENSE BLOCK ***** - - Version: MPL 1.1/GPL 2.0/LGPL 2.1 - - - - The contents of this file are subject to the Mozilla Public License Version - - 1.1 (the "License"); you may not use this file except in compliance with - - the License. You may obtain a copy of the License at - - http://www.mozilla.org/MPL/ - - - - Software distributed under the License is distributed on an "AS IS" basis, - - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - - for the specific language governing rights and limitations under the - - License. - - - - The Original Code is Jetpack. - - - - The Initial Developer of the Original Code is - - the Mozilla Foundation. - - Portions created by the Initial Developer are Copyright (C) 2010 - - the Initial Developer. All Rights Reserved. - - - - Contributor(s): - - Drew Willcoxon <adw@mozilla.com> (Original Author) - - - - Alternatively, the contents of this file may be used under the terms of - - either the GNU General Public License Version 2 or later (the "GPL"), or - - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - - in which case the provisions of the GPL or the LGPL are applicable instead - - of those above. If you wish to allow use of your version of this file only - - under the terms of either the GPL or the LGPL, and not to allow others to - - use your version of this file under the terms of the MPL, indicate your - - decision by deleting the provisions above and replace them with the notice - - and other provisions required by the LGPL or the GPL. If you do not delete - - the provisions above, a recipient may use your version of this file under - - the terms of any one of the MPL, the GPL or the LGPL. - - - - ***** END LICENSE BLOCK ***** --> - -<html> - <head> - <title>Context menu test</title> - </head> - <body> - <p> - <img id="image" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="> - </p> - - <p> - <a id="link" href=""> - A simple link. - </a> - </p> - - <p> - <a href=""> - <span id="span-link"> - A span inside a link. - </span> - </a> - </p> - - <p id="text"> - Some text. - </p> - - <p> - <textarea id="textfield"> - A text field, - with some text. - </textarea> - </p> - - <p> - <iframe id="iframe" src="data:text/html,An iframe." - width="200" height="100"> - </iframe> - </p> - </body> -</html> diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-context-menu.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-context-menu.js deleted file mode 100644 index 157edf1..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-context-menu.js +++ /dev/null @@ -1,2075 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Drew Willcoxon <adw@mozilla.com> (Original Author) - * Matteo Ferretti <zer0@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -let {Cc,Ci} = require("chrome"); -const { Loader } = require('./helpers'); - -// These should match the same constants in the module. -const ITEM_CLASS = "jetpack-context-menu-item"; -const SEPARATOR_ID = "jetpack-context-menu-separator"; -const OVERFLOW_THRESH_DEFAULT = 10; -const OVERFLOW_THRESH_PREF = - "extensions.addon-sdk.context-menu.overflowThreshold"; -const OVERFLOW_MENU_ID = "jetpack-content-menu-overflow-menu"; -const OVERFLOW_POPUP_ID = "jetpack-content-menu-overflow-popup"; - -const TEST_DOC_URL = module.uri.replace(/\.js$/, ".html"); - - -// Destroying items that were previously created should cause them to be absent -// from the menu. -exports.testConstructDestroy = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - // Create an item. - let item = new loader.cm.Item({ label: "item" }); - test.assertEqual(item.parentMenu, null, "item's parent menu should be null"); - - test.showMenu(null, function (popup) { - - // It should be present when the menu is shown. - test.checkMenu([item], [], []); - popup.hidePopup(); - - // Destroy the item. Multiple destroys should be harmless. - item.destroy(); - item.destroy(); - test.showMenu(null, function (popup) { - - // It should be removed from the menu. - test.checkMenu([], [], [item]); - test.done(); - }); - }); -}; - - -// Destroying an item twice should not cause an error. -exports.testDestroyTwice = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = new loader.cm.Item({ label: "item" }); - item.destroy(); - item.destroy(); - - test.pass("Destroying an item twice should not cause an error."); - test.done(); -}; - - -// CSS selector contexts should cause their items to be present in the menu -// when the menu is invoked on nodes that match the selectors. -exports.testSelectorContextMatch = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = new loader.cm.Item({ - label: "item", - data: "item", - context: loader.cm.SelectorContext("img") - }); - - test.withTestDoc(function (window, doc) { - test.showMenu(doc.getElementById("image"), function (popup) { - test.checkMenu([item], [], []); - test.done(); - }); - }); -}; - - -// CSS selector contexts should cause their items to be present in the menu -// when the menu is invoked on nodes that have ancestors that match the -// selectors. -exports.testSelectorAncestorContextMatch = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = new loader.cm.Item({ - label: "item", - data: "item", - context: loader.cm.SelectorContext("a[href]") - }); - - test.withTestDoc(function (window, doc) { - test.showMenu(doc.getElementById("span-link"), function (popup) { - test.checkMenu([item], [], []); - test.done(); - }); - }); -}; - - -// CSS selector contexts should cause their items to be absent from the menu -// when the menu is not invoked on nodes that match or have ancestors that -// match the selectors. -exports.testSelectorContextNoMatch = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = new loader.cm.Item({ - label: "item", - data: "item", - context: loader.cm.SelectorContext("img") - }); - - test.showMenu(null, function (popup) { - test.checkMenu([], [item], []); - test.done(); - }); -}; - - -// Page contexts should cause their items to be present in the menu when the -// menu is not invoked on an active element. -exports.testPageContextMatch = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let items = [ - new loader.cm.Item({ - label: "item 0" - }), - new loader.cm.Item({ - label: "item 1", - context: undefined - }), - new loader.cm.Item({ - label: "item 2", - context: loader.cm.PageContext() - }), - new loader.cm.Item({ - label: "item 3", - context: [loader.cm.PageContext()] - }) - ]; - - test.showMenu(null, function (popup) { - test.checkMenu(items, [], []); - test.done(); - }); -}; - - -// Page contexts should cause their items to be absent from the menu when the -// menu is invoked on an active element. -exports.testPageContextNoMatch = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let items = [ - new loader.cm.Item({ - label: "item 0" - }), - new loader.cm.Item({ - label: "item 1", - context: undefined - }), - new loader.cm.Item({ - label: "item 2", - context: loader.cm.PageContext() - }), - new loader.cm.Item({ - label: "item 3", - context: [loader.cm.PageContext()] - }) - ]; - - test.withTestDoc(function (window, doc) { - test.showMenu(doc.getElementById("image"), function (popup) { - test.checkMenu([], items, []); - test.done(); - }); - }); -}; - - -// Selection contexts should cause items to appear when a selection exists. -exports.testSelectionContextMatch = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = loader.cm.Item({ - label: "item", - context: loader.cm.SelectionContext() - }); - - test.withTestDoc(function (window, doc) { - window.getSelection().selectAllChildren(doc.body); - test.showMenu(null, function (popup) { - test.checkMenu([item], [], []); - test.done(); - }); - }); -}; - - -// Selection contexts should cause items to appear when a selection exists in -// a text field. -exports.testSelectionContextMatchInTextField = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = loader.cm.Item({ - label: "item", - context: loader.cm.SelectionContext() - }); - - test.withTestDoc(function (window, doc) { - let textfield = doc.getElementById("textfield"); - textfield.setSelectionRange(0, textfield.value.length); - test.showMenu(textfield, function (popup) { - test.checkMenu([item], [], []); - test.done(); - }); - }); -}; - - -// Selection contexts should not cause items to appear when a selection does -// not exist in a text field. -exports.testSelectionContextNoMatchInTextField = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = loader.cm.Item({ - label: "item", - context: loader.cm.SelectionContext() - }); - - test.withTestDoc(function (window, doc) { - let textfield = doc.getElementById("textfield"); - textfield.setSelectionRange(0, 0); - test.showMenu(textfield, function (popup) { - test.checkMenu([], [item], []); - test.done(); - }); - }); -}; - - -// Selection contexts should not cause items to appear when a selection does -// not exist. -exports.testSelectionContextNoMatch = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = loader.cm.Item({ - label: "item", - context: loader.cm.SelectionContext() - }); - - test.showMenu(null, function (popup) { - test.checkMenu([], [item], []); - test.done(); - }); -}; - - -// URL contexts should cause items to appear on pages that match. -exports.testURLContextMatch = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let items = [ - loader.cm.Item({ - label: "item 0", - context: loader.cm.URLContext(TEST_DOC_URL) - }), - loader.cm.Item({ - label: "item 1", - context: loader.cm.URLContext([TEST_DOC_URL, "*.bogus.com"]) - }) - ]; - - test.withTestDoc(function (window, doc) { - test.showMenu(null, function (popup) { - test.checkMenu(items, [], []); - test.done(); - }); - }); -}; - - -// URL contexts should not cause items to appear on pages that do not match. -exports.testURLContextNoMatch = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let items = [ - loader.cm.Item({ - label: "item 0", - context: loader.cm.URLContext("*.bogus.com") - }), - loader.cm.Item({ - label: "item 1", - context: loader.cm.URLContext(["*.bogus.com", "*.gnarly.com"]) - }) - ]; - - test.withTestDoc(function (window, doc) { - test.showMenu(null, function (popup) { - test.checkMenu([], items, []); - test.done(); - }); - }); -}; - - -// Removing a non-matching URL context after its item is created and the page is -// loaded should cause the item's content script to be evaluated. -exports.testURLContextRemove = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let shouldBeEvaled = false; - let context = loader.cm.URLContext("*.bogus.com"); - let item = loader.cm.Item({ - label: "item", - context: context, - contentScript: 'self.postMessage("ok");', - onMessage: function (msg) { - test.assert(shouldBeEvaled, - "content script should be evaluated when expected"); - shouldBeEvaled = false; - test.done(); - } - }); - - test.withTestDoc(function (window, doc) { - shouldBeEvaled = true; - item.context.remove(context); - }); -}; - - -// Adding a non-matching URL context after its item is created and the page is -// loaded should cause the item's worker to be destroyed. -exports.testURLContextAdd = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = loader.cm.Item({ label: "item" }); - - test.withTestDoc(function (window, doc) { - let privatePropsKey = loader.globalScope.PRIVATE_PROPS_KEY; - let workerReg = item.valueOf(privatePropsKey)._workerReg; - - let found = false; - for each (let winWorker in workerReg.winWorkers) { - if (winWorker.win === window) { - found = true; - break; - } - } - this.test.assert(found, "window should be present in worker registry"); - - item.context.add(loader.cm.URLContext("*.bogus.com")); - - for each (let winWorker in workerReg.winWorkers) - this.test.assertNotEqual(winWorker.win, window, - "window should not be present in worker registry"); - - test.done(); - }); -}; - - -// Content contexts that return true should cause their items to be present -// in the menu. -exports.testContentContextMatch = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = new loader.cm.Item({ - label: "item", - contentScript: 'self.on("context", function () true);' - }); - - test.showMenu(null, function (popup) { - test.checkMenu([item], [], []); - test.done(); - }); -}; - - -// Content contexts that return false should cause their items to be absent -// from the menu. -exports.testContentContextNoMatch = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = new loader.cm.Item({ - label: "item", - contentScript: 'self.on("context", function () false);' - }); - - test.showMenu(null, function (popup) { - test.checkMenu([], [item], []); - test.done(); - }); -}; - - -// Content contexts that return a string should cause their items to be present -// in the menu and the items' labels to be updated. -exports.testContentContextMatchString = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = new loader.cm.Item({ - label: "first label", - contentScript: 'self.on("context", function () "second label");' - }); - - test.showMenu(null, function (popup) { - test.checkMenu([item], [], []); - test.assertEqual(item.label, "second label", - "item's label should be updated"); - test.done(); - }); -}; - - -// The args passed to context listeners should be correct. -exports.testContentContextArgs = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - let callbacks = 0; - - let item = new loader.cm.Item({ - label: "item", - contentScript: 'self.on("context", function (node) {' + - ' let Ci = Components.interfaces;' + - ' self.postMessage(node instanceof Ci.nsIDOMHTMLElement);' + - ' return false;' + - '});', - onMessage: function (isElt) { - test.assert(isElt, "node should be an HTML element"); - if (++callbacks == 2) test.done(); - } - }); - - test.showMenu(null, function () { - if (++callbacks == 2) test.done(); - }); -}; - -// Multiple contexts imply intersection, not union, and content context -// listeners should not be called if all declarative contexts are not current. -exports.testMultipleContexts = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = new loader.cm.Item({ - label: "item", - context: [loader.cm.SelectorContext("a[href]"), loader.cm.PageContext()], - contentScript: 'self.on("context", function () self.postMessage());', - onMessage: function () { - test.fail("Context listener should not be called"); - } - }); - - test.withTestDoc(function (window, doc) { - test.showMenu(doc.getElementById("span-link"), function (popup) { - test.checkMenu([], [item], []); - test.done(); - }); - }); -}; - - -// Once a context is removed, it should no longer cause its item to appear. -exports.testRemoveContext = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let ctxt = loader.cm.SelectorContext("img"); - let item = new loader.cm.Item({ - label: "item", - context: ctxt - }); - - test.withTestDoc(function (window, doc) { - test.showMenu(doc.getElementById("image"), function (popup) { - - // The item should be present at first. - test.checkMenu([item], [], []); - popup.hidePopup(); - - // Remove the img context and check again. - item.context.remove(ctxt); - test.showMenu(doc.getElementById("image"), function (popup) { - test.checkMenu([], [item], []); - test.done(); - }); - }); - }); -}; - - -// Lots of items should overflow into the overflow submenu. -exports.testOverflow = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let items = []; - for (let i = 0; i < OVERFLOW_THRESH_DEFAULT + 1; i++) { - let item = new loader.cm.Item({ label: "item " + i }); - items.push(item); - } - - test.showMenu(null, function (popup) { - test.checkMenu(items, [], []); - test.done(); - }); -}; - - -// Module unload should cause all items to be removed. -exports.testUnload = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = new loader.cm.Item({ label: "item" }); - - test.showMenu(null, function (popup) { - - // The menu should contain the item. - test.checkMenu([item], [], []); - popup.hidePopup(); - - // Unload the module. - loader.unload(); - test.showMenu(null, function (popup) { - - // The item should be removed from the menu. - test.checkMenu([], [], [item]); - test.done(); - }); - }); -}; - - -// Using multiple module instances to add items without causing overflow should -// work OK. Assumes OVERFLOW_THRESH_DEFAULT <= 2. -exports.testMultipleModulesAdd = function (test) { - test = new TestHelper(test); - let loader0 = test.newLoader(); - let loader1 = test.newLoader(); - - // Use each module to add an item, then unload each module in turn. - let item0 = new loader0.cm.Item({ label: "item 0" }); - let item1 = new loader1.cm.Item({ label: "item 1" }); - - test.showMenu(null, function (popup) { - - // The menu should contain both items. - test.checkMenu([item0, item1], [], []); - popup.hidePopup(); - - // Unload the first module. - loader0.unload(); - test.showMenu(null, function (popup) { - - // The first item should be removed from the menu. - test.checkMenu([item1], [], [item0]); - popup.hidePopup(); - - // Unload the second module. - loader1.unload(); - test.showMenu(null, function (popup) { - - // Both items should be removed from the menu. - test.checkMenu([], [], [item0, item1]); - test.done(); - }); - }); - }); -}; - - -// Using multiple module instances to add items causing overflow should work OK. -exports.testMultipleModulesAddOverflow = function (test) { - test = new TestHelper(test); - let loader0 = test.newLoader(); - let loader1 = test.newLoader(); - - // Use module 0 to add OVERFLOW_THRESH_DEFAULT items. - let items0 = []; - for (let i = 0; i < OVERFLOW_THRESH_DEFAULT; i++) { - let item = new loader0.cm.Item({ label: "item 0 " + i }); - items0.push(item); - } - - // Use module 1 to add one item. - let item1 = new loader1.cm.Item({ label: "item 1" }); - - let allItems = items0.concat(item1); - - test.showMenu(null, function (popup) { - - // The menu should contain all items in overflow. - test.checkMenu(allItems, [], []); - popup.hidePopup(); - - // Unload the first module. - loader0.unload(); - test.showMenu(null, function (popup) { - - // The first items should be removed from the menu, which should not - // overflow. - test.checkMenu([item1], [], items0); - popup.hidePopup(); - - // Unload the second module. - loader1.unload(); - test.showMenu(null, function (popup) { - - // All items should be removed from the menu. - test.checkMenu([], [], allItems); - test.done(); - }); - }); - }); -}; - - -// Using multiple module instances to modify the menu without causing overflow -// should work OK. This test creates two loaders and: -// loader0 create item -> loader1 create item -> loader0.unload -> -// loader1.unload -exports.testMultipleModulesDiffContexts1 = function (test) { - test = new TestHelper(test); - let loader0 = test.newLoader(); - let loader1 = test.newLoader(); - - let item0 = new loader0.cm.Item({ - label: "item 0", - context: loader0.cm.SelectorContext("img") - }); - - let item1 = new loader1.cm.Item({ label: "item 1" }); - - test.showMenu(null, function (popup) { - - // The menu should contain item1. - test.checkMenu([item1], [item0], []); - popup.hidePopup(); - - // Unload module 0. - loader0.unload(); - test.showMenu(null, function (popup) { - - // item0 should be removed from the menu. - test.checkMenu([item1], [], [item0]); - popup.hidePopup(); - - // Unload module 1. - loader1.unload(); - test.showMenu(null, function (popup) { - - // Both items should be removed from the menu. - test.checkMenu([], [], [item0, item1]); - test.done(); - }); - }); - }); -}; - - -// Using multiple module instances to modify the menu without causing overflow -// should work OK. This test creates two loaders and: -// loader1 create item -> loader0 create item -> loader0.unload -> -// loader1.unload -exports.testMultipleModulesDiffContexts2 = function (test) { - test = new TestHelper(test); - let loader0 = test.newLoader(); - let loader1 = test.newLoader(); - - let item1 = new loader1.cm.Item({ label: "item 1" }); - - let item0 = new loader0.cm.Item({ - label: "item 0", - context: loader0.cm.SelectorContext("img") - }); - - test.showMenu(null, function (popup) { - - // The menu should contain item1. - test.checkMenu([item1], [item0], []); - popup.hidePopup(); - - // Unload module 0. - loader0.unload(); - test.showMenu(null, function (popup) { - - // item0 should be removed from the menu. - test.checkMenu([item1], [], [item0]); - popup.hidePopup(); - - // Unload module 1. - loader1.unload(); - test.showMenu(null, function (popup) { - - // Both items should be removed from the menu. - test.checkMenu([], [], [item0, item1]); - test.done(); - }); - }); - }); -}; - - -// Using multiple module instances to modify the menu without causing overflow -// should work OK. This test creates two loaders and: -// loader0 create item -> loader1 create item -> loader1.unload -> -// loader0.unload -exports.testMultipleModulesDiffContexts3 = function (test) { - test = new TestHelper(test); - let loader0 = test.newLoader(); - let loader1 = test.newLoader(); - - let item0 = new loader0.cm.Item({ - label: "item 0", - context: loader0.cm.SelectorContext("img") - }); - - let item1 = new loader1.cm.Item({ label: "item 1" }); - - test.showMenu(null, function (popup) { - - // The menu should contain item1. - test.checkMenu([item1], [item0], []); - popup.hidePopup(); - - // Unload module 1. - loader1.unload(); - test.showMenu(null, function (popup) { - - // item1 should be removed from the menu. - test.checkMenu([], [item0], [item1]); - popup.hidePopup(); - - // Unload module 0. - loader0.unload(); - test.showMenu(null, function (popup) { - - // Both items should be removed from the menu. - test.checkMenu([], [], [item0, item1]); - test.done(); - }); - }); - }); -}; - - -// Using multiple module instances to modify the menu without causing overflow -// should work OK. This test creates two loaders and: -// loader1 create item -> loader0 create item -> loader1.unload -> -// loader0.unload -exports.testMultipleModulesDiffContexts4 = function (test) { - test = new TestHelper(test); - let loader0 = test.newLoader(); - let loader1 = test.newLoader(); - - let item1 = new loader1.cm.Item({ label: "item 1" }); - - let item0 = new loader0.cm.Item({ - label: "item 0", - context: loader0.cm.SelectorContext("img") - }); - - test.showMenu(null, function (popup) { - - // The menu should contain item1. - test.checkMenu([item1], [item0], []); - popup.hidePopup(); - - // Unload module 1. - loader1.unload(); - test.showMenu(null, function (popup) { - - // item1 should be removed from the menu. - test.checkMenu([], [item0], [item1]); - popup.hidePopup(); - - // Unload module 0. - loader0.unload(); - test.showMenu(null, function (popup) { - - // Both items should be removed from the menu. - test.checkMenu([], [], [item0, item1]); - test.done(); - }); - }); - }); -}; - - -// Test interactions between a loaded module, unloading another module, and the -// menu separator and overflow submenu. -exports.testMultipleModulesAddRemove = function (test) { - test = new TestHelper(test); - let loader0 = test.newLoader(); - let loader1 = test.newLoader(); - - let item = new loader0.cm.Item({ label: "item" }); - - test.showMenu(null, function (popup) { - - // The menu should contain the item. - test.checkMenu([item], [], []); - popup.hidePopup(); - - // Remove the item. - item.destroy(); - test.showMenu(null, function (popup) { - - // The item should be removed from the menu. - test.checkMenu([], [], [item]); - popup.hidePopup(); - - // Unload module 1. - loader1.unload(); - test.showMenu(null, function (popup) { - - // There shouldn't be any errors involving the menu separator or - // overflow submenu. - test.checkMenu([], [], [item]); - test.done(); - }); - }); - }); -}; - - -// An item's click listener should work. -exports.testItemClick = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = new loader.cm.Item({ - label: "item", - data: "item data", - contentScript: 'self.on("click", function (node, data) {' + - ' let Ci = Components.interfaces;' + - ' self.postMessage({' + - ' isElt: node instanceof Ci.nsIDOMHTMLElement,' + - ' data: data' + - ' });' + - '});', - onMessage: function (data) { - test.assertEqual(this, item, "`this` inside onMessage should be item"); - test.assert(data.isElt, "node should be an HTML element"); - test.assertEqual(data.data, item.data, "data should be item data"); - test.done(); - } - }); - - test.showMenu(null, function (popup) { - test.checkMenu([item], [], []); - let elt = test.getItemElt(popup, item); - elt.click(); - }); -}; - - -// A menu's click listener should work and receive bubbling clicks from -// sub-items appropriately. This also tests menus and ensures that when a CSS -// selector context matches the clicked node's ancestor, the matching ancestor -// is passed to listeners as the clicked node. -exports.testMenuClick = function (test) { - // Create a top-level menu, submenu, and item, like this: - // topMenu -> submenu -> item - // Click the item and make sure the click bubbles. - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = new loader.cm.Item({ - label: "submenu item", - data: "submenu item data" - }); - - let submenu = new loader.cm.Menu({ - label: "submenu", - items: [item] - }); - - let topMenu = new loader.cm.Menu({ - label: "top menu", - contentScript: 'self.on("click", function (node, data) {' + - ' let Ci = Components.interfaces;' + - ' self.postMessage({' + - ' isAnchor: node instanceof Ci.nsIDOMHTMLAnchorElement,' + - ' data: data' + - ' });' + - '});', - onMessage: function (data) { - test.assertEqual(this, topMenu, "`this` inside top menu should be menu"); - test.assert(data.isAnchor, "Clicked node should be anchor"); - test.assertEqual(data.data, item.data, - "Clicked item data should be correct"); - test.done(); - }, - items: [submenu], - context: loader.cm.SelectorContext("a") - }); - - test.withTestDoc(function (window, doc) { - test.showMenu(doc.getElementById("span-link"), function (popup) { - test.checkMenu([topMenu], [], []); - let topMenuElt = test.getItemElt(popup, topMenu); - let topMenuPopup = topMenuElt.firstChild; - let submenuElt = test.getItemElt(topMenuPopup, submenu); - let submenuPopup = submenuElt.firstChild; - let itemElt = test.getItemElt(submenuPopup, item); - itemElt.click(); - }); - }); -}; - - -// Click listeners should work when multiple modules are loaded. -exports.testItemClickMultipleModules = function (test) { - test = new TestHelper(test); - let loader0 = test.newLoader(); - let loader1 = test.newLoader(); - - let item0 = loader0.cm.Item({ - label: "loader 0 item", - contentScript: 'self.on("click", self.postMessage);', - onMessage: function () { - test.fail("loader 0 item should not emit click event"); - } - }); - let item1 = loader1.cm.Item({ - label: "loader 1 item", - contentScript: 'self.on("click", self.postMessage);', - onMessage: function () { - test.pass("loader 1 item clicked as expected"); - test.done(); - } - }); - - test.showMenu(null, function (popup) { - test.checkMenu([item0, item1], [], []); - let item1Elt = test.getItemElt(popup, item1); - item1Elt.click(); - }); -}; - - -// Adding a separator to a submenu should work OK. -exports.testSeparator = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let menu = new loader.cm.Menu({ - label: "submenu", - items: [new loader.cm.Separator()] - }); - - test.showMenu(null, function (popup) { - test.checkMenu([menu], [], []); - test.done(); - }); -}; - - -// Existing context menu modifications should apply to new windows. -exports.testNewWindow = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = new loader.cm.Item({ label: "item" }); - - test.withNewWindow(function () { - test.showMenu(null, function (popup) { - test.checkMenu([item], [], []); - test.done(); - }); - }); -}; - - -// When a new window is opened, items added by an unloaded module should not -// be present in the menu. -exports.testNewWindowMultipleModules = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - let item = new loader.cm.Item({ label: "item" }); - - test.showMenu(null, function (popup) { - test.checkMenu([item], [], []); - popup.hidePopup(); - loader.unload(); - test.withNewWindow(function () { - test.showMenu(null, function (popup) { - test.checkMenu([], [], []); - test.done(); - }); - }); - }); -}; - - -// Items in the context menu should be sorted according to locale. -exports.testSorting = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - // Make an unsorted items list. It'll look like this: - // item 1, item 0, item 3, item 2, item 5, item 4, ... - let items = []; - for (let i = 0; i < OVERFLOW_THRESH_DEFAULT; i += 2) { - items.push(new loader.cm.Item({ label: "item " + (i + 1) })); - items.push(new loader.cm.Item({ label: "item " + i })); - } - - test.showMenu(null, function (popup) { - test.checkMenu(items, [], []); - test.done(); - }); -}; - - -// Items in the overflow menu should be sorted according to locale. -exports.testSortingOverflow = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - // Make an unsorted items list. It'll look like this: - // item 1, item 0, item 3, item 2, item 5, item 4, ... - let items = []; - for (let i = 0; i < OVERFLOW_THRESH_DEFAULT * 2; i += 2) { - items.push(new loader.cm.Item({ label: "item " + (i + 1) })); - items.push(new loader.cm.Item({ label: "item " + i })); - } - - test.showMenu(null, function (popup) { - test.checkMenu(items, [], []); - test.done(); - }); -}; - - -// Multiple modules shouldn't interfere with sorting. -exports.testSortingMultipleModules = function (test) { - test = new TestHelper(test); - let loader0 = test.newLoader(); - let loader1 = test.newLoader(); - - let items0 = []; - let items1 = []; - for (let i = 0; i < OVERFLOW_THRESH_DEFAULT; i++) { - if (i % 2) { - let item = new loader0.cm.Item({ label: "item " + i }); - items0.push(item); - } - else { - let item = new loader1.cm.Item({ label: "item " + i }); - items1.push(item); - } - } - let allItems = items0.concat(items1); - - test.showMenu(null, function (popup) { - - // All items should be present and sorted. - test.checkMenu(allItems, [], []); - popup.hidePopup(); - loader0.unload(); - loader1.unload(); - test.showMenu(null, function (popup) { - - // All items should be removed. - test.checkMenu([], [], allItems); - test.done(); - }); - }); -}; - - -// The binary search of insertionPoint should work OK. -exports.testInsertionPoint = function (test) { - function mockElts(labels) { - return labels.map(function (label) { - return { label: label, getAttribute: function (l) label }; - }); - } - - test = new TestHelper(test); - let loader = test.newLoader(); - let insertionPoint = loader.globalScope.insertionPoint; - - let ip = insertionPoint("a", []); - test.assertStrictEqual(ip, null, "Insertion point should be null"); - - ip = insertionPoint("a", mockElts(["b"])); - test.assertEqual(ip.label, "b", "Insertion point should be 'b'"); - - ip = insertionPoint("c", mockElts(["b"])); - test.assertStrictEqual(ip, null, "Insertion point should be null"); - - ip = insertionPoint("b", mockElts(["a", "c"])); - test.assertEqual(ip.label, "c", "Insertion point should be 'c'"); - - ip = insertionPoint("c", mockElts(["a", "b", "d"])); - test.assertEqual(ip.label, "d", "Insertion point should be 'd'"); - - ip = insertionPoint("a", mockElts(["b", "c", "d"])); - test.assertEqual(ip.label, "b", "Insertion point should be 'b'"); - - ip = insertionPoint("d", mockElts(["a", "b", "c"])); - test.assertStrictEqual(ip, null, "Insertion point should be null"); - - test.done(); -}; - - -// Content click handlers and context handlers should be able to communicate, -// i.e., they're eval'ed in the same worker and sandbox. -exports.testContentCommunication = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = new loader.cm.Item({ - label: "item", - contentScript: 'var potato;' + - 'self.on("context", function () {' + - ' potato = "potato";' + - ' return true;' + - '});' + - 'self.on("click", function () {' + - ' self.postMessage(potato);' + - '});', - }); - - item.on("message", function (data) { - test.assertEqual(data, "potato", "That's a lot of potatoes!"); - test.done(); - }); - - test.showMenu(null, function (popup) { - test.checkMenu([item], [], []); - let elt = test.getItemElt(popup, item); - elt.click(); - }); -}; - - -// When the context menu is invoked on a tab that was already open when the -// module was loaded, it should contain the expected items and content workers -// should function as expected. -exports.testLoadWithOpenTab = function (test) { - test = new TestHelper(test); - test.withTestDoc(function (window, doc) { - let loader = test.newLoader(); - let item = new loader.cm.Item({ - label: "item", - contentScript: - 'self.on("click", function () self.postMessage("click"));', - onMessage: function (msg) { - if (msg === "click") - test.done(); - } - }); - test.showMenu(null, function (popup) { - test.checkMenu([item], [], []); - test.getItemElt(popup, item).click(); - }); - }); -}; - - -// Setting an item's label before the menu is ever shown should correctly change -// its label and, if necessary, its order within the menu. -exports.testSetLabelBeforeShow = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let items = [ - new loader.cm.Item({ label: "a" }), - new loader.cm.Item({ label: "b" }) - ] - items[0].label = "z"; - test.assertEqual(items[0].label, "z"); - - test.showMenu(null, function (popup) { - test.checkMenu([items[1], items[0]], [], []); - test.done(); - }); -}; - - -// Setting an item's label after the menu is shown should correctly change its -// label and, if necessary, its order within the menu. -exports.testSetLabelAfterShow = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let items = [ - new loader.cm.Item({ label: "a" }), - new loader.cm.Item({ label: "b" }) - ]; - - test.showMenu(null, function (popup) { - test.checkMenu(items, [], []); - popup.hidePopup(); - - items[0].label = "z"; - test.assertEqual(items[0].label, "z"); - test.showMenu(null, function (popup) { - test.checkMenu([items[1], items[0]], [], []); - test.done(); - }); - }); -}; - - -// Setting an item's label before the menu is ever shown should correctly change -// its label and, if necessary, its order within the menu if the item is in the -// overflow submenu. -exports.testSetLabelBeforeShowOverflow = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let prefs = loader.loader.require("preferences-service"); - prefs.set(OVERFLOW_THRESH_PREF, 0); - - let items = [ - new loader.cm.Item({ label: "a" }), - new loader.cm.Item({ label: "b" }) - ] - items[0].label = "z"; - test.assertEqual(items[0].label, "z"); - - test.showMenu(null, function (popup) { - test.checkMenu([items[1], items[0]], [], []); - prefs.set(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT); - test.done(); - }); -}; - - -// Setting an item's label after the menu is shown should correctly change its -// label and, if necessary, its order within the menu if the item is in the -// overflow submenu. -exports.testSetLabelAfterShowOverflow = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let prefs = loader.loader.require("preferences-service"); - prefs.set(OVERFLOW_THRESH_PREF, 0); - - let items = [ - new loader.cm.Item({ label: "a" }), - new loader.cm.Item({ label: "b" }) - ]; - - test.showMenu(null, function (popup) { - test.checkMenu(items, [], []); - popup.hidePopup(); - - items[0].label = "z"; - test.assertEqual(items[0].label, "z"); - test.showMenu(null, function (popup) { - test.checkMenu([items[1], items[0]], [], []); - prefs.set(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT); - test.done(); - }); - }); -}; - - -// Setting the label of an item in a Menu should work. -exports.testSetLabelMenuItem = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let menu = loader.cm.Menu({ - label: "menu", - items: [loader.cm.Item({ label: "a" })] - }); - menu.items[0].label = "z"; - - test.assertEqual(menu.items[0].label, "z"); - - test.showMenu(null, function (popup) { - test.checkMenu([menu], [], []); - test.done(); - }); -}; - - -// Menu.addItem() should work. -exports.testMenuAddItem = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let menu = loader.cm.Menu({ - label: "menu", - items: [ - loader.cm.Item({ label: "item 0" }) - ] - }); - menu.addItem(loader.cm.Item({ label: "item 1" })); - menu.addItem(loader.cm.Item({ label: "item 2" })); - - test.assertEqual(menu.items.length, 3, - "menu should have correct number of items"); - for (let i = 0; i < 3; i++) { - test.assertEqual(menu.items[i].label, "item " + i, - "item label should be correct"); - test.assertEqual(menu.items[i].parentMenu, menu, - "item's parent menu should be correct"); - } - - test.showMenu(null, function (popup) { - test.checkMenu([menu], [], []); - test.done(); - }); -}; - - -// Adding the same item twice to a menu should work as expected. -exports.testMenuAddItemTwice = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let menu = loader.cm.Menu({ - label: "menu", - items: [] - }); - let subitem = loader.cm.Item({ label: "item 1" }) - menu.addItem(subitem); - menu.addItem(loader.cm.Item({ label: "item 0" })); - menu.addItem(subitem); - - test.assertEqual(menu.items.length, 2, - "menu should have correct number of items"); - for (let i = 0; i < 2; i++) { - test.assertEqual(menu.items[i].label, "item " + i, - "item label should be correct"); - } - - test.showMenu(null, function (popup) { - test.checkMenu([menu], [], []); - test.done(); - }); -}; - - -// Menu.removeItem() should work. -exports.testMenuRemoveItem = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let subitem = loader.cm.Item({ label: "item 1" }); - let menu = loader.cm.Menu({ - label: "menu", - items: [ - loader.cm.Item({ label: "item 0" }), - subitem, - loader.cm.Item({ label: "item 2" }) - ] - }); - - // Removing twice should be harmless. - menu.removeItem(subitem); - menu.removeItem(subitem); - - test.assertEqual(subitem.parentMenu, null, - "item's parent menu should be correct"); - - test.assertEqual(menu.items.length, 2, - "menu should have correct number of items"); - test.assertEqual(menu.items[0].label, "item 0", - "item label should be correct"); - test.assertEqual(menu.items[1].label, "item 2", - "item label should be correct"); - - test.showMenu(null, function (popup) { - test.checkMenu([menu], [], []); - test.done(); - }); -}; - - -// Adding an item currently contained in one menu to another menu should work. -exports.testMenuItemSwap = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let subitem = loader.cm.Item({ label: "item" }); - let menu0 = loader.cm.Menu({ - label: "menu 0", - items: [subitem] - }); - let menu1 = loader.cm.Menu({ - label: "menu 1", - items: [] - }); - menu1.addItem(subitem); - - test.assertEqual(menu0.items.length, 0, - "menu should have correct number of items"); - - test.assertEqual(menu1.items.length, 1, - "menu should have correct number of items"); - test.assertEqual(menu1.items[0].label, "item", - "item label should be correct"); - - test.assertEqual(subitem.parentMenu, menu1, - "item's parent menu should be correct"); - - test.showMenu(null, function (popup) { - test.checkMenu([menu0, menu1], [], []); - test.done(); - }); -}; - - -// Destroying an item should remove it from its parent menu. -exports.testMenuItemDestroy = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let subitem = loader.cm.Item({ label: "item" }); - let menu = loader.cm.Menu({ - label: "menu", - items: [subitem] - }); - subitem.destroy(); - - test.assertEqual(menu.items.length, 0, - "menu should have correct number of items"); - test.assertEqual(subitem.parentMenu, null, - "item's parent menu should be correct"); - - test.showMenu(null, function (popup) { - test.checkMenu([menu], [], []); - test.done(); - }); -}; - - -// Setting Menu.items should work. -exports.testMenuItemsSetter = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let menu = loader.cm.Menu({ - label: "menu", - items: [ - loader.cm.Item({ label: "old item 0" }), - loader.cm.Item({ label: "old item 1" }) - ] - }); - menu.items = [ - loader.cm.Item({ label: "new item 0" }), - loader.cm.Item({ label: "new item 1" }), - loader.cm.Item({ label: "new item 2" }) - ]; - - test.assertEqual(menu.items.length, 3, - "menu should have correct number of items"); - for (let i = 0; i < 3; i++) { - test.assertEqual(menu.items[i].label, "new item " + i, - "item label should be correct"); - test.assertEqual(menu.items[i].parentMenu, menu, - "item's parent menu should be correct"); - } - - test.showMenu(null, function (popup) { - test.checkMenu([menu], [], []); - test.done(); - }); -}; - - -// Setting Item.data should work. -exports.testItemDataSetter = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let item = loader.cm.Item({ label: "old item 0", data: "old" }); - item.data = "new"; - - test.assertEqual(item.data, "new", "item should have correct data"); - - test.showMenu(null, function (popup) { - test.checkMenu([item], [], []); - test.done(); - }); -}; - - -// Open the test doc, load the module, make sure items appear when context- -// clicking the iframe. -exports.testAlreadyOpenIframe = function (test) { - test = new TestHelper(test); - test.withTestDoc(function (window, doc) { - let loader = test.newLoader(); - let item = new loader.cm.Item({ - label: "item" - }); - test.showMenu(doc.getElementById("iframe"), function (popup) { - test.checkMenu([item], [], []); - test.done(); - }); - }); -}; - - -// Test image support. -exports.testItemImage = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let imageURL = require("self").data.url("moz_favicon.ico"); - let item = new loader.cm.Item({ label: "item", image: imageURL }); - let menu = new loader.cm.Menu({ label: "menu", image: imageURL, items: [] }); - - test.showMenu(null, function (popup) { - test.checkMenu([item, menu], [], []); - - let imageURL2 = require("self").data.url("dummy.ico"); - item.image = imageURL2; - menu.image = imageURL2; - test.checkMenu([item, menu], [], []); - - item.image = null; - menu.image = null; - test.checkMenu([item, menu], [], []); - - test.done(); - }); -}; - - -// Menu.destroy should destroy the item tree rooted at that menu. -exports.testMenuDestroy = function (test) { - test = new TestHelper(test); - let loader = test.newLoader(); - - let menu = loader.cm.Menu({ - label: "menu", - items: [ - loader.cm.Item({ label: "item 0" }), - loader.cm.Menu({ - label: "item 1", - items: [ - loader.cm.Item({ label: "subitem 0" }), - loader.cm.Item({ label: "subitem 1" }), - loader.cm.Item({ label: "subitem 2" }) - ] - }), - loader.cm.Item({ label: "item 2" }) - ] - }); - menu.destroy(); - - let numRegistryEntries = 0; - loader.globalScope.browserManager.browserWins.forEach(function (bwin) { - for (let itemID in bwin.items) - numRegistryEntries++; - }); - test.assertEqual(numRegistryEntries, 0, "All items should be unregistered."); - - test.showMenu(null, function (popup) { - test.checkMenu([], [], [menu]); - test.done(); - }); -}; - - -// NO TESTS BELOW THIS LINE! /////////////////////////////////////////////////// - -// Run only a dummy test if context-menu doesn't support the host app. -if (!require("xul-app").is("Firefox")) { - for (let [prop, val] in Iterator(exports)) - if (/^test/.test(prop) && typeof(val) === "function") - delete exports[prop]; - exports.testAppNotSupported = function (test) { - test.pass("context-menu does not support this application."); - }; -} - - -// This makes it easier to run tests by handling things like opening the menu, -// opening new windows, making assertions, etc. Methods on |test| can be called -// on instances of this class. Don't forget to call done() to end the test! -// WARNING: This looks up items in popups by comparing labels, so don't give two -// items the same label. -function TestHelper(test) { - // default waitUntilDone timeout is 10s, which is too short on the win7 - // buildslave - test.waitUntilDone(30*1000); - this.test = test; - this.loaders = []; - this.browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]. - getService(Ci.nsIWindowMediator). - getMostRecentWindow("navigator:browser"); -} - -TestHelper.prototype = { - get contextMenuPopup() { - return this.browserWindow.document.getElementById("contentAreaContextMenu"); - }, - - get contextMenuSeparator() { - return this.browserWindow.document.getElementById(SEPARATOR_ID); - }, - - get overflowPopup() { - return this.browserWindow.document.getElementById(OVERFLOW_POPUP_ID); - }, - - get overflowSubmenu() { - return this.browserWindow.document.getElementById(OVERFLOW_MENU_ID); - }, - - get tabBrowser() { - return this.browserWindow.gBrowser; - }, - - // Methods on the wrapped test can be called on this object. - __noSuchMethod__: function (methodName, args) { - this.test[methodName].apply(this.test, args); - }, - - // Asserts that absentItems -- an array of items that should not match the - // current context -- aren't present in the menu. - checkAbsentItems: function (presentItems, absentItems) { - for (let i = 0; i < absentItems.length; i++) { - let item = absentItems[i]; - let elt = this.getItemElt(this.contextMenuPopup, item); - - // The implementation actually hides items rather than removing or not - // adding them in the first place, but that's an implementation detail. - this.test.assert(!elt || elt.hidden, - "Item should not be present in top-level menu"); - - if (this.shouldOverflow(presentItems)) { - elt = getItemElt(this.overflowPopup, item); - this.test.assert(!elt || elt.hidden, - "Item should not be present in overflow submenu"); - } - } - }, - - // Asserts that elt, a DOM element representing item, looks OK. - checkItemElt: function (elt, item) { - let itemType = this.getItemType(item); - - switch (itemType) { - case "Item": - this.test.assertEqual(elt.localName, "menuitem", - "Item DOM element should be a xul:menuitem"); - if (typeof(item.data) === "string") { - this.test.assertEqual(elt.getAttribute("value"), item.data, - "Item should have correct data"); - } - break - case "Menu": - this.test.assertEqual(elt.localName, "menu", - "Menu DOM element should be a xul:menu"); - let subPopup = elt.firstChild; - this.test.assert(subPopup, "xul:menu should have a child"); - this.test.assertEqual(subPopup.localName, "menupopup", - "xul:menu's first child should be a menupopup"); - break; - case "Separator": - this.test.assertEqual(elt.localName, "menuseparator", - "Separator DOM element should be a xul:menuseparator"); - break; - } - - if (itemType === "Item" || itemType === "Menu") { - this.test.assertEqual(elt.getAttribute("label"), item.label, - "Item should have correct title"); - if (typeof(item.image) === "string") - this.test.assertEqual(elt.getAttribute("image"), item.image, - "Item should have correct image"); - else - this.test.assert(!elt.hasAttribute("image"), - "Item should not have image"); - } - }, - - // Asserts that the context menu looks OK given the arguments. presentItems - // are items that should match the current context. absentItems are items - // that shouldn't. removedItems are items that have been removed from the - // menu. - checkMenu: function (presentItems, absentItems, removedItems) { - this.checkSeparator(presentItems); - this.checkOverflow(presentItems); - this.checkPresentItems(presentItems); - this.checkAbsentItems(presentItems, absentItems); - this.checkRemovedItems(removedItems); - this.checkSort(presentItems); - }, - - // Asserts that the overflow submenu is present or absent as appropriate for - // presentItems. - checkOverflow: function (presentItems) { - let submenu = this.overflowSubmenu; - if (this.shouldOverflow(presentItems)) { - this.test.assert(submenu && !submenu.hidden, - "Overflow submenu should be present"); - this.test.assert(submenu.localName, "menu", - "Overflow submenu should be a <menu>"); - let overflowPopup = this.overflowPopup; - this.test.assert(overflowPopup, - "Overflow submenu popup should be present"); - this.test.assert(overflowPopup.localName, "menupopup", - "Overflow submenu popup should be a <menupopup>"); - } - else { - this.test.assert(!submenu || submenu.hidden, - "Overflow submenu should be absent"); - } - }, - - // Asserts that the items that are present in the menu because they match the - // current context look OK. - checkPresentItems: function (presentItems) { - function recurse(popup, items, isTopLevel) { - items.forEach(function (item) { - let elt = this.getItemElt(popup, item); - - if (isTopLevel) { - if (this.shouldOverflow(items)) { - this.test.assert(!elt || elt.hidden, - "Item should not be present in top-level menu"); - - let overflowPopup = this.overflowPopup; - this.test.assert(overflowPopup, - "Overflow submenu should be present"); - - elt = this.getItemElt(overflowPopup, item); - this.test.assert(elt && !elt.hidden, - "Item should be present in overflow submenu"); - } - else { - this.test.assert(elt && !elt.hidden, - "Item should be present in top-level menu"); - } - } - else { - this.test.assert(elt && !elt.hidden, - "Item should be present in menu"); - } - - this.checkItemElt(elt, item); - if (this.getItemType(item) === "Menu") - recurse.call(this, elt.firstChild, item.items, false); - }, this); - } - - recurse.call(this, this.contextMenuPopup, presentItems, true); - }, - - // Asserts that items that have been removed from the menu are really removed. - checkRemovedItems: function (removedItems) { - for (let i = 0; i < removedItems.length; i++) { - let item = removedItems[i]; - - let elt = this.getItemElt(this.contextMenuPopup, item); - this.test.assert(!elt, "Item should be removed from top-level menu"); - - let overflowPopup = this.overflowPopup; - if (overflowPopup) { - elt = this.getItemElt(overflowPopup, item); - this.test.assert(!elt, "Item should be removed from overflow submenu"); - } - } - }, - - // Asserts that the menu separator separating standard items from our items - // looks OK. - checkSeparator: function (presentItems) { - let sep = this.contextMenuSeparator; - if (presentItems.length) { - this.test.assert(sep && !sep.hidden, "Menu separator should be present"); - this.test.assertEqual(sep.localName, "menuseparator", - "Menu separator should be a <menuseparator>"); - } - else { - this.test.assert(!sep || sep.hidden, "Menu separator should be absent"); - } - }, - - // Asserts that our items are sorted. - checkSort: function (presentItems) { - // Get the first item in sorted order, get its elt, walk the nextSibling - // chain, making sure each is greater than the previous. - if (presentItems.length) { - let sorted = presentItems.slice(0). - sort(function (a, b) a.label.localeCompare(b.label)); - let elt = this.shouldOverflow(presentItems) ? - this.getItemElt(this.overflowPopup, sorted[0]) : - this.getItemElt(this.contextMenuPopup, sorted[0]); - let numElts = 1; - while (elt.nextSibling && - elt.nextSibling.className.split(/\s+/).indexOf(ITEM_CLASS) >= 0) { - let eltLabel = elt.getAttribute("label"); - let nextLabel = elt.nextSibling.getAttribute("label"); - this.test.assert(eltLabel.localeCompare(nextLabel) < 0, - "Item label should be < next item's label"); - elt = elt.nextSibling; - numElts++; - } - this.test.assertEqual(numElts, presentItems.length, - "The first item in sorted order should have the " + - "first element in sorted order"); - } - }, - - // Attaches an event listener to node. The listener is automatically removed - // when it's fired (so it's assumed it will fire), and callback is called - // after a short delay. Since the module we're testing relies on the same - // event listeners to do its work, this is to give them a little breathing - // room before callback runs. Inside callback |this| is this object. - delayedEventListener: function (node, event, callback, useCapture) { - const self = this; - node.addEventListener(event, function handler(evt) { - node.removeEventListener(event, handler, useCapture); - require("timer").setTimeout(function () { - try { - callback.call(self, evt); - } - catch (err) { - self.test.exception(err); - self.test.done(); - } - }, 20); - }, useCapture); - }, - - // Call to finish the test. - done: function () { - function commonDone() { - if (this.tab) { - this.tabBrowser.removeTab(this.tab); - this.tabBrowser.selectedTab = this.oldSelectedTab; - } - while (this.loaders.length) { - let browserManager = this.loaders[0].globalScope.browserManager; - let topLevelItems = browserManager.topLevelItems.slice(); - let privatePropsKey = this.loaders[0].globalScope.PRIVATE_PROPS_KEY; - let workerRegs = topLevelItems.map(function (item) { - return item.valueOf(privatePropsKey)._workerReg; - }); - - this.loaders[0].unload(); - - // Make sure the browser manager is cleaned up. - this.test.assertEqual(browserManager.browserWins.length, 0, - "browserManager should have no windows left"); - this.test.assertEqual(browserManager.topLevelItems.length, 0, - "browserManager should have no items left"); - this.test.assert(!("contentWins" in browserManager), - "browserManager should have no content windows left"); - - // Make sure the items' worker registries are cleaned up. - topLevelItems.forEach(function (item) { - this.test.assert(!("_workerReg" in item.valueOf(privatePropsKey)), - "item's worker registry should be removed"); - }, this); - workerRegs.forEach(function (workerReg) { - this.test.assertEqual(Object.keys(workerReg.winWorkers).length, 0, - "worker registry should be empty"); - this.test.assertEqual( - Object.keys(workerReg.winsWithoutWorkers).length, 0, - "worker registry list of windows without workers should be empty"); - }, this); - } - this.test.done(); - } - - function closeBrowserWindow() { - if (this.oldBrowserWindow) { - this.delayedEventListener(this.browserWindow, "unload", commonDone, - false); - this.browserWindow.close(); - this.browserWindow = this.oldBrowserWindow; - delete this.oldBrowserWindow; - } - else { - commonDone.call(this); - } - }; - - if (this.contextMenuPopup.state == "closed") { - closeBrowserWindow.call(this); - } - else { - this.delayedEventListener(this.contextMenuPopup, "popuphidden", - function () closeBrowserWindow.call(this), - false); - this.contextMenuPopup.hidePopup(); - } - }, - - // Returns the DOM element in popup corresponding to item. - // WARNING: The element is found by comparing labels, so don't give two items - // the same label. - getItemElt: function (popup, item) { - let nodes = popup.childNodes; - for (let i = nodes.length - 1; i >= 0; i--) { - if (this.getItemType(item) === "Separator") { - if (nodes[i].localName === "menuseparator") - return nodes[i]; - } - else if (nodes[i].getAttribute("label") === item.label) - return nodes[i]; - } - return null; - }, - - // Returns "Item", "Menu", or "Separator". - getItemType: function (item) { - // Could use instanceof here, but that would require accessing the loader - // that created the item, and I don't want to A) somehow search through the - // this.loaders list to find it, and B) assume there are any live loaders at - // all. - return /^\[object (Item|Menu|Separator)/.exec(item.toString())[1]; - }, - - // Returns a wrapper around a new loader: { loader, cm, unload, globalScope }. - // loader is a Cuddlefish sandboxed loader, cm is the context menu module, - // globalScope is the context menu module's global scope, and unload is a - // function that unloads the loader and associated resources. - newLoader: function () { - const self = this; - let loader = Loader(module); - let wrapper = { - loader: loader, - cm: loader.require("context-menu"), - globalScope: loader.sandbox("context-menu"), - unload: function () { - loader.unload(); - let idx = self.loaders.indexOf(wrapper); - if (idx < 0) - throw new Error("Test error: tried to unload nonexistent loader"); - self.loaders.splice(idx, 1); - } - }; - this.loaders.push(wrapper); - return wrapper; - }, - - // Returns true if the number of presentItems crosses the overflow threshold. - shouldOverflow: function (presentItems) { - return presentItems.length > - (this.loaders.length ? - this.loaders[0].loader.require("preferences-service"). - get(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT) : - OVERFLOW_THRESH_DEFAULT); - }, - - // Opens the context menu on the current page. If targetNode is null, the - // menu is opened in the top-left corner. onShowncallback is passed the - // popup. - showMenu: function(targetNode, onshownCallback) { - function sendEvent() { - this.delayedEventListener(this.browserWindow, "popupshowing", - function (e) { - let popup = e.target; - onshownCallback.call(this, popup); - }, false); - - let rect = targetNode ? - targetNode.getBoundingClientRect() : - { left: 0, top: 0, width: 0, height: 0 }; - let contentWin = this.browserWindow.content; - contentWin. - QueryInterface(Ci.nsIInterfaceRequestor). - getInterface(Ci.nsIDOMWindowUtils). - sendMouseEvent("contextmenu", - rect.left + (rect.width / 2), - rect.top + (rect.height / 2), - 2, 1, 0); - } - - // If a new tab or window has not yet been opened, open a new tab now. For - // some reason using the tab already opened when the test starts causes - // leaks. See bug 566351 for details. - if (!targetNode && !this.oldSelectedTab && !this.oldBrowserWindow) { - this.oldSelectedTab = this.tabBrowser.selectedTab; - this.tab = this.tabBrowser.addTab("about:blank"); - let browser = this.tabBrowser.getBrowserForTab(this.tab); - - this.delayedEventListener(browser, "load", function () { - this.tabBrowser.selectedTab = this.tab; - sendEvent.call(this); - }, true); - } - else - sendEvent.call(this); - }, - - // Opens a new browser window. The window will be closed automatically when - // done() is called. - withNewWindow: function (onloadCallback) { - let win = this.browserWindow.OpenBrowserWindow(); - this.delayedEventListener(win, "load", onloadCallback, true); - this.oldBrowserWindow = this.browserWindow; - this.browserWindow = win; - }, - - // Opens a new tab with our test page in the current window. The tab will - // be closed automatically when done() is called. - withTestDoc: function (onloadCallback) { - this.oldSelectedTab = this.tabBrowser.selectedTab; - this.tab = this.tabBrowser.addTab(TEST_DOC_URL); - let browser = this.tabBrowser.getBrowserForTab(this.tab); - - this.delayedEventListener(browser, "load", function () { - this.tabBrowser.selectedTab = this.tab; - onloadCallback.call(this, browser.contentWindow, browser.contentDocument); - }, true); - } -}; diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-hotkeys.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-hotkeys.js deleted file mode 100644 index 3b69a28..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-hotkeys.js +++ /dev/null @@ -1,156 +0,0 @@ -"use strict"; - -const { Hotkey } = require("hotkeys"); -const { keyDown } = require("dom/events/keys"); -const { Loader } = require('./helpers'); - -exports["test hotkey: function key"] = function(assert, done) { - var element = require("window-utils").activeBrowserWindow.document.documentElement; - var showHotKey = Hotkey({ - combo: "f1", - onPress: function() { - assert.pass("first callback is called"); - keyDown(element, "f2"); - showHotKey.destroy(); - } - }); - - var hideHotKey = Hotkey({ - combo: "f2", - onPress: function() { - assert.pass("second callback is called"); - hideHotKey.destroy(); - done(); - } - }); - - keyDown(element, "f1"); -}; - -exports["test hotkey: accel alt shift"] = function(assert, done) { - var element = require("window-utils").activeBrowserWindow.document.documentElement; - var showHotKey = Hotkey({ - combo: "accel-shift-6", - onPress: function() { - assert.pass("first callback is called"); - keyDown(element, "accel-alt-shift-6"); - showHotKey.destroy(); - } - }); - - var hideHotKey = Hotkey({ - combo: "accel-alt-shift-6", - onPress: function() { - assert.pass("second callback is called"); - hideHotKey.destroy(); - done(); - } - }); - - keyDown(element, "accel-shift-6"); -}; - -exports["test hotkey meta & control"] = function(assert, done) { - var element = require("window-utils").activeBrowserWindow.document.documentElement; - var showHotKey = Hotkey({ - combo: "meta-3", - onPress: function() { - assert.pass("first callback is called"); - keyDown(element, "alt-control-shift-b"); - showHotKey.destroy(); - } - }); - - var hideHotKey = Hotkey({ - combo: "Ctrl-Alt-Shift-B", - onPress: function() { - assert.pass("second callback is called"); - hideHotKey.destroy(); - done(); - } - }); - - keyDown(element, "meta-3"); -}; - -exports["test hotkey: control-1 / meta--"] = function(assert, done) { - var element = require("window-utils").activeBrowserWindow.document.documentElement; - var showHotKey = Hotkey({ - combo: "control-1", - onPress: function() { - assert.pass("first callback is called"); - keyDown(element, "meta--"); - showHotKey.destroy(); - } - }); - - var hideHotKey = Hotkey({ - combo: "meta--", - onPress: function() { - assert.pass("second callback is called"); - hideHotKey.destroy(); - done(); - } - }); - - keyDown(element, "control-1"); -}; - -exports["test invalid combos"] = function(assert) { - assert.throws(function() { - Hotkey({ - combo: "d", - onPress: function() {} - }); - }, "throws if no modifier is present"); - assert.throws(function() { - Hotkey({ - combo: "alt", - onPress: function() {} - }); - }, "throws if no key is present"); - assert.throws(function() { - Hotkey({ - combo: "alt p b", - onPress: function() {} - }); - }, "throws if more then one key is present"); -}; - -exports["test no exception on unmodified keypress"] = function(assert) { - var element = require("window-utils").activeBrowserWindow.document.documentElement; - var someHotkey = Hotkey({ - combo: "control-alt-1", - onPress: function() { - } - }); - keyDown(element, "a"); - assert.pass("No exception throw, unmodified keypress passed"); -}; - -exports["test hotkey: automatic destroy"] = function(assert, done) { - // Hacky way to be able to create unloadable modules via makeSandboxedLoader. - let loader = Loader(module); - - var called = false; - var element = loader.require("window-utils").activeBrowserWindow.document.documentElement; - var hotkey = loader.require("hotkeys").Hotkey({ - combo: "accel-shift-x", - onPress: function() { - called = true; - } - }); - - // Unload the module so that previous hotkey is automatically destroyed - loader.unload(); - - // Ensure that the hotkey is really destroyed - keyDown(element, "accel-shift-x"); - - require("timer").setTimeout(function () { - assert.ok(!called, "Hotkey is destroyed and not called."); - done(); - }, 0); -}; - -require("test").run(exports); diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-module.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-module.js deleted file mode 100644 index c62f923..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-module.js +++ /dev/null @@ -1,33 +0,0 @@ -"use strict"; - -/** Disabled because of Bug 672199 -exports["test module exports are frozen"] = function(assert) { - assert.ok(Object.isFrozen(require("addon-kit/hotkeys")), - "module exports are frozen"); -}; - -exports["test redefine exported property"] = function(assert) { - let hotkeys = require("addon-kit/hotkeys"); - let { Hotkey } = hotkeys; - try { Object.defineProperty(hotkeys, 'Hotkey', { value: {} }); } catch(e) {} - assert.equal(hotkeys.Hotkey, Hotkey, "exports can't be redefined"); -}; -*/ - -exports["test can't delete exported property"] = function(assert) { - let hotkeys = require("addon-kit/hotkeys"); - let { Hotkey } = hotkeys; - - try { delete hotkeys.Hotkey; } catch(e) {} - assert.equal(hotkeys.Hotkey, Hotkey, "exports can't be deleted"); -}; - -exports["test can't override exported property"] = function(assert) { - let hotkeys = require("addon-kit/hotkeys"); - let { Hotkey } = hotkeys; - - try { hotkeys.Hotkey = Object } catch(e) {} - assert.equal(hotkeys.Hotkey, Hotkey, "exports can't be overriden"); -}; - -require("test").run(exports); diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-notifications.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-notifications.js deleted file mode 100644 index 1eb6190..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-notifications.js +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim:set ts=2 sw=2 sts=2 et filetype=javascript - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Drew Willcoxon <adw@mozilla.com> (Original Author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -const { Loader } = require('./helpers'); - -exports.testOnClick = function (test) { - let [loader, mockAlertServ] = makeLoader(module); - let notifs = loader.require("notifications"); - let data = "test data"; - let opts = { - onClick: function (clickedData) { - test.assertEqual(this, notifs, "|this| should be notifications module"); - test.assertEqual(clickedData, data, - "data passed to onClick should be correct"); - }, - data: data, - title: "test title", - text: "test text", - iconURL: "test icon URL" - }; - notifs.notify(opts); - mockAlertServ.click(); - loader.unload(); -}; - -// Returns [loader, mockAlertService]. -function makeLoader(test) { - let loader = Loader(module); - let mockAlertServ = { - showAlertNotification: function (imageUrl, title, text, textClickable, - cookie, alertListener, name) { - this._cookie = cookie; - this._alertListener = alertListener; - }, - click: function () { - this._alertListener.observe(null, "alertclickcallback", this._cookie); - } - }; - loader.require("notifications"); - let scope = loader.sandbox("notifications"); - scope.notify = mockAlertServ.showAlertNotification.bind(mockAlertServ); - return [loader, mockAlertServ]; -}; diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-page-mod.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-page-mod.js deleted file mode 100644 index 2b38946..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-page-mod.js +++ /dev/null @@ -1,416 +0,0 @@ -"use strict"; - -var pageMod = require("page-mod"); -var testPageMod = require("pagemod-test-helpers").testPageMod; -const { Loader } = require('./helpers'); -const tabs = require("tabs"); - -/* XXX This can be used to delay closing the test Firefox instance for interactive - * testing or visual inspection. This test is registered first so that it runs - * the last. */ -exports.delay = function(test) { - if (false) { - test.waitUntilDone(60000); - require("timer").setTimeout(function() {test.done();}, 4000); - } else - test.pass(); -} - -/* Tests for the PageMod APIs */ - -exports.testPageMod1 = function(test) { - let mods = testPageMod(test, "about:", [{ - include: /about:/, - contentScriptWhen: 'end', - contentScript: 'new ' + function WorkerScope() { - window.document.body.setAttribute("JEP-107", "worked"); - }, - onAttach: function() { - test.assertEqual(this, mods[0], "The 'this' object is the page mod."); - } - }], - function(win, done) { - test.assertEqual( - win.document.body.getAttribute("JEP-107"), - "worked", - "PageMod.onReady test" - ); - done(); - } - ); -}; - -exports.testPageMod2 = function(test) { - testPageMod(test, "about:", [{ - include: "about:*", - contentScript: [ - 'new ' + function contentScript() { - window.AUQLUE = function() { return 42; } - try { - window.AUQLUE() - } - catch(e) { - throw new Error("PageMod scripts executed in order"); - } - document.documentElement.setAttribute("first", "true"); - }, - 'new ' + function contentScript() { - document.documentElement.setAttribute("second", "true"); - } - ] - }], function(win, done) { - test.assertEqual(win.document.documentElement.getAttribute("first"), - "true", - "PageMod test #2: first script has run"); - test.assertEqual(win.document.documentElement.getAttribute("second"), - "true", - "PageMod test #2: second script has run"); - test.assertEqual("AUQLUE" in win, false, - "PageMod test #2: scripts get a wrapped window"); - done(); - }); -}; - -exports.testPageModIncludes = function(test) { - var asserts = []; - function createPageModTest(include, expectedMatch) { - // Create an 'onload' test function... - asserts.push(function(test, win) { - var matches = include in win.localStorage; - test.assert(expectedMatch ? matches : !matches, - "'" + include + "' match test, expected: " + expectedMatch); - }); - // ...and corresponding PageMod options - return { - include: include, - contentScript: 'new ' + function() { - self.on("message", function(msg) { - window.localStorage[msg] = true; - }); - }, - // The testPageMod callback with test assertions is called on 'end', - // and we want this page mod to be attached before it gets called, - // so we attach it on 'start'. - contentScriptWhen: 'start', - onAttach: function(worker) { - worker.postMessage(this.include[0]); - } - }; - } - - testPageMod(test, "about:buildconfig", [ - createPageModTest("*", false), - createPageModTest("*.google.com", false), - createPageModTest("about:*", true), - createPageModTest("about:", false), - createPageModTest("about:buildconfig", true) - ], - function (win, done) { - test.waitUntil(function () win.localStorage["about:buildconfig"], - "about:buildconfig page-mod to be executed") - .then(function () { - asserts.forEach(function(fn) { - fn(test, win); - }); - done(); - }); - } - ); -}; - -exports.testPageModErrorHandling = function(test) { - test.assertRaises(function() { - new pageMod.PageMod(); - }, - 'pattern is undefined', - "PageMod() throws when 'include' option is not specified."); -}; - -/* Tests for internal functions. */ -exports.testCommunication1 = function(test) { - let workerDone = false, - callbackDone = null; - - testPageMod(test, "about:", [{ - include: "about:*", - contentScriptWhen: 'end', - contentScript: 'new ' + function WorkerScope() { - self.on('message', function(msg) { - document.body.setAttribute('JEP-107', 'worked'); - self.postMessage(document.body.getAttribute('JEP-107')); - }) - }, - onAttach: function(worker) { - worker.on('error', function(e) { - test.fail('Errors where reported'); - }); - worker.on('message', function(value) { - test.assertEqual( - "worked", - value, - "test comunication" - ); - workerDone = true; - if (callbackDone) - callbackDone(); - }); - worker.postMessage('do it!') - } - }], - function(win, done) { - (callbackDone = function() { - if (workerDone) { - test.assertEqual( - 'worked', - win.document.body.getAttribute('JEP-107'), - 'attribute should be modified' - ); - done(); - } - })(); - } - ); -}; - -exports.testCommunication2 = function(test) { - let callbackDone = null, - window; - - testPageMod(test, "about:", [{ - include: "about:*", - contentScriptWhen: 'start', - contentScript: 'new ' + function WorkerScope() { - document.documentElement.setAttribute('AUQLUE', 42); - window.addEventListener('load', function listener() { - self.postMessage('onload'); - }, false); - self.on("message", function() { - self.postMessage(document.documentElement.getAttribute("test")) - }); - }, - onAttach: function(worker) { - worker.on('error', function(e) { - test.fail('Errors where reported'); - }); - worker.on('message', function(msg) { - if ('onload' == msg) { - test.assertEqual( - '42', - window.document.documentElement.getAttribute('AUQLUE'), - 'PageMod scripts executed in order' - ); - window.document.documentElement.setAttribute('test', 'changes in window'); - worker.postMessage('get window.test') - } else { - test.assertEqual( - 'changes in window', - msg, - 'PageMod test #2: second script has run' - ) - callbackDone(); - } - }); - } - }], - function(win, done) { - window = win; - callbackDone = done; - } - ); -}; - -exports.testEventEmitter = function(test) { - let workerDone = false, - callbackDone = null; - - testPageMod(test, "about:", [{ - include: "about:*", - contentScript: 'new ' + function WorkerScope() { - self.port.on('addon-to-content', function(data) { - self.port.emit('content-to-addon', data); - }); - }, - onAttach: function(worker) { - worker.on('error', function(e) { - test.fail('Errors were reported : '+e); - }); - worker.port.on('content-to-addon', function(value) { - test.assertEqual( - "worked", - value, - "EventEmitter API works!" - ); - if (callbackDone) - callbackDone(); - else - workerDone = true; - }); - worker.port.emit('addon-to-content', 'worked'); - } - }], - function(win, done) { - if (workerDone) - done(); - else - callbackDone = done; - } - ); -}; - -// Execute two concurrent page mods on same document to ensure that their -// JS contexts are different -exports.testMixedContext = function(test) { - let doneCallback = null; - let messages = 0; - let modObject = { - include: "data:text/html,", - contentScript: 'new ' + function WorkerScope() { - // Both scripts will execute this, - // context is shared if one script see the other one modification. - let isContextShared = "sharedAttribute" in document; - self.postMessage(isContextShared); - document.sharedAttribute = true; - }, - onAttach: function(w) { - w.on("message", function (isContextShared) { - if (isContextShared) { - test.fail("Page mod contexts are mixed."); - doneCallback(); - } - else if (++messages == 2) { - test.pass("Page mod contexts are different."); - doneCallback(); - } - }); - } - }; - testPageMod(test, "data:text/html,", [modObject, modObject], - function(win, done) { - doneCallback = done; - } - ); -}; - -exports.testHistory = function(test) { - // We need a valid url in order to have a working History API. - // (i.e do not work on data: or about: pages) - // Test bug 679054. - let url = require("self").data.url("test-page-mod.html"); - let callbackDone = null; - testPageMod(test, url, [{ - include: url, - contentScriptWhen: 'end', - contentScript: 'new ' + function WorkerScope() { - history.pushState({}, "", "#"); - history.replaceState({foo: "bar"}, "", "#"); - self.postMessage(history.state); - }, - onAttach: function(worker) { - worker.on('message', function (data) { - test.assertEqual(JSON.stringify(data), JSON.stringify({foo: "bar"}), - "History API works!"); - callbackDone(); - }); - } - }], - function(win, done) { - callbackDone = done; - } - ); -}; - -exports.testRelatedTab = function(test) { - test.waitUntilDone(); - - let tab; - let { PageMod } = require("page-mod"); - let pageMod = new PageMod({ - include: "about:*", - onAttach: function(worker) { - test.assertEqual(tab, worker.tab, "Worker.tab is valid"); - pageMod.destroy(); - tab.close(); - test.done(); - } - }); - - tabs.open({ - url: "about:", - onOpen: function onOpen(t) { - tab = t; - } - }); - -}; - -exports['test tab worker on message'] = function(test) { - test.waitUntilDone(); - - let { browserWindows } = require("windows"); - let tabs = require("tabs"); - let { PageMod } = require("page-mod"); - - let url1 = "data:text/html,<title>tab1</title><h1>worker1.tab</h1>"; - let url2 = "data:text/html,<title>tab2</title><h1>worker2.tab</h1>"; - let worker1 = null; - - let mod = PageMod({ - include: "data:text/html,*", - contentScriptWhen: "ready", - contentScript: "self.postMessage('#1');", - onAttach: function onAttach(worker) { - worker.on("message", function onMessage() { - this.tab.attach({ - contentScriptWhen: "ready", - contentScript: "self.postMessage({ url: window.location.href, title: document.title });", - onMessage: function onMessage(data) { - test.assertEqual(this.tab.url, data.url, "location is correct"); - test.assertEqual(this.tab.title, data.title, "title is correct"); - if (this.tab.url === url1) { - worker1 = this; - tabs.open({ url: url2, inBackground: true }); - } - else if (this.tab.url === url2) { - mod.destroy(); - worker1.tab.close(); - worker1.destroy(); - worker.tab.close(); - worker.destroy(); - test.done(); - } - } - }); - }); - } - }); - - tabs.open(url1); -}; - -exports.testAutomaticDestroy = function(test) { - test.waitUntilDone(); - let loader = Loader(module); - - let pageMod = loader.require("page-mod").PageMod({ - include: "about:*", - contentScriptWhen: "start", - onAttach: function(w) { - test.fail("Page-mod should have been detroyed during module unload"); - } - }); - - // Unload the page-mod module so that our page mod is destroyed - loader.unload(); - - // Then create a second tab to ensure that it is correctly destroyed - let tabs = require("tabs"); - tabs.open({ - url: "about:", - onReady: function onReady(tab) { - test.pass("check automatic destroy"); - tab.close(); - test.done(); - } - }); - -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-page-worker.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-page-worker.js deleted file mode 100644 index 89cdf45..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-page-worker.js +++ /dev/null @@ -1,362 +0,0 @@ -let tests = {}, Pages, Page; -const { Loader } = require('./helpers'); - -const ERR_DESTROYED = - "The page has been destroyed and can no longer be used."; - -tests.testSimplePageCreation = function(test) { - test.waitUntilDone(); - - let page = new Page({ - contentScript: "self.postMessage(window.location.href)", - contentScriptWhen: "end", - onMessage: function (message) { - test.assertEqual(message, "about:blank", - "Page Worker should start with a blank page by default"); - test.assertEqual(this, page, "The 'this' object is the page itself."); - test.done(); - } - }); -} - -/* - * Tests that we can't be tricked by document overloads as we have access - * to wrapped nodes - */ -tests.testWrappedDOM = function(test) { - test.waitUntilDone(); - - let page = Page({ - allow: { script: true }, - contentURL: "data:text/html,<script>document.getElementById=3;window.scrollTo=3;</script>", - contentScript: "window.addEventListener('load', function () " + - "self.postMessage([typeof(document.getElementById), " + - "typeof(window.scrollTo)]), true)", - onMessage: function (message) { - test.assertEqual(message[0], - "function", - "getElementById from content script is the native one"); - - test.assertEqual(message[1], - "function", - "scrollTo from content script is the native one"); - - test.done(); - } - }); -} - -/* -// We do not offer unwrapped access to DOM since bug 601295 landed -// See 660780 to track progress of unwrap feature -tests.testUnwrappedDOM = function(test) { - test.waitUntilDone(); - - let page = Page({ - allow: { script: true }, - contentURL: "data:text/html,<script>document.getElementById=3;window.scrollTo=3;</script>", - contentScript: "window.addEventListener('load', function () " + - "self.postMessage([typeof(unsafeWindow.document.getElementById), " + - "typeof(unsafeWindow.scrollTo)]), true)", - onMessage: function (message) { - test.assertEqual(message[0], - "number", - "document inside page is free to be changed"); - - test.assertEqual(message[1], - "number", - "window inside page is free to be changed"); - - test.done(); - } - }); -} -*/ - -tests.testPageProperties = function(test) { - let page = new Page(); - - for each (let prop in ['contentURL', 'allow', 'contentScriptFile', - 'contentScript', 'contentScriptWhen', 'on', - 'postMessage', 'removeListener']) { - test.assert(prop in page, prop + " property is defined on page."); - } - - test.assert(function () page.postMessage("foo") || true, - "postMessage doesn't throw exception on page."); -} - -tests.testConstructorAndDestructor = function(test) { - test.waitUntilDone(); - - let loader = Loader(module); - let Pages = loader.require("page-worker"); - let global = loader.sandbox("page-worker"); - - let pagesReady = 0; - - let page1 = Pages.Page({ - contentScript: "self.postMessage('')", - contentScriptWhen: "end", - onMessage: pageReady - }); - let page2 = Pages.Page({ - contentScript: "self.postMessage('')", - contentScriptWhen: "end", - onMessage: pageReady - }); - - test.assertNotEqual(page1, page2, - "Page 1 and page 2 should be different objects."); - - function pageReady() { - if (++pagesReady == 2) { - page1.destroy(); - page2.destroy(); - - test.assert(isDestroyed(page1), "page1 correctly unloaded."); - test.assert(isDestroyed(page2), "page2 correctly unloaded."); - - loader.unload(); - test.done(); - } - } -} - -tests.testAutoDestructor = function(test) { - test.waitUntilDone(); - - let loader = Loader(module); - let Pages = loader.require("page-worker"); - - let page = Pages.Page({ - contentScript: "self.postMessage('')", - contentScriptWhen: "end", - onMessage: function() { - loader.unload(); - test.assert(isDestroyed(page), "Page correctly unloaded."); - test.done(); - } - }); -} - -tests.testValidateOptions = function(test) { - test.assertRaises( - function () Page({ contentURL: 'home' }), - "The `contentURL` option must be a valid URL.", - "Validation correctly denied a non-URL contentURL" - ); - - test.assertRaises( - function () Page({ onMessage: "This is not a function."}), - "The event listener must be a function.", - "Validation correctly denied a non-function onMessage." - ); - - test.pass("Options validation is working."); -} - -tests.testContentAndAllowGettersAndSetters = function(test) { - test.waitUntilDone(); - let content = "data:text/html,<script>window.localStorage.allowScript=3;</script>"; - let page = Page({ - contentURL: content, - contentScript: "self.postMessage(window.localStorage.allowScript)", - contentScriptWhen: "end", - onMessage: step0 - }); - - function step0(message) { - test.assertEqual(message, "3", - "Correct value expected for allowScript - 3"); - test.assertEqual(page.contentURL, content, - "Correct content expected"); - page.removeListener('message', step0); - page.on('message', step1); - page.allow = { script: false }; - page.contentURL = content = - "data:text/html,<script>window.localStorage.allowScript='f'</script>"; - } - - function step1(message) { - test.assertEqual(message, "3", - "Correct value expected for allowScript - 3"); - test.assertEqual(page.contentURL, content, "Correct content expected"); - page.removeListener('message', step1); - page.on('message', step2); - page.allow = { script: true }; - page.contentURL = content = - "data:text/html,<script>window.localStorage.allowScript='g'</script>"; - } - - function step2(message) { - test.assertEqual(message, "g", - "Correct value expected for allowScript - g"); - test.assertEqual(page.contentURL, content, "Correct content expected"); - page.removeListener('message', step2); - page.on('message', step3); - page.allow.script = false; - page.contentURL = content = - "data:text/html,<script>window.localStorage.allowScript=3</script>"; - } - - function step3(message) { - test.assertEqual(message, "g", - "Correct value expected for allowScript - g"); - test.assertEqual(page.contentURL, content, "Correct content expected"); - page.removeListener('message', step3); - page.on('message', step4); - page.allow.script = true; - page.contentURL = content = - "data:text/html,<script>window.localStorage.allowScript=4</script>"; - } - - function step4(message) { - test.assertEqual(message, "4", - "Correct value expected for allowScript - 4"); - test.assertEqual(page.contentURL, content, "Correct content expected"); - test.done(); - } - -} - -tests.testOnMessageCallback = function(test) { - test.waitUntilDone(); - - Page({ - contentScript: "self.postMessage('')", - contentScriptWhen: "end", - onMessage: function() { - test.pass("onMessage callback called"); - test.done(); - } - }); -} - -tests.testMultipleOnMessageCallbacks = function(test) { - test.waitUntilDone(); - - let count = 0; - let page = Page({ - contentScript: "self.postMessage('')", - contentScriptWhen: "end", - onMessage: function() count += 1 - }); - page.on('message', function() count += 2); - page.on('message', function() count *= 3); - page.on('message', function() - test.assertEqual(count, 9, "All callbacks were called, in order.")); - page.on('message', function() test.done()); - -} - -tests.testLoadContentPage = function(test) { - - test.waitUntilDone(); - - let page = Page({ - onMessage: function(message) { - // The message is an array whose first item is the test method to call - // and the rest of whose items are arguments to pass it. - test[message.shift()].apply(test, message); - }, - contentURL: require("self").data.url("test-page-worker.html"), - contentScriptFile: require("self").data.url("test-page-worker.js"), - contentScriptWhen: "ready" - }); - -} - -tests.testAllowScriptDefault = function(test) { - - test.waitUntilDone(); - - let page = Page({ - onMessage: function(message) { - test.assert(message, "Script is allowed to run by default."); - test.done(); - }, - contentURL: "data:text/html,<script>document.documentElement.setAttribute('foo', 3);</script>", - contentScript: "self.postMessage(document.documentElement.getAttribute('foo'))", - contentScriptWhen: "ready" - }); -} - -tests.testAllowScript = function(test) { - - test.waitUntilDone(); - - let page = Page({ - onMessage: function(message) { - test.assert(message, "Script runs when allowed to do so."); - test.done(); - }, - allow: { script: true }, - contentURL: "data:text/html,<script>document.documentElement.setAttribute('foo', 3);</script>", - contentScript: "self.postMessage(document.documentElement.hasAttribute('foo') && " + - " document.documentElement.getAttribute('foo') == 3)", - contentScriptWhen: "ready" - }); -} - -tests.testPingPong = function(test) { - test.waitUntilDone(); - let page = Page({ - contentURL: 'data:text/html,ping-pong', - contentScript: 'self.on("message", function(message) self.postMessage("pong"));' - + 'self.postMessage("ready");', - onMessage: function(message) { - if ('ready' == message) { - page.postMessage('ping'); - } - else { - test.assert(message, 'pong', 'Callback from contentScript'); - test.done(); - } - } - }); -}; - -tests.testMultipleDestroys = function(test) { - let page = Page(); - page.destroy(); - page.destroy(); - test.pass("Multiple destroys should not cause an error"); -}; - - -function isDestroyed(page) { - try { - page.postMessage("foo"); - } - catch (err if err.message == ERR_DESTROYED) { - return true; - } - return false; -} - - -let pageWorkerSupported = true; - -try { - Pages = require("page-worker"); - Page = Pages.Page; -} -catch (ex if ex.message == [ - "The page-worker module currently supports only Firefox and Thunderbird. ", - "In the future, we would like it to support other applications, however. ", - "Please see https://bugzilla.mozilla.org/show_bug.cgi?id=546740 for more ", - "information." - ].join("")) { - pageWorkerSupported = false; -} - -if (pageWorkerSupported) { - for (let test in tests) { - exports[test] = tests[test]; - } -} else { - exports.testPageWorkerNotSupported = function(test) { - test.pass("The page-worker module is not supported on this app."); - } -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-panel.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-panel.js deleted file mode 100644 index 3e240db..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-panel.js +++ /dev/null @@ -1,437 +0,0 @@ -let { Cc, Ci } = require("chrome"); -let panels = require('panel'); -let tests = {}, panels, Panel; -const { Loader } = require('./helpers'); - -tests.testPanel = function(test) { - test.waitUntilDone(); - let panel = Panel({ - contentURL: "about:buildconfig", - contentScript: "self.postMessage(1); self.on('message', function() self.postMessage(2));", - onMessage: function (message) { - test.assertEqual(this, panel, "The 'this' object is the panel."); - switch(message) { - case 1: - test.pass("The panel was loaded."); - panel.postMessage(''); - break; - case 2: - test.pass("The panel posted a message and received a response."); - panel.destroy(); - test.done(); - break; - } - } - }); -}; - -tests.testPanelEmit = function(test) { - test.waitUntilDone(); - let panel = Panel({ - contentURL: "about:buildconfig", - contentScript: "self.port.emit('loaded');" + - "self.port.on('addon-to-content', " + - " function() self.port.emit('received'));", - }); - panel.port.on("loaded", function () { - test.pass("The panel was loaded and sent a first event."); - panel.port.emit("addon-to-content"); - }); - panel.port.on("received", function () { - test.pass("The panel posted a message and received a response."); - panel.destroy(); - test.done(); - }); -}; - -tests.testPanelEmitEarly = function(test) { - test.waitUntilDone(); - let panel = Panel({ - contentURL: "about:buildconfig", - contentScript: "self.port.on('addon-to-content', " + - " function() self.port.emit('received'));", - }); - panel.port.on("received", function () { - test.pass("The panel posted a message early and received a response."); - panel.destroy(); - test.done(); - }); - panel.port.emit("addon-to-content"); -}; - -tests.testShowHidePanel = function(test) { - test.waitUntilDone(); - let panel = Panel({ - contentScript: "self.postMessage('')", - contentScriptWhen: "end", - onMessage: function (message) { - panel.show(); - }, - onShow: function () { - test.pass("The panel was shown."); - test.assertEqual(this, panel, "The 'this' object is the panel."); - test.assertEqual(this.isShowing, true, "panel.isShowing == true."); - panel.hide(); - }, - onHide: function () { - test.pass("The panel was hidden."); - test.assertEqual(this, panel, "The 'this' object is the panel."); - test.assertEqual(this.isShowing, false, "panel.isShowing == false."); - panel.destroy(); - test.done(); - } - }); -}; - -tests.testDocumentReload = function(test) { - test.waitUntilDone(); - let content = - "<script>" + - "setTimeout(function () {" + - " window.location = 'about:blank';" + - "}, 250);" + - "</script>"; - let messageCount = 0; - let panel = Panel({ - contentURL: "data:text/html," + encodeURIComponent(content), - contentScript: "self.postMessage(window.location.href)", - onMessage: function (message) { - messageCount++; - if (messageCount == 1) { - test.assertMatches(message, /data:text\/html,/, "First document had a content script"); - } - else if (messageCount == 2) { - test.assertEqual(message, "about:blank", "Second document too"); - panel.destroy(); - test.done(); - } - } - }); -}; - -tests.testParentResizeHack = function(test) { - let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]. - getService(Ci.nsIWindowMediator). - getMostRecentWindow("navigator:browser"); - let docShell = browserWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell); - if (!("allowWindowControl" in docShell)) { - // bug 635673 is not fixed in this firefox build - test.pass("allowWindowControl attribute that allow to fix browser window " + - "resize is not available on this build."); - return; - } - - test.waitUntilDone(30000); - - let previousWidth = browserWindow.outerWidth, previousHeight = browserWindow.outerHeight; - - let content = "<script>" + - "function contentResize() {" + - " resizeTo(200,200);" + - " resizeBy(200,200);" + - "}" + - "</script>" + - "Try to resize browser window"; - let panel = Panel({ - contentURL: "data:text/html," + encodeURIComponent(content), - contentScript: "self.on('message', function(message){" + - " if (message=='resize') " + - " unsafeWindow.contentResize();" + - "});", - contentScriptWhen: "ready", - onMessage: function (message) { - - }, - onShow: function () { - panel.postMessage('resize'); - require("timer").setTimeout(function () { - test.assertEqual(previousWidth,browserWindow.outerWidth,"Size doesn't change by calling resizeTo/By/..."); - test.assertEqual(previousHeight,browserWindow.outerHeight,"Size doesn't change by calling resizeTo/By/..."); - panel.destroy(); - test.done(); - },0); - } - }); - panel.show(); -} - -tests.testResizePanel = function(test) { - test.waitUntilDone(); - - // These tests fail on Linux if the browser window in which the panel - // is displayed is not active. And depending on what other tests have run - // before this one, it might not be (the untitled window in which the test - // runner executes is often active). So we make sure the browser window - // is focused by focusing it before running the tests. Then, to be the best - // possible test citizen, we refocus whatever window was focused before we - // started running these tests. - - let activeWindow = Cc["@mozilla.org/embedcomp/window-watcher;1"]. - getService(Ci.nsIWindowWatcher). - activeWindow; - let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]. - getService(Ci.nsIWindowMediator). - getMostRecentWindow("navigator:browser"); - - - function onFocus() { - browserWindow.removeEventListener("focus", onFocus, true); - - let panel = Panel({ - contentScript: "self.postMessage('')", - contentScriptWhen: "end", - height: 10, - width: 10, - onMessage: function (message) { - panel.show(); - }, - onShow: function () { - panel.resize(100,100); - panel.hide(); - }, - onHide: function () { - test.assert((panel.width == 100) && (panel.height == 100), - "The panel was resized."); - if (activeWindow) - activeWindow.focus(); - test.done(); - } - }); - } - - if (browserWindow === activeWindow) { - onFocus(); - } - else { - browserWindow.addEventListener("focus", onFocus, true); - browserWindow.focus(); - } -}; - -tests.testHideBeforeShow = function(test) { - test.waitUntilDone(); - let showCalled = false; - let panel = Panel({ - onShow: function () { - showCalled = true; - }, - onHide: function () { - test.assert(!showCalled, 'must not emit show if was hidden before'); - test.done(); - } - }); - panel.show(); - panel.hide(); -}; - -tests.testSeveralShowHides = function(test) { - test.waitUntilDone(); - let hideCalled = 0; - let panel = panels.Panel({ - contentURL: "about:buildconfig", - onShow: function () { - panel.hide(); - }, - onHide: function () { - hideCalled++; - if (hideCalled < 3) - panel.show(); - else { - test.pass("onHide called three times as expected"); - test.done(); - } - } - }); - panel.on('error', function(e) { - test.fail('error was emitted:' + e.message + '\n' + e.stack); - }); - panel.show(); -}; - -tests.testAnchorAndArrow = function(test) { - test.waitUntilDone(20000); - let count = 0; - function newPanel(tab, anchor) { - let panel = panels.Panel({ - contentURL: "data:text/html,<html><body style='padding: 0; margin: 0; " + - "background: gray; text-align: center;'>Anchor: " + - anchor.id + "</body></html>", - width: 200, - height: 100, - onShow: function () { - count++; - panel.destroy(); - if (count==5) { - test.pass("All anchored panel test displayed"); - tab.close(function () { - test.done(); - }); - } - } - }); - panel.show(anchor); - } - - let tabs= require("tabs"); - let url = 'data:text/html,' + - '<html><head><title>foo</title></head><body>' + - '<style>div {background: gray; position: absolute; width: 300px; ' + - 'border: 2px solid black;}</style>' + - '<div id="tl" style="top: 0px; left: 0px;">Top Left</div>' + - '<div id="tr" style="top: 0px; right: 0px;">Top Right</div>' + - '<div id="bl" style="bottom: 0px; left: 0px;">Bottom Left</div>' + - '<div id="br" style="bottom: 0px; right: 0px;">Bottom right</div>' + - '</body></html>'; - - tabs.open({ - url: url, - onReady: function(tab) { - let browserWindow = Cc["@mozilla.org/appshell/window-mediator;1"]. - getService(Ci.nsIWindowMediator). - getMostRecentWindow("navigator:browser"); - let window = browserWindow.content; - newPanel(tab, window.document.getElementById('tl')); - newPanel(tab, window.document.getElementById('tr')); - newPanel(tab, window.document.getElementById('bl')); - newPanel(tab, window.document.getElementById('br')); - let anchor = browserWindow.document.getElementById("identity-box"); - newPanel(tab, anchor); - } - }); - - - -}; - -tests.testPanelTextColor = function(test) { - test.waitUntilDone(); - let html = "<html><head><style>body {color: yellow}</style></head>" + - "<body><p>Foo</p></body></html>"; - let panel = Panel({ - contentURL: "data:text/html," + encodeURI(html), - contentScript: "self.port.emit('color', " + - "window.getComputedStyle(document.body.firstChild, null). " + - " getPropertyValue('color'));" - }); - panel.port.on("color", function (color) { - test.assertEqual(color, "rgb(255, 255, 0)", - "The panel text color style is preserved when a style exists."); - panel.destroy(); - test.done(); - }); -}; - -function makeEventOrderTest(options) { - let expectedEvents = []; - - return function(test) { - let panel = panels.Panel({ contentURL: "about:buildconfig" }); - - function expect(event, cb) { - expectedEvents.push(event); - panel.on(event, function() { - test.assertEqual(event, expectedEvents.shift()); - if (cb) - require("timer").setTimeout(cb, 1); - }); - return {then: expect}; - } - - test.waitUntilDone(); - options.test(test, expect, panel); - } -} - -tests.testAutomaticDestroy = function(test) { - let loader = Loader(module); - let panel = loader.require("panel").Panel({ - contentURL: "about:buildconfig", - contentScript: - "self.port.on('event', function() self.port.emit('event-back'));" - }); - - loader.unload(); - - panel.port.on("event-back", function () { - test.fail("Panel should have been destroyed on module unload"); - }); - panel.port.emit("event"); - test.pass("check automatic destroy"); -}; - -tests.testWaitForInitThenShowThenDestroy = makeEventOrderTest({ - test: function(test, expect, panel) { - expect('inited', function() { panel.show(); }). - then('show', function() { panel.destroy(); }). - then('hide', function() { test.done(); }); - } -}); - -tests.testShowThenWaitForInitThenDestroy = makeEventOrderTest({ - test: function(test, expect, panel) { - panel.show(); - expect('inited'). - then('show', function() { panel.destroy(); }). - then('hide', function() { test.done(); }); - } -}); - -tests.testShowThenHideThenDestroy = makeEventOrderTest({ - test: function(test, expect, panel) { - panel.show(); - expect('show', function() { panel.hide(); }). - then('hide', function() { panel.destroy(); test.done(); }); - } -}); - -tests.testContentURLOption = function(test) { - const URL_STRING = "about:buildconfig"; - const HTML_CONTENT = "<html><title>Test</title><p>This is a test.</p></html>"; - - let (panel = Panel({ contentURL: URL_STRING })) { - test.pass("contentURL accepts a string URL."); - test.assertEqual(panel.contentURL, URL_STRING, - "contentURL is the string to which it was set."); - } - - let dataURL = "data:text/html," + encodeURIComponent(HTML_CONTENT); - let (panel = Panel({ contentURL: dataURL })) { - test.pass("contentURL accepts a data: URL."); - } - - let (panel = Panel({})) { - test.assert(panel.contentURL == null, - "contentURL is undefined."); - } - - test.assertRaises(function () Panel({ contentURL: "foo" }), - "The `contentURL` option must be a valid URL.", - "Panel throws an exception if contentURL is not a URL."); -}; - -let panelSupported = true; - -try { - panels = require("panel"); - Panel = panels.Panel; -} -catch(ex if ex.message == [ - "The panel module currently supports only Firefox. In the future ", - "we would like it to support other applications, however. Please see ", - "https://bugzilla.mozilla.org/show_bug.cgi?id=jetpack-panel-apps ", - "for more information." - ].join("")) { - panelSupported = false; -} - -if (panelSupported) { - for (let test in tests) - exports[test] = tests[test]; -} -else { - exports.testPanelNotSupported = function(test) { - test.pass("The panel module is not supported on this app."); - } -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-passwords.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-passwords.js deleted file mode 100644 index e799b48..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-passwords.js +++ /dev/null @@ -1,277 +0,0 @@ -"use strict"; - -const { store, search, remove } = require("passwords"); - -exports["test store requires `password` field"] = function(assert, done) { - store({ - username: "foo", - realm: "bar", - onComplete: function onComplete() { - assert.fail("onComplete should not be called"); - }, - onError: function onError() { - assert.pass("'`password` is required"); - done(); - } - }); -}; - -exports["test store requires `username` field"] = function(assert, done) { - store({ - password: "foo", - realm: "bar", - onComplete: function onComplete() { - assert.fail("onComplete should not be called"); - }, - onError: function onError() { - assert.pass("'`username` is required"); - done(); - } - }); -}; - -exports["test onComplete is optional"] = function(assert, done) { - store({ - realm: "bla", - username: "bla", - password: "bla", - onError: function onError() { - assert.fail("onError was called"); - } - }); - assert.pass("exception is not thrown if `onComplete is missing") - done(); -}; - -exports["test exceptions in onComplete are reported"] = function(assert, done) { - store({ - realm: "throws", - username: "error", - password: "boom!", - onComplete: function onComplete(error) { - throw new Error("Boom!") - }, - onError: function onError(error) { - assert.equal(error.message, "Boom!", "Error thrown is reported"); - done(); - } - }); -}; - -exports["test store requires `realm` field"] = function(assert, done) { - store({ - username: "foo", - password: "bar", - onComplete: function onComplete() { - assert.fail("onComplete should not be called"); - }, - onError: function onError() { - assert.pass("'`realm` is required"); - done(); - } - }); -}; - -exports["test can't store same login twice"] = function(assert, done) { - store({ - username: "user", - password: "pass", - realm: "realm", - onComplete: function onComplete() { - assert.pass("credential saved"); - - store({ - username: "user", - password: "pass", - realm: "realm", - onComplete: function onComplete() { - assert.fail("onComplete should not be called"); - }, - onError: function onError() { - assert.pass("re-saving credential failed"); - - remove({ - username: "user", - password: "pass", - realm: "realm", - onComplete: function onComplete() { - assert.pass("credential was removed"); - done(); - }, - onError: function onError() { - assert.fail("remove should not fail"); - } - }); - } - }); - }, - onError: function onError() { - assert.fail("onError should not be called"); - } - }); -}; - -exports["test remove fails if no login found"] = function(assert, done) { - remove({ - username: "foo", - password: "bar", - realm: "baz", - onComplete: function onComplete() { - assert.fail("should not be able to remove unstored credentials"); - }, - onError: function onError() { - assert.pass("can't remove unstored credentials"); - done(); - } - }); -}; - -exports["test addon associated credentials"] = function(assert, done) { - store({ - username: "foo", - password: "bar", - realm: "baz", - onComplete: function onComplete() { - search({ - username: "foo", - password: "bar", - realm: "baz", - onComplete: function onComplete([credential]) { - assert.equal(credential.url.indexOf("addon:"), 0, - "`addon:` uri is used for add-on credentials"); - assert.equal(credential.username, "foo", - "username matches"); - assert.equal(credential.password, "bar", - "password matches"); - assert.equal(credential.realm, "baz", "realm matches"); - assert.equal(credential.formSubmitURL, null, - "`formSubmitURL` is `null` for add-on credentials"); - assert.equal(credential.usernameField, "", "usernameField is empty"); - assert.equal(credential.passwordField, "", "passwordField is empty"); - - remove({ - username: credential.username, - password: credential.password, - realm: credential.realm, - onComplete: function onComplete() { - assert.pass("credential is removed"); - done(); - }, - onError: function onError() { - assert.fail("onError should not be called"); - } - }); - }, - onError: function onError() { - assert.fail("onError should not be called"); - } - }); - }, - onError: function onError() { - assert.fail("onError should not be called"); - } - }); -}; - -exports["test web page associated credentials"] = function(assert, done) { - store({ - url: "http://bar.foo.com/authentication/?login", - formSubmitURL: "http://login.foo.com/authenticate.cgi", - username: "user", - password: "pass", - usernameField: "user-f", - passwordField: "pass-f", - onComplete: function onComplete() { - search({ - username: "user", - password: "pass", - url: "http://bar.foo.com", - formSubmitURL: "http://login.foo.com", - onComplete: function onComplete([credential]) { - assert.equal(credential.url, "http://bar.foo.com", "url matches"); - assert.equal(credential.username, "user", "username matches"); - assert.equal(credential.password, "pass", "password matches"); - assert.equal(credential.realm, null, "realm is null"); - assert.equal(credential.formSubmitURL, "http://login.foo.com", - "formSubmitURL matches"); - assert.equal(credential.usernameField, "user-f", - "usernameField is matches"); - assert.equal(credential.passwordField, "pass-f", - "passwordField matches"); - - remove({ - url: credential.url, - formSubmitURL: credential.formSubmitURL, - username: credential.username, - password: credential.password, - usernameField: credential.usernameField, - passwordField: credential.passwordField, - - onComplete: function onComplete() { - assert.pass("credential is removed"); - done(); - }, - onError: function onError(e) { - assert.fail("onError should not be called"); - } - }); - }, - onError: function onError() { - assert.fail("onError should not be called"); - } - }); - }, - onError: function onError() { - assert.fail("onError should not be called"); - } - }); -}; - -exports["test site authentication credentials"] = function(assert, done) { - store({ - url: "http://authentication.com", - username: "U", - password: "P", - realm: "R", - onComplete: function onComplete() { - search({ - url: "http://authentication.com", - username: "U", - password: "P", - realm: "R", - onComplete: function onComplete([credential]) { - assert.equal(credential.url,"http://authentication.com", - "url matches"); - assert.equal(credential.username, "U", "username matches"); - assert.equal(credential.password, "P", "password matches"); - assert.equal(credential.realm, "R", "realm matches"); - assert.equal(credential.formSubmitURL, null, "formSubmitURL is null"); - assert.equal(credential.usernameField, "", "usernameField is empty"); - assert.equal(credential.passwordField, "", "passwordField is empty"); - - remove({ - url: credential.url, - username: credential.username, - password: credential.password, - realm: credential.realm, - onComplete: function onComplete() { - assert.pass("credential is removed"); - done(); - }, - onError: function onError() { - assert.fail("onError should not be called"); - } - }); - }, - onError: function onError() { - assert.fail("onError should not be called"); - } - }); - }, - onError: function onError() { - assert.fail("onError should not be called"); - } - }); -}; - -require("test").run(exports); diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-private-browsing.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-private-browsing.js deleted file mode 100644 index a3c1519..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-private-browsing.js +++ /dev/null @@ -1,238 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Paul O’Shannessy <paul@oshannessy.com> - * Irakli Gozalishvili <gozala@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -let pb = require("private-browsing"); -let {Cc,Ci} = require("chrome"); -const { Loader } = require('./helpers'); - -let pbService; -// Currently, only Firefox implements the private browsing service. -if (require("xul-app").is("Firefox")) { - pbService = Cc["@mozilla.org/privatebrowsing;1"]. - getService(Ci.nsIPrivateBrowsingService); -} - -if (pbService) { - - // tests that isActive has the same value as the private browsing service - // expects - exports.testGetIsActive = function (test) { - test.assertEqual(pb.isActive, false, - "private-browsing.isActive is correct without modifying PB service"); - - pbService.privateBrowsingEnabled = true; - test.assert(pb.isActive, - "private-browsing.isActive is correct after modifying PB service"); - - // Switch back to normal mode. - pbService.privateBrowsingEnabled = false; - }; - - // tests that activating does put the browser into private browsing mode - exports.testActivateDeactivate = function (test) { - test.waitUntilDone(); - pb.once("start", function onStart() { - test.assertEqual(pbService.privateBrowsingEnabled, true, - "private browsing mode was activated"); - pb.deactivate(); - }); - pb.once("stop", function onStop() { - test.assertEqual(pbService.privateBrowsingEnabled, false, - "private browsing mode was deactivate"); - test.done(); - }); - pb.activate(); - }; - - exports.testStart = function(test) { - test.waitUntilDone(); - pb.on("start", function onStart() { - test.assertEqual(this, pb, "`this` should be private-browsing module"); - test.assert(pbService.privateBrowsingEnabled, - 'private mode is active when "start" event is emitted'); - test.assert(pb.isActive, - '`isActive` is `true` when "start" event is emitted'); - pb.removeListener("start", onStart); - test.done(); - }); - pb.activate(); - }; - - exports.testStop = function(test) { - test.waitUntilDone(); - pb.on("stop", function onStop() { - test.assertEqual(this, pb, "`this` should be private-browsing module"); - test.assertEqual(pbService.privateBrowsingEnabled, false, - "private mode is disabled when stop event is emitted"); - test.assertEqual(pb.isActive, false, - "`isActive` is `false` when stop event is emitted"); - pb.removeListener("stop", onStop); - test.done(); - }); - pb.activate(); - pb.deactivate(); - }; - - exports.testAutomaticUnload = function(test) { - test.waitUntilDone(); - // Create another private browsing instance and unload it - let loader = Loader(module); - let pb2 = loader.require("private-browsing"); - let called = false; - pb2.on("start", function onStart() { - called = true; - test.fail("should not be called:x"); - }); - loader.unload(); - - // Then switch to private mode in order to check that the previous instance - // is correctly destroyed - pb.activate(); - pb.once("start", function onStart() { - require("timer").setTimeout(function () { - test.assert(!called, - "First private browsing instance is destroyed and inactive"); - - // Must reset to normal mode, so that next test starts with it. - pb.deactivate(); - test.done(); - }, 0); - }); - }; - - exports.testBothListeners = function(test) { - test.waitUntilDone(); - let stop = false; - let start = false; - - function onStop() { - test.assertEqual(stop, false, - "stop callback must be called only once"); - test.assertEqual(pbService.privateBrowsingEnabled, false, - "private mode is disabled when stop event is emitted"); - test.assertEqual(pb.isActive, false, - "`isActive` is `false` when stop event is emitted"); - - pb.on("start", finish); - pb.removeListener("start", onStart); - pb.removeListener("start", onStart2); - pb.activate(); - stop = true; - } - - function onStart() { - test.assertEqual(false, start, - "stop callback must be called only once"); - test.assert(pbService.privateBrowsingEnabled, - "private mode is active when start event is emitted"); - test.assert(pb.isActive, - "`isActive` is `true` when start event is emitted"); - - pb.on("stop", onStop); - pb.deactivate(); - start = true; - } - - function onStart2() { - test.assert(start, "start listener must be called already"); - test.assertEqual(false, stop, "stop callback must not be called yet"); - } - - function finish() { - test.assert(pbService.privateBrowsingEnabled, true, - "private mode is active when start event is emitted"); - test.assert(pb.isActive, - "`isActive` is `true` when start event is emitted"); - - pb.removeListener("start", finish); - pb.removeListener("stop", onStop); - - pb.deactivate(); - pb.once("stop", function () { - test.assertEqual(pbService.privateBrowsingEnabled, false); - test.assertEqual(pb.isActive, false); - - test.done(); - }); - } - - pb.on("start", onStart); - pb.on("start", onStart2); - pbService.privateBrowsingEnabled = true; - }; - - exports["test activate private mode via handler"] = function(test) { - const tabs = require("tabs"); - - test.waitUntilDone(); - function onReady(tab) { - if (tab.url == "about:robots") - tab.close(function() pb.activate()); - } - function cleanup(tab) { - if (tab.url == "about:") { - tabs.removeListener("ready", cleanup); - tab.close(function onClose() { - test.done(); - }); - } - } - - tabs.on("ready", onReady); - pb.once("start", function onStart() { - test.pass("private mode was activated"); - pb.deactivate(); - }); - pb.once("stop", function onStop() { - test.pass("private mode was deactivated"); - tabs.removeListener("ready", onReady); - tabs.on("ready", cleanup); - }); - tabs.once("open", function onOpen() { - tabs.open("about:robots"); - }); - tabs.open("about:"); - }; -} -else { - // tests for the case where private browsing doesn't exist - exports.testNoImpl = function (test) { - test.assertEqual(pb.isActive, false, - "pb.isActive returns false when private browsing isn't supported"); - }; -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-request.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-request.js deleted file mode 100644 index 8b8300e..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-request.js +++ /dev/null @@ -1,358 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Paul O’Shannessy <paul@oshannessy.com> (Original Author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -const Request = require("request").Request; - -var port = 8080; -var data = require("self").data; -var testFilePath = require("url").toFilename(data.url("test-request.txt")); -var basePath = require("file").dirname(testFilePath); - -var {startServerAsync} = require("httpd"); - -exports.testOptionsValidator = function(test) { - // First, a simple test to make sure we didn't break normal functionality. - test.assertRaises(function () { - Request({ - url: null - }); - }, 'The option "url" must be one of the following types: string'); - - // Next we'll have a Request that doesn't throw from c'tor, but from a setter. - let req = Request({ - url: "http://playground.zpao.com/jetpack/request/text.php", - onComplete: function () {} - }); - test.assertRaises(function () { - req.url = null; - }, 'The option "url" must be one of the following types: string'); - // The url shouldn't have changed, so check that - test.assertEqual(req.url, "http://playground.zpao.com/jetpack/request/text.php"); -} - -exports.testContentValidator = function(test) { - test.waitUntilDone(); - Request({ - url: "data:text/html,response", - content: { 'key1' : null, 'key2' : 'some value' }, - onComplete: function(response) { - test.assertEqual(response.text, "response?key1=null&key2=some+value"); - test.done(); - } - }).get(); -}; - -// All tests below here require a network connection. They will be commented out -// when checked in. If you'd like to run them, simply uncomment them. -// -// When we have the means, these tests will be converted so that they don't -// require an external server nor a network connection. - -// This is a request to a file that exists. -exports.testStatus200 = function (test) { - var srv = startServerAsync(port, basePath); - - test.waitUntilDone(); - var req = Request({ - url: "http://localhost:" + port + "/test-request.txt", - onComplete: function (response) { - test.assertEqual(this, req, "`this` should be request"); - test.assertEqual(response.status, 200); - test.assertEqual(response.statusText, "OK"); - test.assertEqual(response.headers["Content-Type"], "text/plain"); - test.assertEqual(response.text, "Look ma, no hands!\n"); - srv.stop(function() test.done()); - } - }).get(); -} - -// This tries to get a file that doesn't exist -exports.testStatus404 = function (test) { - var srv = startServerAsync(port, basePath); - - test.waitUntilDone(); - Request({ - // the following URL doesn't exist - url: "http://localhost:" + port + "/test-request-404.txt", - onComplete: function (response) { - test.assertEqual(response.status, 404); - test.assertEqual(response.statusText, "Not Found"); - srv.stop(function() test.done()); - } - }).get(); -} - -/* -// a simple file with a known header -exports.testKnownHeader = function (test) { - test.waitUntilDone(); - Request({ - url: "http://playground.zpao.com/jetpack/request/headers.php", - onComplete: function (response) { - test.assertEqual(response.headers["x-zpao-header"], "Jamba Juice"); - test.done(); - } - }).get(); -} - -// complex headers -exports.testKnownHeader = function (test) { - let headers = { - "x-zpao-header": "Jamba Juice is: delicious", - "x-zpao-header-2": "foo, bar", - "Set-Cookie": "foo=bar\nbaz=foo" - } - test.waitUntilDone(); - Request({ - url: "http://playground.zpao.com/jetpack/request/complex_headers.php", - onComplete: function (response) { - for (k in headers) { - test.assertEqual(response.headers[k], headers[k]); - } - test.done(); - } - }).get(); -} -*/ - -exports.testSimpleJSON = function (test) { - var srv = startServerAsync(port, basePath); - - test.waitUntilDone(); - Request({ - url: "http://localhost:" + port + "/test-request.json", - onComplete: function (response) { - assertDeepEqual(test, response.json, { foo: "bar" }); - srv.stop(function() test.done()); - } - }).get(); -} - -exports.testInvalidJSON = function (test) { - var srv = startServerAsync(port, basePath); - - test.waitUntilDone(); - Request({ - url: "http://localhost:" + port + "/test-request-invalid.json", - onComplete: function (response) { - test.assertEqual(response.json, null); - srv.stop(function() test.done()); - } - }).get(); -} - -/* -exports.testGetWithParamsNotContent = function (test) { - test.waitUntilDone(); - Request({ - url: "http://playground.zpao.com/jetpack/request/getpost.php?foo=bar", - onComplete: function (response) { - let expected = { - "POST": [], - "GET" : { foo: "bar" } - }; - assertDeepEqual(test, response.json, expected); - test.done(); - } - }).get(); -} - -exports.testGetWithContent = function (test) { - test.waitUntilDone(); - Request({ - url: "http://playground.zpao.com/jetpack/request/getpost.php", - content: { foo: "bar" }, - onComplete: function (response) { - let expected = { - "POST": [], - "GET" : { foo: "bar" } - }; - assertDeepEqual(test, response.json, expected); - test.done(); - } - }).get(); -} - -exports.testGetWithParamsAndContent = function (test) { - test.waitUntilDone(); - Request({ - url: "http://playground.zpao.com/jetpack/request/getpost.php?foo=bar", - content: { baz: "foo" }, - onComplete: function (response) { - let expected = { - "POST": [], - "GET" : { foo: "bar", baz: "foo" } - }; - assertDeepEqual(test, response.json, expected); - test.done(); - } - }).get(); -} - -exports.testSimplePost = function (test) { - test.waitUntilDone(); - Request({ - url: "http://playground.zpao.com/jetpack/request/getpost.php", - content: { foo: "bar" }, - onComplete: function (response) { - let expected = { - "POST": { foo: "bar" }, - "GET" : [] - }; - assertDeepEqual(test, response.json, expected); - test.done(); - } - }).post(); -} - -exports.testEncodedContent = function (test) { - test.waitUntilDone(); - Request({ - url: "http://playground.zpao.com/jetpack/request/getpost.php", - content: "foo=bar&baz=foo", - onComplete: function (response) { - let expected = { - "POST": [], - "GET" : { foo: "bar", baz: "foo" } - }; - assertDeepEqual(test, response.json, expected); - test.done(); - } - }).get(); -} - -exports.testEncodedContentWithSpaces = function (test) { - test.waitUntilDone(); - Request({ - url: "http://playground.zpao.com/jetpack/request/getpost.php", - content: "foo=bar+hop!&baz=foo", - onComplete: function (response) { - let expected = { - "POST": [], - "GET" : { foo: "bar hop!", baz: "foo" } - }; - assertDeepEqual(test, response.json, expected); - test.done(); - } - }).get(); -} - -exports.testGetWithArray = function (test) { - test.waitUntilDone(); - Request({ - url: "http://playground.zpao.com/jetpack/request/getpost.php", - content: { foo: [1, 2], baz: "foo" }, - onComplete: function (response) { - let expected = { - "POST": [], - "GET" : { foo: [1, 2], baz: "foo" } - }; - assertDeepEqual(test, response.json, expected); - test.done(); - } - }).get(); -} - -exports.testGetWithNestedArray = function (test) { - test.waitUntilDone(); - Request({ - url: "http://playground.zpao.com/jetpack/request/getpost.php", - content: { foo: [1, 2, [3, 4]], bar: "baz" }, - onComplete: function (response) { - let expected = { - "POST": [], - "GET" : this.content - }; - assertDeepEqual(test, response.json, expected); - test.done(); - } - }).get(); -} - -exports.testGetWithNestedArray = function (test) { - test.waitUntilDone(); - let request = Request({ - url: "http://playground.zpao.com/jetpack/request/getpost.php", - content: { - foo: [1, 2, { - omg: "bbq", - "all your base!": "are belong to us" - }], - bar: "baz" - }, - onComplete: function (response) { - let expected = { - "POST": [], - "GET" : request.content - }; - assertDeepEqual(test, response.json, expected); - test.done(); - } - }).get(); -} -*/ - -// This is not a proper testing for deep equal, but it's good enough for my uses -// here. It will do type coercion to check equality, but that's good here. Data -// coming from the server will be stringified and so "0" should be equal to 0. -function assertDeepEqual(test, obj1, obj2, msg) { - function equal(o1, o2) { - // cover our non-object cases well enough - if (o1 == o2) - return true; - if (typeof(o1) != typeof(o2)) - return false; - if (typeof(o1) != "object") - return o1 == o2; - - let e = true; - for (let [key, val] in Iterator(o1)) { - e = e && key in o2 && equal(o2[key], val); - if (!e) - break; - } - for (let [key, val] in Iterator(o2)) { - e = e && key in o1 && equal(o1[key], val); - if (!e) - break; - } - return e; - } - msg = msg || "objects not equal - " + JSON.stringify(obj1) + " != " + - JSON.stringify(obj2); - test.assert(equal(obj1, obj2), msg); -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-selection.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-selection.js deleted file mode 100644 index cd96072..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-selection.js +++ /dev/null @@ -1,490 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Eric H. Jung <eric.jung@yahoo.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -let timer = require("timer"); -let {Cc,Ci} = require("chrome"); - -// Arbitrary delay needed to avoid weird behavior. -// TODO: We need to find all uses of this and replace them -// with more deterministic solutions. -const ARB_DELAY = 100; - -// Select all divs elements in an HTML document -function selectAllDivs(window) { - let divs = window.document.getElementsByTagName("div"); - let s = window.getSelection(); - if (s.rangeCount > 0) - s.removeAllRanges(); - for (let i = 0; i < divs.length; i++) { - let range = window.document.createRange(); - range.selectNode(divs[i]); - s.addRange(range); - } -} - -function selectTextarea(window, from, to) { - let textarea = window.document.getElementsByTagName("textarea")[0]; - - from = from || 0; - to = to || textarea.value.length; - - textarea.setSelectionRange(from, to); - textarea.focus(); -} - -function primeTestCase(html, test, callback) { - let tabBrowser = require("tab-browser"); - let dataURL = "data:text/html," + encodeURI(html); - let tracker = tabBrowser.whenContentLoaded( - function(window) { - if (window.document.location.href != dataURL) - return; - callback(window, test); - timer.setTimeout(function() { - tracker.unload(); - test.done(); - window.close(); - }, - ARB_DELAY); - } - ); - tabBrowser.addTab(dataURL); -} - -const DIV1 = '<div id="foo">bar</div>'; -const DIV2 = '<div>noodles</div>'; -const HTML_MULTIPLE = '<html><body>' + DIV1 + DIV2 + '</body></html>'; -const HTML_SINGLE = '<html><body>' + DIV1 + '</body></html>'; - -// Tests of contiguous - -exports.testContiguousMultiple = function testContiguousMultiple(test) { - let selection = require("selection"); - primeTestCase(HTML_MULTIPLE, test, function(window, test) { - selectAllDivs(window); - test.assertEqual(selection.isContiguous, false, - "selection.isContiguous multiple works."); - }); - - test.waitUntilDone(5000); -}; - -exports.testContiguousSingle = function testContiguousSingle(test) { - let selection = require("selection"); - primeTestCase(HTML_SINGLE, test, function(window, test) { - selectAllDivs(window); - test.assertEqual(selection.isContiguous, true, - "selection.isContiguous single works."); - }); - - test.waitUntilDone(5000); -}; - -exports.testContiguousWithoutSelection = - function testContiguousWithoutSelection(test) { - let selection = require("selection"); - primeTestCase(HTML_SINGLE, test, function(window, test) { - test.assertEqual(selection.isContiguous, false, - "selection.isContiguous without selection works."); - }); - - test.waitUntilDone(5000); -}; - -/** - * Test that setting the contiguous property has no effect. - */ -/*exports.testSetContiguous = function testSetContiguous(test) { - let selection = require("selection"); - primeTestCase(HTML_MULTIPLE, test, function(window, test) { - selectAllDivs(window); - try { - selection.isContiguous = true; - test.assertEqual(selection.isContiguous, false, - "setting selection.isContiguous doesn't work (as expected)."); - } - catch (e) { - test.pass("setting selection.isContiguous doesn't work (as expected)."); - } - }); - - test.waitUntilDone(5000); -};*/ - - -// HTML tests - -exports.testGetHTMLSingleSelection = function testGetHTMLSingleSelection(test) { - let selection = require("selection"); - primeTestCase(HTML_SINGLE, test, function(window, test) { - selectAllDivs(window); - test.assertEqual(selection.html, DIV1, "get html selection works"); - }); - - test.waitUntilDone(5000); -}; - -/* Myk's comments: This is fine. However, it reminds me to figure out and - specify whether iteration is ordered. If so, we'll want to change this - test in the future to test that the discontiguous selections are returned in - the appropriate order. In the meantime, add a comment to that effect here */ -exports.testGetHTMLMultipleSelection = - function testGetHTMLMultipleSelection(test) { - let selection = require("selection"); - primeTestCase(HTML_MULTIPLE, test, function(window, test) { - selectAllDivs(window); - let assertions = false; - for each (let i in selection) { - test.assertEqual(true, [DIV1, DIV2].some(function(t) t == i.html), - "get multiple selection html works"); - assertions = true; - } - // Ensure we ran at least one assertEqual() - test.assert(assertions, "No assertions were called"); - }); - - test.waitUntilDone(5000); -}; - -exports.testGetHTMLNull = function testGetHTMLNull(test) { - let selection = require("selection"); - primeTestCase(HTML_SINGLE, test, function(window, test) { - test.assertEqual(selection.html, null, "get html null works"); - }); - - test.waitUntilDone(5000); -}; - -exports.testGetHTMLWeird = function testGetHTMLWeird(test) { - let selection = require("selection"); - // If the getter is used when there are contiguous selections, the first - // selection should be returned - primeTestCase(HTML_MULTIPLE, test, function(window, test) { - selectAllDivs(window); - test.assertEqual(selection.html, DIV1, "get html weird works"); - }); - - test.waitUntilDone(5000); -}; - -exports.testGetHTMLNullInTextareaSelection = - function testGetHTMLNullInTextareaSelection(test) { - let selection = require("selection"); - - primeTestCase(TEXT_FIELD, test, function(window, test) { - selectTextarea(window); - - test.assertEqual(selection.html, null, "get html null in textarea works") - }); - - test.waitUntilDone(5000); -}; - -const REPLACEMENT_HTML = "<b>Lorem ipsum dolor sit amet</b>"; - -exports.testSetHTMLSelection = function testSetHTMLSelection(test) { - let selection = require("selection"); - primeTestCase(HTML_SINGLE, test, function(window, test) { - selectAllDivs(window); - selection.html = REPLACEMENT_HTML; - test.assertEqual(selection.html, "<span>" + REPLACEMENT_HTML + - "</span>", "selection html works"); - }); - - test.waitUntilDone(5000); -}; - -exports.testSetHTMLException = function testSetHTMLException(test) { - let selection = require("selection"); - primeTestCase(HTML_SINGLE, test, function(window, test) { - try { - selection.html = REPLACEMENT_HTML; - test.fail("set HTML throws when there's no selection."); - } - catch (e) { - test.pass("set HTML throws when there's no selection."); - } - }); - - test.waitUntilDone(5000); -}; - -const TEXT1 = "foo"; -const TEXT2 = "noodles"; -const TEXT_MULTIPLE = "<html><body><div>" + TEXT1 + "</div><div>" + TEXT2 + - "</div></body></html>"; -const TEXT_SINGLE = "<html><body><div>" + TEXT1 + "</div></body></html>"; -const TEXT_FIELD = "<html><body><textarea>" + TEXT1 + "</textarea></body></html>"; - -// Text tests - -exports.testSetHTMLinTextareaSelection = - function testSetHTMLinTextareaSelection(test) { - let selection = require("selection"); - - primeTestCase(TEXT_FIELD, test, function(window, test) { - selectTextarea(window); - - // HTML string is set as plain text in textareas, that's because - // `selection.html` and `selection.text` are basically aliases when a - // value is set. See bug 677269 - selection.html = REPLACEMENT_HTML; - - test.assertEqual(selection.text, REPLACEMENT_HTML, - "set selection html in textarea works"); - }); - - test.waitUntilDone(5000); -}; - -exports.testGetTextSingleSelection = - function testGetTextSingleSelection(test) { - let selection = require("selection"); - primeTestCase(TEXT_SINGLE, test, function(window, test) { - selectAllDivs(window); - test.assertEqual(selection.text, TEXT1, "get text selection works"); - }); - - test.waitUntilDone(5000); -}; - -exports.testGetTextMultipleSelection = - function testGetTextMultipleSelection(test) { - let selection = require("selection"); - primeTestCase(TEXT_MULTIPLE, test, function(window, test) { - selectAllDivs(window); - let assertions = false; - for each (let i in selection) { - test.assertEqual(true, [TEXT1, TEXT2].some(function(t) t == i.text), - "get multiple selection text works"); - assertions = true; - } - // Ensure we ran at least one assertEqual() - test.assert(assertions, "No assertions were called"); - }); - - test.waitUntilDone(5000); -}; - -exports.testGetTextNull = function testGetTextNull(test) { - let selection = require("selection"); - primeTestCase(TEXT_SINGLE, test, function(window, test) { - test.assertEqual(selection.text, null, "get text null works"); - }); - - test.waitUntilDone(5000); -}; - -exports.testGetTextWeird = function testGetTextWeird(test) { - let selection = require("selection"); - // If the getter is used when there are contiguous selections, the first - // selection should be returned - primeTestCase(TEXT_MULTIPLE, test, function(window, test) { - selectAllDivs(window); - test.assertEqual(selection.text, TEXT1, "get text weird works"); - }); - - test.waitUntilDone(5000); -}; - -exports.testGetTextNullInTextareaSelection = - function testGetTextInTextareaSelection(test) { - let selection = require("selection"); - - primeTestCase(TEXT_FIELD, test, function(window, test) { - test.assertEqual(selection.text, null, "get text null in textarea works") - }); - - test.waitUntilDone(5000); -}; - -exports.testGetTextInTextareaSelection = - function testGetTextInTextareaSelection(test) { - let selection = require("selection"); - - primeTestCase(TEXT_FIELD, test, function(window, test) { - selectTextarea(window); - - test.assertEqual(selection.text, TEXT1, "get text null in textarea works") - }); - - test.waitUntilDone(5000); -}; - -const REPLACEMENT_TEXT = "Lorem ipsum dolor sit amet"; - -exports.testSetTextSelection = function testSetTextSelection(test) { - let selection = require("selection"); - primeTestCase(TEXT_SINGLE, test, function(window, test) { - selectAllDivs(window); - selection.text = REPLACEMENT_TEXT; - test.assertEqual(selection.text, REPLACEMENT_TEXT, "selection text works"); - }); - - test.waitUntilDone(5000); -}; - -exports.testSetHTMLException = function testSetHTMLException(test) { - let selection = require("selection"); - primeTestCase(TEXT_SINGLE, test, function(window, test) { - try { - selection.text = REPLACEMENT_TEXT; - test.fail("set HTML throws when there's no selection."); - } - catch (e) { - test.pass("set HTML throws when there's no selection."); - } - }); - - test.waitUntilDone(5000); -}; - -exports.testSetTextInTextareaSelection = - function testSetTextInTextareaSelection(test) { - let selection = require("selection"); - - primeTestCase(TEXT_FIELD, test, function(window, test) { - selectTextarea(window); - - selection.text = REPLACEMENT_TEXT; - - test.assertEqual(selection.text, REPLACEMENT_TEXT, - "set selection text in textarea works"); - }); - - test.waitUntilDone(5000); -}; - -// Iterator tests - -exports.testIterator = function testIterator(test) { - let selection = require("selection"); - let selectionCount = 0; - primeTestCase(TEXT_MULTIPLE, test, function(window, test) { - selectAllDivs(window); - for each (let i in selection) - selectionCount++; - test.assertEqual(2, selectionCount, "iterator works."); - }); - - test.waitUntilDone(5000); -}; - -exports.testIteratorWithTextareaSelection = - function testIteratorWithTextareaSelection(test) { - let selection = require("selection"); - let selectionCount = 0; - - primeTestCase(TEXT_FIELD, test, function(window, test) { - selectTextarea(window); - - for each (let i in selection) - selectionCount++; - - test.assertEqual(1, selectionCount, "iterator works in textarea."); - }); - - test.waitUntilDone(5000); -}; - -/* onSelect tests */ - -/* -function sendSelectionSetEvent(window) { - const Ci = Components.interfaces; - let utils = window.QueryInterface(Ci.nsIInterfaceRequestor). - getInterface(Ci.nsIDOMWindowUtils); - if (!utils.sendSelectionSetEvent(0, 1, false)) - dump("**** sendSelectionSetEvent did not select anything\n"); - else - dump("**** sendSelectionSetEvent succeeded\n"); -} - -// testOnSelect() requires nsIDOMWindowUtils, which is only available in -// Firefox 3.7+. -exports.testOnSelect = function testOnSelect(test) { - let selection = require("selection"); - let callbackCount = 0; - primeTestCase(TEXT_SINGLE, test, function(window, test) { - selection.onSelect = function() {callbackCount++}; - // Now simulate the user selecting stuff - sendSelectionSetEvent(window); - selection.text = REPLACEMENT_TEXT; - test.assertEqual(1, callbackCount, "onSelect text listener works."); - //test.pass(); - //test.done(); - }); - - test.waitUntilDone(5000); -}; - -// testOnSelectExceptionNoBubble() requires nsIDOMWindowUtils, which is only -// available in Firefox 3.7+. -exports.testOnSelectExceptionNoBubble = - function testOnSelectTextSelection(test) { - let selection = require("selection"); - primeTestCase(HTML_SINGLE, test, function(window, test) { - selection.onSelect = function() { - throw new Error("Exception thrown in testOnSelectExceptionNoBubble"); - }; - // Now simulate the user selecting stuff - sendSelectionSetEvent(window); - test.pass("onSelect catches exceptions."); - }); - - test.waitUntilDone(5000); -}; -*/ - -// If the module doesn't support the app we're being run in, require() will -// throw. In that case, remove all tests above from exports, and add one dummy -// test that passes. -try { - require("selection"); -} -catch (err) { - // This bug should be mentioned in the error message. - let bug = "https://bugzilla.mozilla.org/show_bug.cgi?id=560716"; - if (err.message.indexOf(bug) < 0) - throw err; - for (let [prop, val] in Iterator(exports)) { - if (/^test/.test(prop) && typeof(val) === "function") - delete exports[prop]; - } - exports.testAppNotSupported = function (test) { - test.pass("The selection module does not support this application."); - }; -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-simple-prefs.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-simple-prefs.js deleted file mode 100644 index 581eca1..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-simple-prefs.js +++ /dev/null @@ -1,180 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Erik Vold <erikvvold@gmail.com> (Original Author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - - -const { Loader } = require("./helpers"); -const setTimeout = require("timers").setTimeout; -const notify = require("observer-service").notify; -const { jetpackID } = require("@packaging"); - -exports.testSetGetBool = function(test) { - test.waitUntilDone(); - - let loader = Loader(module); - let sp = loader.require("simple-prefs").prefs; - - test.assertEqual(sp.test, undefined, "Value should not exist"); - sp.test = true; - test.assert(sp.test, "Value read should be the value previously set"); - - loader.unload(); - test.done(); -}; - -exports.testSetGetInt = function(test) { - test.waitUntilDone(); - - // Load the module once, set a value. - let loader = Loader(module); - let sp = loader.require("simple-prefs").prefs; - - test.assertEqual(sp["test-int"], undefined, "Value should not exist"); - sp["test-int"] = 1; - test.assertEqual(sp["test-int"], 1, "Value read should be the value previously set"); - - loader.unload(); - test.done(); -}; - -exports.testSetComplex = function(test) { - test.waitUntilDone(); - - let loader = Loader(module); - let sp = loader.require("simple-prefs").prefs; - - try { - sp["test-complex"] = {test: true}; - test.fail("Complex values are not allowed"); - } - catch (e) { - test.pass("Complex values are not allowed"); - } - - loader.unload(); - test.done(); -}; - -exports.testSetGetString = function(test) { - test.waitUntilDone(); - - let loader = Loader(module); - let sp = loader.require("simple-prefs").prefs; - - test.assertEqual(sp["test-string"], undefined, "Value should not exist"); - sp["test-string"] = "test"; - test.assertEqual(sp["test-string"], "test", "Value read should be the value previously set"); - - loader.unload(); - test.done(); -}; - -exports.testHasAndRemove = function(test) { - test.waitUntilDone(); - - let loader = Loader(module); - let sp = loader.require("simple-prefs").prefs; - - sp.test = true; - test.assert(("test" in sp), "Value exists"); - delete sp.test; - test.assertEqual(sp.test, undefined, "Value should be undefined"); - - loader.unload(); - test.done(); - -}; - -exports.testPrefListener = function(test) { - test.waitUntilDone(); - - let loader = Loader(module); - let sp = loader.require("simple-prefs"); - - let listener = function(prefName) { - test.assertEqual(prefName, "test-listen", "The prefs listener heard the right event"); - test.done(); - }; - - sp.on("test-listen", listener); - - sp.prefs["test-listen"] = true; - loader.unload(); -}; - -exports.testBtnListener = function(test) { - test.waitUntilDone(); - - let loader = Loader(module); - let sp = loader.require("simple-prefs"); - - sp.on("test-btn-listen", function() { - test.pass("Button press event was heard"); - test.done(); - }); - notify((jetpackID + "-cmdPressed"), "", "test-btn-listen"); - - loader.unload(); -}; - -exports.testPrefRemoveListener = function(test) { - test.waitUntilDone(); - - let loader = Loader(module); - let sp = loader.require("simple-prefs"); - let counter = 0; - - let listener = function() { - test.pass("The prefs listener was not removed yet"); - - if (++counter > 1) - test.fail("The prefs listener was not removed"); - - sp.removeListener("test-listen2", listener); - - sp.prefs["test-listen2"] = false; - - setTimeout(function() { - test.pass("The prefs listener was removed"); - loader.unload(); - test.done(); - }, 250); - }; - - sp.on("test-listen2", listener); - - sp.prefs["test-listen2"] = true; -}; diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-simple-storage.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-simple-storage.js deleted file mode 100644 index 95e4689..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-simple-storage.js +++ /dev/null @@ -1,346 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim:set ts=2 sw=2 sts=2 et filetype=javascript - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Drew Willcoxon <adw@mozilla.com> (Original Author) - * Irakli Gozalishvili <gozala@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -const file = require("file"); -const prefs = require("preferences-service"); - -const QUOTA_PREF = "extensions.addon-sdk.simple-storage.quota"; - -let {Cc,Ci} = require("chrome"); - -const { Loader } = require("./helpers"); -const options = require("@packaging"); - -let storeFile = Cc["@mozilla.org/file/directory_service;1"]. - getService(Ci.nsIProperties). - get("ProfD", Ci.nsIFile); -storeFile.append("jetpack"); -storeFile.append(options.jetpackID); -storeFile.append("simple-storage"); -storeFile.append("store.json"); -let storeFilename = storeFile.path; - -exports.testSetGet = function (test) { - test.waitUntilDone(); - - // Load the module once, set a value. - let loader = newLoader(test); - let ss = loader.require("simple-storage"); - manager(loader).jsonStore.onWrite = function (storage) { - test.assert(file.exists(storeFilename), "Store file should exist"); - - // Load the module again and make sure the value stuck. - loader = newLoader(test); - ss = loader.require("simple-storage"); - manager(loader).jsonStore.onWrite = function (storage) { - file.remove(storeFilename); - test.done(); - }; - test.assertEqual(ss.storage.foo, val, "Value should persist"); - loader.unload(); - }; - let val = "foo"; - ss.storage.foo = val; - test.assertEqual(ss.storage.foo, val, "Value read should be value set"); - loader.unload(); -}; - -exports.testSetGetRootArray = function (test) { - setGetRoot(test, [1, 2, 3], function (arr1, arr2) { - if (arr1.length !== arr2.length) - return false; - for (let i = 0; i < arr1.length; i++) { - if (arr1[i] !== arr2[i]) - return false; - } - return true; - }); -}; - -exports.testSetGetRootBool = function (test) { - setGetRoot(test, true); -}; - -exports.testSetGetRootFunction = function (test) { - setGetRootError(test, function () {}, - "Setting storage to a function should fail"); -}; - -exports.testSetGetRootNull = function (test) { - setGetRoot(test, null); -}; - -exports.testSetGetRootNumber = function (test) { - setGetRoot(test, 3.14); -}; - -exports.testSetGetRootObject = function (test) { - setGetRoot(test, { foo: 1, bar: 2 }, function (obj1, obj2) { - for (let [prop, val] in Iterator(obj1)) { - if (!(prop in obj2) || obj2[prop] !== val) - return false; - } - for (let [prop, val] in Iterator(obj2)) { - if (!(prop in obj1) || obj1[prop] !== val) - return false; - } - return true; - }); -}; - -exports.testSetGetRootString = function (test) { - setGetRoot(test, "sho' 'nuff"); -}; - -exports.testSetGetRootUndefined = function (test) { - setGetRootError(test, undefined, "Setting storage to undefined should fail"); -}; - -exports.testEmpty = function (test) { - let loader = newLoader(test); - let ss = loader.require("simple-storage"); - loader.unload(); - test.assert(!file.exists(storeFilename), "Store file should not exist"); -}; - -exports.testMalformed = function (test) { - let stream = file.open(storeFilename, "w"); - stream.write("i'm not json"); - stream.close(); - let loader = newLoader(test); - let ss = loader.require("simple-storage"); - let empty = true; - for (let key in ss.storage) { - empty = false; - break; - } - test.assert(empty, "Malformed storage should cause root to be empty"); - loader.unload(); -}; - -// Go over quota and handle it by listener. -exports.testQuotaExceededHandle = function (test) { - test.waitUntilDone(); - prefs.set(QUOTA_PREF, 18); - - let loader = newLoader(test); - let ss = loader.require("simple-storage"); - ss.on("OverQuota", function () { - test.pass("OverQuota was emitted as expected"); - test.assertEqual(this, ss, "`this` should be simple storage"); - ss.storage = { x: 4, y: 5 }; - - manager(loader).jsonStore.onWrite = function () { - loader = newLoader(test); - ss = loader.require("simple-storage"); - let numProps = 0; - for (let prop in ss.storage) - numProps++; - test.assert(numProps, 2, - "Store should contain 2 values: " + ss.storage.toSource()); - test.assertEqual(ss.storage.x, 4, "x value should be correct"); - test.assertEqual(ss.storage.y, 5, "y value should be correct"); - manager(loader).jsonStore.onWrite = function (storage) { - prefs.reset(QUOTA_PREF); - test.done(); - }; - loader.unload(); - }; - loader.unload(); - }); - // This will be JSON.stringify()ed to: {"a":1,"b":2,"c":3} (19 bytes) - ss.storage = { a: 1, b: 2, c: 3 }; - manager(loader).jsonStore.write(); -}; - -// Go over quota but don't handle it. The last good state should still persist. -exports.testQuotaExceededNoHandle = function (test) { - test.waitUntilDone(); - prefs.set(QUOTA_PREF, 5); - - let loader = newLoader(test); - let ss = loader.require("simple-storage"); - - manager(loader).jsonStore.onWrite = function (storage) { - loader = newLoader(test); - ss = loader.require("simple-storage"); - test.assertEqual(ss.storage, val, - "Value should have persisted: " + ss.storage); - ss.storage = "some very long string that is very long"; - ss.on("OverQuota", function () { - test.pass("OverQuota emitted as expected"); - manager(loader).jsonStore.onWrite = function () { - test.fail("Over-quota value should not have been written"); - }; - loader.unload(); - - loader = newLoader(test); - ss = loader.require("simple-storage"); - test.assertEqual(ss.storage, val, - "Over-quota value should not have been written, " + - "old value should have persisted: " + ss.storage); - loader.unload(); - prefs.reset(QUOTA_PREF); - test.done(); - }); - manager(loader).jsonStore.write(); - }; - - let val = "foo"; - ss.storage = val; - loader.unload(); -}; - -exports.testQuotaUsage = function (test) { - test.waitUntilDone(); - - let quota = 21; - prefs.set(QUOTA_PREF, quota); - - let loader = newLoader(test); - let ss = loader.require("simple-storage"); - - // {"a":1} (7 bytes) - ss.storage = { a: 1 }; - test.assertEqual(ss.quotaUsage, 7 / quota, "quotaUsage should be correct"); - - // {"a":1,"bb":2} (14 bytes) - ss.storage = { a: 1, bb: 2 }; - test.assertEqual(ss.quotaUsage, 14 / quota, "quotaUsage should be correct"); - - // {"a":1,"bb":2,"cc":3} (21 bytes) - ss.storage = { a: 1, bb: 2, cc: 3 }; - test.assertEqual(ss.quotaUsage, 21 / quota, "quotaUsage should be correct"); - - manager(loader).jsonStore.onWrite = function () { - prefs.reset(QUOTA_PREF); - test.done(); - }; - loader.unload(); -}; - -exports.testUninstall = function (test) { - test.waitUntilDone(); - let loader = newLoader(test); - let ss = loader.require("simple-storage"); - manager(loader).jsonStore.onWrite = function () { - test.assert(file.exists(storeFilename), "Store file should exist"); - - loader = newLoader(test); - ss = loader.require("simple-storage"); - loader.unload("uninstall"); - test.assert(!file.exists(storeFilename), "Store file should be removed"); - test.done(); - }; - ss.storage.foo = "foo"; - loader.unload(); -}; - -exports.testSetNoSetRead = function (test) { - test.waitUntilDone(); - - // Load the module, set a value. - let loader = newLoader(test); - let ss = loader.require("simple-storage"); - manager(loader).jsonStore.onWrite = function (storage) { - test.assert(file.exists(storeFilename), "Store file should exist"); - - // Load the module again but don't access ss.storage. - loader = newLoader(test); - ss = loader.require("simple-storage"); - manager(loader).jsonStore.onWrite = function (storage) { - test.fail("Nothing should be written since `storage` was not accessed."); - }; - loader.unload(); - - // Load the module a third time and make sure the value stuck. - loader = newLoader(test); - ss = loader.require("simple-storage"); - manager(loader).jsonStore.onWrite = function (storage) { - file.remove(storeFilename); - test.done(); - }; - test.assertEqual(ss.storage.foo, val, "Value should persist"); - loader.unload(); - }; - let val = "foo"; - ss.storage.foo = val; - test.assertEqual(ss.storage.foo, val, "Value read should be value set"); - loader.unload(); -}; - -function manager(loader) loader.sandbox("simple-storage").manager; - -function newLoader() Loader(module); - -function setGetRoot(test, val, compare) { - test.waitUntilDone(); - - compare = compare || function (a, b) a === b; - - // Load the module once, set a value. - let loader = newLoader(test); - let ss = loader.require("simple-storage"); - manager(loader).jsonStore.onWrite = function () { - test.assert(file.exists(storeFilename), "Store file should exist"); - - // Load the module again and make sure the value stuck. - loader = newLoader(test); - ss = loader.require("simple-storage"); - manager(loader).jsonStore.onWrite = function () { - file.remove(storeFilename); - test.done(); - }; - test.assert(compare(ss.storage, val), "Value should persist"); - loader.unload(); - }; - ss.storage = val; - test.assert(compare(ss.storage, val), "Value read should be value set"); - loader.unload(); -} - -function setGetRootError(test, val, msg) { - let pred = "storage must be one of the following types: " + - "array, boolean, null, number, object, string"; - let loader = newLoader(test); - let ss = loader.require("simple-storage"); - test.assertRaises(function () ss.storage = val, pred, msg); - loader.unload(); -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-tabs.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-tabs.js deleted file mode 100644 index ae98312..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-tabs.js +++ /dev/null @@ -1,905 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Dietrich Ayala <dietrich@mozilla.com> (Original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -"use strict"; - -var {Cc,Ci} = require("chrome"); -const { Loader } = require("./helpers"); - -// test tab.activeTab getter -exports.testActiveTab_getter = function(test) { - test.waitUntilDone(); - - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - - let url = "data:text/html,<html><head><title>foo</title></head></html>"; - require("tab-browser").addTab( - url, - { - onLoad: function(e) { - test.assert(tabs.activeTab); - test.assertEqual(tabs.activeTab.url, url); - test.assertEqual(tabs.activeTab.title, "foo"); - closeBrowserWindow(window, function() test.done()); - } - } - ); - }); -}; - -// test 'BrowserWindow' instance creation on tab 'activate' event -// See bug 648244: there was a infinite loop. -exports.testBrowserWindowCreationOnActivate = function(test) { - test.waitUntilDone(); - - let windows = require("windows").browserWindows; - let tabs = require("tabs"); - - let gotActivate = false; - - tabs.once('activate', function onActivate(eventTab) { - test.assert(windows.activeWindow, "Is able to fetch activeWindow"); - gotActivate = true; - }); - - openBrowserWindow(function(window, browser) { - test.assert(gotActivate, "Received activate event before openBrowserWindow's callback is called"); - closeBrowserWindow(window, function () test.done()); - }); -} - -// test tab.activeTab setter -exports.testActiveTab_setter = function(test) { - test.waitUntilDone(); - - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - let url = "data:text/html,<html><head><title>foo</title></head></html>"; - - tabs.on('ready', function onReady(tab) { - tabs.removeListener('ready', onReady); - test.assertEqual(tabs.activeTab.url, "about:blank", "activeTab url has not changed"); - test.assertEqual(tab.url, url, "url of new background tab matches"); - tabs.on('activate', function onActivate(eventTab) { - tabs.removeListener('activate', onActivate); - test.assertEqual(tabs.activeTab.url, url, "url after activeTab setter matches"); - test.assertEqual(eventTab, tab, "event argument is the activated tab"); - test.assertEqual(eventTab, tabs.activeTab, "the tab is the active one"); - closeBrowserWindow(window, function() test.done()); - }); - tab.activate(); - }) - - tabs.open({ - url: url, - inBackground: true - }); - }); -}; - -exports.testAutomaticDestroy = function(test) { - test.waitUntilDone(); - - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - - // Create a second tab instance that we will destroy - let called = false; - - let loader = Loader(module); - let tabs2 = loader.require("tabs"); - tabs2.on('open', function onOpen(tab) { - called = true; - }); - - loader.unload(); - - // Fire a tab event an ensure that this destroyed tab is inactive - tabs.once('open', function () { - require("timer").setTimeout(function () { - test.assert(!called, "Unloaded tab module is destroyed and inactive"); - closeBrowserWindow(window, function() test.done()); - }, 0); - }); - - tabs.open("data:text/html,foo"); - - }); -}; - -// test tab properties -exports.testTabProperties = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs= require("tabs"); - let url = "data:text/html,<html><head><title>foo</title></head><body>foo</body></html>"; - tabs.open({ - url: url, - onReady: function(tab) { - test.assertEqual(tab.title, "foo", "title of the new tab matches"); - test.assertEqual(tab.url, url, "URL of the new tab matches"); - test.assert(tab.favicon, "favicon of the new tab is not empty"); - test.assertEqual(tab.style, null, "style of the new tab matches"); - test.assertEqual(tab.index, 1, "index of the new tab matches"); - test.assertNotEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches"); - closeBrowserWindow(window, function() test.done()); - } - }); - }); -}; - -// test tabs iterator and length property -exports.testTabsIteratorAndLength = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - let startCount = 0; - for each (let t in tabs) startCount++; - test.assertEqual(startCount, tabs.length, "length property is correct"); - let url = "data:text/html,default"; - tabs.open(url); - tabs.open(url); - tabs.open({ - url: url, - onOpen: function(tab) { - let count = 0; - for each (let t in tabs) count++; - test.assertEqual(count, startCount + 3, "iterated tab count matches"); - test.assertEqual(startCount + 3, tabs.length, "iterated tab count matches length property"); - closeBrowserWindow(window, function() test.done()); - } - }); - }); -}; - -// test tab.url setter -exports.testTabLocation = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - let url1 = "data:text/html,foo"; - let url2 = "data:text/html,bar"; - - tabs.on('ready', function onReady(tab) { - if (tab.url != url2) - return; - tabs.removeListener('ready', onReady); - test.pass("tab.load() loaded the correct url"); - closeBrowserWindow(window, function() test.done()); - }); - - tabs.open({ - url: url1, - onOpen: function(tab) { - tab.url = url2 - } - }); - }); -}; - -// test tab.close() -exports.testTabClose = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - let url = "data:text/html,foo"; - - test.assertNotEqual(tabs.activeTab.url, url, "tab is now the active tab"); - tabs.on('ready', function onReady(tab) { - tabs.removeListener('ready', onReady); - test.assertEqual(tabs.activeTab.url, tab.url, "tab is now the active tab"); - tab.close(function() { - closeBrowserWindow(window, function() test.done()); - }); - test.assertNotEqual(tabs.activeTab.url, url, "tab is no longer the active tab"); - }); - - tabs.open(url); - }); -}; - -// test tab.reload() -exports.testTabReload = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - let url = "data:text/html,<!doctype%20html><title></title>"; - - tabs.open({ url: url, onReady: function onReady(tab) { - tab.removeListener("ready", onReady); - - browser.addEventListener( - "load", - function onLoad() { - browser.removeEventListener("load", onLoad, true); - - browser.addEventListener( - "load", - function onReload() { - browser.removeEventListener("load", onReload, true); - test.pass("the tab was loaded again"); - test.assertEqual(tab.url, url, "the tab has the same URL"); - closeBrowserWindow(window, function() test.done()); - }, - true - ); - tab.reload(); - }, - true - ); - }}); - }); -}; - -// test tab.move() -exports.testTabMove = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - let url = "data:text/html,foo"; - - tabs.open({ - url: url, - onOpen: function(tab) { - test.assertEqual(tab.index, 1, "tab index before move matches"); - tab.index = 0; - test.assertEqual(tab.index, 0, "tab index after move matches"); - closeBrowserWindow(window, function() test.done()); - } - }); - }); -}; - -// open tab with default options -exports.testOpen = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - let url = "data:text/html,default"; - tabs.open({ - url: url, - onReady: function(tab) { - test.assertEqual(tab.url, url, "URL of the new tab matches"); - test.assertEqual(window.content.location, url, "URL of active tab in the current window matches"); - closeBrowserWindow(window, function() test.done()); - } - }); - }); -}; - -// open pinned tab -exports.testOpenPinned = function(test) { - const xulApp = require("xul-app"); - if (xulApp.versionInRange(xulApp.platformVersion, "2.0b2", "*")) { - // test tab pinning - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - let url = "data:text/html,default"; - tabs.open({ - url: url, - isPinned: true, - onOpen: function(tab) { - test.assertEqual(tab.isPinned, true, "The new tab is pinned"); - closeBrowserWindow(window, function() test.done()); - } - }); - }); - } - else { - test.pass("Pinned tabs are not supported in this application."); - } -}; - -// pin/unpin opened tab -exports.testPinUnpin = function(test) { - const xulApp = require("xul-app"); - if (xulApp.versionInRange(xulApp.platformVersion, "2.0b2", "*")) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - let url = "data:text/html,default"; - tabs.open({ - url: url, - onOpen: function(tab) { - tab.pin(); - test.assertEqual(tab.isPinned, true, "The tab was pinned correctly"); - tab.unpin(); - test.assertEqual(tab.isPinned, false, "The tab was unpinned correctly"); - closeBrowserWindow(window, function() test.done()); - } - }); - }); - } - else { - test.pass("Pinned tabs are not supported in this application."); - } -}; - -// open tab in background -exports.testInBackground = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - let activeUrl = tabs.activeTab.url; - let url = "data:text/html,background"; - test.assertEqual(activeWindow, window, "activeWindow matches this window"); - tabs.on('ready', function onReady(tab) { - tabs.removeListener('ready', onReady); - test.assertEqual(tabs.activeTab.url, activeUrl, "URL of active tab has not changed"); - test.assertEqual(tab.url, url, "URL of the new background tab matches"); - test.assertEqual(activeWindow, window, "a new window was not opened"); - test.assertNotEqual(tabs.activeTab.url, url, "URL of active tab is not the new URL"); - closeBrowserWindow(window, function() test.done()); - }); - tabs.open({ - url: url, - inBackground: true - }); - }); -}; - -// open tab in new window -exports.testOpenInNewWindow = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - - let cache = []; - let windowUtils = require("window-utils"); - let wt = new windowUtils.WindowTracker({ - onTrack: function(win) { - cache.push(win); - }, - onUntrack: function(win) { - cache.splice(cache.indexOf(win), 1) - } - }); - let startWindowCount = cache.length; - - let url = "data:text/html,newwindow"; - tabs.open({ - url: url, - inNewWindow: true, - onReady: function(tab) { - let newWindow = cache[cache.length - 1]; - test.assertEqual(cache.length, startWindowCount + 1, "a new window was opened"); - test.assertEqual(activeWindow, newWindow, "new window is active"); - test.assertEqual(tab.url, url, "URL of the new tab matches"); - test.assertEqual(newWindow.content.location, url, "URL of new tab in new window matches"); - test.assertEqual(tabs.activeTab.url, url, "URL of activeTab matches"); - for (var i in cache) cache[i] = null; - wt.unload(); - closeBrowserWindow(newWindow, function() { - closeBrowserWindow(window, function() test.done()); - }); - } - }); - }); -}; - -// onOpen event handler -exports.testTabsEvent_onOpen = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - var tabs = require("tabs"); - let url = "data:text/html,1"; - let eventCount = 0; - - // add listener via property assignment - function listener1(tab) { - eventCount++; - }; - tabs.on('open', listener1); - - // add listener via collection add - tabs.on('open', function listener2(tab) { - test.assertEqual(++eventCount, 2, "both listeners notified"); - tabs.removeListener('open', listener1); - tabs.removeListener('open', listener2); - closeBrowserWindow(window, function() test.done()); - }); - - tabs.open(url); - }); -}; - -// onClose event handler -exports.testTabsEvent_onClose = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - var tabs = require("tabs"); - let url = "data:text/html,onclose"; - let eventCount = 0; - - // add listener via property assignment - function listener1(tab) { - eventCount++; - } - tabs.on('close', listener1); - - // add listener via collection add - tabs.on('close', function listener2(tab) { - test.assertEqual(++eventCount, 2, "both listeners notified"); - tabs.removeListener('close', listener1); - tabs.removeListener('close', listener2); - closeBrowserWindow(window, function() test.done()); - }); - - tabs.on('ready', function onReady(tab) { - tabs.removeListener('ready', onReady); - tab.close(); - }); - - tabs.open(url); - }); -}; - -// onClose event handler when a window is closed -exports.testTabsEvent_onCloseWindow = function(test) { - test.waitUntilDone(); - - openBrowserWindow(function(window, browser) { - var tabs = require("tabs"); - - let closeCount = 0, individualCloseCount = 0; - function listener() { - closeCount++; - } - tabs.on('close', listener); - - // One tab is already open with the window - let openTabs = 1; - function testCasePossiblyLoaded() { - if (++openTabs == 4) { - beginCloseWindow(); - } - } - - tabs.open({ - url: "data:text/html,tab2", - onOpen: function() testCasePossiblyLoaded(), - onClose: function() individualCloseCount++ - }); - - tabs.open({ - url: "data:text/html,tab3", - onOpen: function() testCasePossiblyLoaded(), - onClose: function() individualCloseCount++ - }); - - tabs.open({ - url: "data:text/html,tab4", - onOpen: function() testCasePossiblyLoaded(), - onClose: function() individualCloseCount++ - }); - - function beginCloseWindow() { - closeBrowserWindow(window, function testFinished() { - tabs.removeListener("close", listener); - - test.assertEqual(closeCount, 4, "Correct number of close events received"); - test.assertEqual(individualCloseCount, 3, - "Each tab with an attached onClose listener received a close " + - "event when the window was closed"); - - test.done(); - }); - } - - }); -} - -// onReady event handler -exports.testTabsEvent_onReady = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - var tabs = require("tabs"); - let url = "data:text/html,onready"; - let eventCount = 0; - - // add listener via property assignment - function listener1(tab) { - eventCount++; - }; - tabs.on('ready', listener1); - - // add listener via collection add - tabs.on('ready', function listener2(tab) { - test.assertEqual(++eventCount, 2, "both listeners notified"); - tabs.removeListener('ready', listener1); - tabs.removeListener('ready', listener2); - closeBrowserWindow(window, function() test.done()); - }); - - tabs.open(url); - }); -}; - -// onActivate event handler -exports.testTabsEvent_onActivate = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - var tabs = require("tabs"); - let url = "data:text/html,onactivate"; - let eventCount = 0; - - // add listener via property assignment - function listener1(tab) { - eventCount++; - }; - tabs.on('activate', listener1); - - // add listener via collection add - tabs.on('activate', function listener2(tab) { - test.assertEqual(++eventCount, 2, "both listeners notified"); - tabs.removeListener('activate', listener1); - tabs.removeListener('activate', listener2); - closeBrowserWindow(window, function() test.done()); - }); - - tabs.open(url); - }); -}; - -// onDeactivate event handler -exports.testTabsEvent_onDeactivate = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - var tabs = require("tabs"); - let url = "data:text/html,ondeactivate"; - let eventCount = 0; - - // add listener via property assignment - function listener1(tab) { - eventCount++; - }; - tabs.on('deactivate', listener1); - - // add listener via collection add - tabs.on('deactivate', function listener2(tab) { - test.assertEqual(++eventCount, 2, "both listeners notified"); - tabs.removeListener('deactivate', listener1); - tabs.removeListener('deactivate', listener2); - closeBrowserWindow(window, function() test.done()); - }); - - tabs.on('open', function onOpen(tab) { - tabs.removeListener('open', onOpen); - tabs.open("data:text/html,foo"); - }); - - tabs.open(url); - }); -}; - -// per-tab event handlers -exports.testPerTabEvents = function(test) { - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - var tabs = require("tabs"); - let eventCount = 0; - - tabs.open({ - url: "data:text/html,foo", - onOpen: function(tab) { - // add listener via property assignment - function listener1() { - eventCount++; - }; - tab.on('ready', listener1); - - // add listener via collection add - tab.on('ready', function listener2() { - test.assertEqual(eventCount, 1, "both listeners notified"); - tab.removeListener('ready', listener1); - tab.removeListener('ready', listener2); - closeBrowserWindow(window, function() test.done()); - }); - } - }); - }); -}; - -exports.testAttachOnOpen = function (test) { - // Take care that attach has to be called on tab ready and not on tab open. - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - - tabs.open({ - url: "data:text/html,foobar", - onOpen: function (tab) { - let worker = tab.attach({ - contentScript: 'self.postMessage(document.location.href); ', - onMessage: function (msg) { - test.assertEqual(msg, "about:blank", - "Worker document url is about:blank on open"); - worker.destroy(); - closeBrowserWindow(window, function() test.done()); - } - }); - } - }); - - }); -} - -exports.testAttachOnMultipleDocuments = function (test) { - // Example of attach that process multiple tab documents - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - let firstLocation = "data:text/html,foobar"; - let secondLocation = "data:text/html,bar"; - let thirdLocation = "data:text/html,fox"; - let onReadyCount = 0; - let worker1 = null; - let worker2 = null; - let detachEventCount = 0; - tabs.open({ - url: firstLocation, - onReady: function (tab) { - onReadyCount++; - if (onReadyCount == 1) { - worker1 = tab.attach({ - contentScript: 'self.on("message", ' + - ' function () self.postMessage(document.location.href)' + - ');', - onMessage: function (msg) { - test.assertEqual(msg, firstLocation, - "Worker url is equal to the 1st document"); - tab.url = secondLocation; - }, - onDetach: function () { - detachEventCount++; - test.pass("Got worker1 detach event"); - test.assertRaises(function () { - worker1.postMessage("ex-1"); - }, - /The page has been destroyed/, - "postMessage throw because worker1 is destroyed"); - checkEnd(); - } - }); - worker1.postMessage("new-doc-1"); - } - else if (onReadyCount == 2) { - - worker2 = tab.attach({ - contentScript: 'self.on("message", ' + - ' function () self.postMessage(document.location.href)' + - ');', - onMessage: function (msg) { - test.assertEqual(msg, secondLocation, - "Worker url is equal to the 2nd document"); - tab.url = thirdLocation; - }, - onDetach: function () { - detachEventCount++; - test.pass("Got worker2 detach event"); - test.assertRaises(function () { - worker2.postMessage("ex-2"); - }, - /The page has been destroyed/, - "postMessage throw because worker2 is destroyed"); - checkEnd(); - } - }); - worker2.postMessage("new-doc-2"); - } - else if (onReadyCount == 3) { - - tab.close(); - - } - - } - }); - - function checkEnd() { - if (detachEventCount != 2) - return; - - test.pass("Got all detach events"); - - closeBrowserWindow(window, function() test.done()); - } - - }); -} - - -exports.testAttachWrappers = function (test) { - // Check that content script has access to wrapped values by default - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - let document = "data:text/html,<script>var globalJSVar = true; " + - " document.getElementById = 3;</script>"; - let count = 0; - - tabs.open({ - url: document, - onReady: function (tab) { - let worker = tab.attach({ - contentScript: 'try {' + - ' self.postMessage(!("globalJSVar" in window));' + - ' self.postMessage(typeof window.globalJSVar == "undefined");' + - '} catch(e) {' + - ' self.postMessage(e.message);' + - '}', - onMessage: function (msg) { - test.assertEqual(msg, true, "Worker has wrapped objects ("+count+")"); - if (count++ == 1) - closeBrowserWindow(window, function() test.done()); - } - }); - } - }); - - }); -} - -/* -// We do not offer unwrapped access to DOM since bug 601295 landed -// See 660780 to track progress of unwrap feature -exports.testAttachUnwrapped = function (test) { - // Check that content script has access to unwrapped values through unsafeWindow - test.waitUntilDone(); - openBrowserWindow(function(window, browser) { - let tabs = require("tabs"); - let document = "data:text/html,<script>var globalJSVar=true;</script>"; - let count = 0; - - tabs.open({ - url: document, - onReady: function (tab) { - let worker = tab.attach({ - contentScript: 'try {' + - ' self.postMessage(unsafeWindow.globalJSVar);' + - '} catch(e) {' + - ' self.postMessage(e.message);' + - '}', - onMessage: function (msg) { - test.assertEqual(msg, true, "Worker has access to javascript content globals ("+count+")"); - closeBrowserWindow(window, function() test.done()); - } - }); - } - }); - - }); -} -*/ - -exports['test window focus changes active tab'] = function(test) { - test.waitUntilDone(); - let win1 = openBrowserWindow(function() { - let win2 = openBrowserWindow(function() { - let tabs = require("tabs"); - tabs.on("activate", function onActivate() { - tabs.removeListener("activate", onActivate); - test.pass("activate was called on windows focus change."); - closeBrowserWindow(win1, function() { - closeBrowserWindow(win2, function() { test.done(); }); - }); - }); - win1.focus(); - }, "data:text/html,test window focus changes active tab</br><h1>Window #2"); - }, "data:text/html,test window focus changes active tab</br><h1>Window #1"); -}; - -exports['test ready event on new window tab'] = function(test) { - test.waitUntilDone(); - let uri = encodeURI("data:text/html,Waiting for ready event!"); - - require("tabs").on("ready", function onReady(tab) { - if (tab.url === uri) { - require("tabs").removeListener("ready", onReady); - test.pass("ready event was emitted"); - closeBrowserWindow(window, function() { - test.done(); - }); - } - }); - - let window = openBrowserWindow(function(){}, uri); -}; -/******************* helpers *********************/ - -// Helper for getting the active window -this.__defineGetter__("activeWindow", function activeWindow() { - return Cc["@mozilla.org/appshell/window-mediator;1"]. - getService(Ci.nsIWindowMediator). - getMostRecentWindow("navigator:browser"); -}); - -// Utility function to open a new browser window. -function openBrowserWindow(callback, url) { - let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"]. - getService(Ci.nsIWindowWatcher); - let urlString = Cc["@mozilla.org/supports-string;1"]. - createInstance(Ci.nsISupportsString); - urlString.data = url; - let window = ww.openWindow(null, "chrome://browser/content/browser.xul", - "_blank", "chrome,all,dialog=no", urlString); - - if (callback) { - window.addEventListener("load", function onLoad(event) { - if (event.target && event.target.defaultView == window) { - window.removeEventListener("load", onLoad, true); - let browsers = window.document.getElementsByTagName("tabbrowser"); - try { - require("timer").setTimeout(function () { - callback(window, browsers[0]); - }, 10); - } catch (e) { console.exception(e); } - } - }, true); - } - - return window; -} - -// Helper for calling code at window close -function closeBrowserWindow(window, callback) { - window.addEventListener("unload", function unload() { - window.removeEventListener("unload", unload, false); - callback(); - }, false); - window.close(); -} - -// If the module doesn't support the app we're being run in, require() will -// throw. In that case, remove all tests above from exports, and add one dummy -// test that passes. -try { - require("tabs"); -} -catch (err) { - // This bug should be mentioned in the error message. - let bug = "https://bugzilla.mozilla.org/show_bug.cgi?id=560716"; - if (err.message.indexOf(bug) < 0) - throw err; - for (let [prop, val] in Iterator(exports)) { - if (/^test/.test(prop) && typeof(val) === "function") - delete exports[prop]; - } - exports.testAppNotSupported = function (test) { - test.pass("the tabs module does not support this application."); - }; -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-timers.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-timers.js deleted file mode 100644 index 98ea613..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-timers.js +++ /dev/null @@ -1,44 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Shane Tomlinson <stomlinson@mozilla.com> (Original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -const timers = require("timers"); - -exports.testTimeout = function (test) { - test.waitUntilDone(); - timers.setTimeout(function () { - test.pass("timers.setTimeout works"); - test.done(); - }, 0); -} diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-widget.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-widget.js deleted file mode 100644 index a5ab83c..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-widget.js +++ /dev/null @@ -1,950 +0,0 @@ -const {Cc,Ci} = require("chrome"); -const { Loader } = require('./helpers'); - -exports.testConstructor = function(test) { - - const tabBrowser = require("tab-browser"); - - test.waitUntilDone(30000); - - const widgets = require("widget"); - const url = require("url"); - const windowUtils = require("window-utils"); - - let browserWindow = windowUtils.activeBrowserWindow; - let doc = browserWindow.document; - let AddonsMgrListener = browserWindow.AddonsMgrListener; - - function container() doc.getElementById("addon-bar"); - function widgetCount() container() ? container().getElementsByTagName("toolbaritem").length : 0; - let widgetStartCount = widgetCount(); - function widgetNode(index) container() ? container().getElementsByTagName("toolbaritem")[index] : null; - - // Test basic construct/destroy - AddonsMgrListener.onInstalling(); - let w = widgets.Widget({ id: "fooID", label: "foo", content: "bar" }); - AddonsMgrListener.onInstalled(); - test.assertEqual(widgetCount(), widgetStartCount + 1, "panel has correct number of child elements after widget construction"); - - // test widget height - test.assertEqual(widgetNode(0).firstChild.boxObject.height, 16, "widget has correct default height"); - - AddonsMgrListener.onUninstalling(); - w.destroy(); - AddonsMgrListener.onUninstalled(); - w.destroy(); - test.pass("Multiple destroys do not cause an error"); - test.assertEqual(widgetCount(), widgetStartCount, "panel has correct number of child elements after destroy"); - - // Test automatic widget destroy on unload - let loader = Loader(module); - let widgetsFromLoader = loader.require("widget"); - let widgetStartCount = widgetCount(); - let w = widgetsFromLoader.Widget({ id: "fooID", label: "foo", content: "bar" }); - test.assertEqual(widgetCount(), widgetStartCount + 1, "widget has been correctly added"); - loader.unload(); - test.assertEqual(widgetCount(), widgetStartCount, "widget has been destroyed on module unload"); - - // Test nothing - test.assertRaises( - function() widgets.Widget({}), - "The widget must have a non-empty label property.", - "throws on no properties"); - - // Test no label - test.assertRaises( - function() widgets.Widget({content: "foo"}), - "The widget must have a non-empty label property.", - "throws on no label"); - - // Test empty label - test.assertRaises( - function() widgets.Widget({label: "", content: "foo"}), - "The widget must have a non-empty label property.", - "throws on empty label"); - - // Test no content or image - test.assertRaises( - function() widgets.Widget({id: "fooID", label: "foo"}), - "No content or contentURL property found. Widgets must have one or the other.", - "throws on no content"); - - // Test empty content, no image - test.assertRaises( - function() widgets.Widget({id:"fooID", label: "foo", content: ""}), - "No content or contentURL property found. Widgets must have one or the other.", - "throws on empty content"); - - // Test empty image, no content - test.assertRaises( - function() widgets.Widget({id:"fooID", label: "foo", image: ""}), - "No content or contentURL property found. Widgets must have one or the other.", - "throws on empty content"); - - // Test empty content, empty image - test.assertRaises( - function() widgets.Widget({id:"fooID", label: "foo", content: "", image: ""}), - "No content or contentURL property found. Widgets must have one or the other.", - "throws on empty content"); - - // Test duplicated ID - let duplicateID = widgets.Widget({id: "foo", label: "foo", content: "bar"}); - test.assertRaises( - function() widgets.Widget({id: "foo", label: "bar", content: "bar"}), - /This widget ID is already used:/, - "throws on duplicated id"); - duplicateID.destroy(); - - // Test duplicate label, different ID - let w1 = widgets.Widget({id: "id1", label: "foo", content: "bar"}); - let w2 = widgets.Widget({id: "id2", label: "foo", content: "bar"}); - w1.destroy(); - w2.destroy(); - - // Test position restore on create/destroy/create - // Create 3 ordered widgets - let w1 = widgets.Widget({id: "first", label:"first", content: "bar"}); - let w2 = widgets.Widget({id: "second", label:"second", content: "bar"}); - let w3 = widgets.Widget({id: "third", label:"third", content: "bar"}); - // Remove the middle widget - test.assertEqual(widgetNode(1).getAttribute("label"), "second", "second widget is the second widget inserted"); - w2.destroy(); - test.assertEqual(widgetNode(1).getAttribute("label"), "third", "second widget is removed, so second widget is now the third one"); - w2 = widgets.Widget({id: "second", label:"second", content: "bar"}); - test.assertEqual(widgetNode(1).getAttribute("label"), "second", "second widget is created again, at the same location"); - // Cleanup this testcase - AddonsMgrListener.onUninstalling(); - w1.destroy(); - w2.destroy(); - w3.destroy(); - AddonsMgrListener.onUninstalled(); - - // Test concurrent widget module instances on addon-bar hiding - let loader = Loader(module); - let anotherWidgetsInstance = loader.require("widget"); - test.assert(container().collapsed, "UI is hidden when no widgets"); - AddonsMgrListener.onInstalling(); - let w1 = widgets.Widget({id: "foo", label: "foo", content: "bar"}); - // Ideally we would let AddonsMgrListener display the addon bar - // But, for now, addon bar is immediatly displayed by sdk code - // https://bugzilla.mozilla.org/show_bug.cgi?id=627484 - test.assert(!container().collapsed, "UI is already visible when we just added the widget"); - AddonsMgrListener.onInstalled(); - test.assert(!container().collapsed, "UI become visible when we notify AddonsMgrListener about end of addon installation"); - let w2 = anotherWidgetsInstance.Widget({id: "bar", label: "bar", content: "foo"}); - test.assert(!container().collapsed, "UI still visible when we add a second widget"); - AddonsMgrListener.onUninstalling(); - w1.destroy(); - AddonsMgrListener.onUninstalled(); - test.assert(!container().collapsed, "UI still visible when we remove one of two widgets"); - AddonsMgrListener.onUninstalling(); - w2.destroy(); - test.assert(!container().collapsed, "UI is still visible when we have removed all widget but still not called onUninstalled"); - AddonsMgrListener.onUninstalled(); - test.assert(container().collapsed, "UI is hidden when we have removed all widget and called onUninstalled"); - - // Helper for testing a single widget. - // Confirms proper addition and content setup. - function testSingleWidget(widgetOptions) { - // We have to display which test is being run, because here we do not - // use the regular test framework but rather a custom one that iterates - // the `tests` array. - console.info("executing: " + widgetOptions.id); - - let startCount = widgetCount(); - let widget = widgets.Widget(widgetOptions); - let node = widgetNode(startCount); - test.assert(node, "widget node at index"); - test.assertEqual(node.tagName, "toolbaritem", "widget element is correct"); - test.assertEqual(widget.width + "px", node.style.minWidth, "widget width is correct"); - test.assertEqual(widgetCount(), startCount + 1, "container has correct number of child elements"); - let content = node.firstElementChild; - test.assert(content, "found content"); - test.assertMatches(content.tagName, /iframe|image/, "content is iframe or image"); - return widget; - } - - // Array of widgets to test - // and a function to test them. - let tests = []; - function nextTest() { - test.assertEqual(widgetCount(), 0, "widget in last test property cleaned itself up"); - if (!tests.length) - test.done(); - else - require("timer").setTimeout(tests.shift(), 0); - } - function doneTest() nextTest(); - - // text widget - tests.push(function testTextWidget() testSingleWidget({ - id: "text", - label: "text widget", - content: "oh yeah", - contentScript: "self.postMessage(document.body.innerHTML);", - contentScriptWhen: "end", - onMessage: function (message) { - test.assertEqual(this.content, message, "content matches"); - this.destroy(); - doneTest(); - } - })); - - // html widget - tests.push(function testHTMLWidget() testSingleWidget({ - id: "html", - label: "html widget", - content: "<div>oh yeah</div>", - contentScript: "self.postMessage(document.body.innerHTML);", - contentScriptWhen: "end", - onMessage: function (message) { - test.assertEqual(this.content, message, "content matches"); - this.destroy(); - doneTest(); - } - })); - - // image url widget - tests.push(function testImageURLWidget() testSingleWidget({ - id: "image", - label: "image url widget", - contentURL: require("self").data.url("test.html"), - contentScript: "self.postMessage({title: document.title, " + - "tag: document.body.firstElementChild.tagName, " + - "content: document.body.firstElementChild.innerHTML});", - contentScriptWhen: "end", - onMessage: function (message) { - test.assertEqual(message.title, "foo", "title matches"); - test.assertEqual(message.tag, "P", "element matches"); - test.assertEqual(message.content, "bar", "element content matches"); - this.destroy(); - doneTest(); - } - })); - - // web uri widget - tests.push(function testWebURIWidget() testSingleWidget({ - id: "web", - label: "web uri widget", - contentURL: require("self").data.url("test.html"), - contentScript: "self.postMessage({title: document.title, " + - "tag: document.body.firstElementChild.tagName, " + - "content: document.body.firstElementChild.innerHTML});", - contentScriptWhen: "end", - onMessage: function (message) { - test.assertEqual(message.title, "foo", "title matches"); - test.assertEqual(message.tag, "P", "element matches"); - test.assertEqual(message.content, "bar", "element content matches"); - this.destroy(); - doneTest(); - } - })); - - // event: onclick + content - tests.push(function testOnclickEventContent() testSingleWidget({ - id: "click", - label: "click test widget - content", - content: "<div id='me'>foo</div>", - contentScript: "var evt = document.createEvent('HTMLEvents'); " + - "evt.initEvent('click', true, true ); " + - "document.getElementById('me').dispatchEvent(evt);", - contentScriptWhen: "end", - onClick: function() { - test.pass("onClick called"); - this.destroy(); - doneTest(); - } - })); - - // event: onmouseover + content - tests.push(function testOnmouseoverEventContent() testSingleWidget({ - id: "mouseover", - label: "mouseover test widget - content", - content: "<div id='me'>foo</div>", - contentScript: "var evt = document.createEvent('HTMLEvents'); " + - "evt.initEvent('mouseover', true, true ); " + - "document.getElementById('me').dispatchEvent(evt);", - contentScriptWhen: "end", - onMouseover: function() { - test.pass("onMouseover called"); - this.destroy(); - doneTest(); - } - })); - - // event: onmouseout + content - tests.push(function testOnmouseoutEventContent() testSingleWidget({ - id: "mouseout", - label: "mouseout test widget - content", - content: "<div id='me'>foo</div>", - contentScript: "var evt = document.createEvent('HTMLEvents'); " + - "evt.initEvent('mouseout', true, true ); " + - "document.getElementById('me').dispatchEvent(evt);", - contentScriptWhen: "end", - onMouseout: function() { - test.pass("onMouseout called"); - this.destroy(); - doneTest(); - } - })); - - // event: onclick + image - tests.push(function testOnclickEventImage() testSingleWidget({ - id: "click", - label: "click test widget - image", - contentURL: require("self").data.url("moz_favicon.ico"), - contentScript: "var evt = document.createEvent('HTMLEvents'); " + - "evt.initEvent('click', true, true ); " + - "document.body.firstElementChild.dispatchEvent(evt);", - contentScriptWhen: "end", - onClick: function() { - test.pass("onClick called"); - this.destroy(); - doneTest(); - } - })); - - // event: onmouseover + image - tests.push(function testOnmouseoverEventImage() testSingleWidget({ - id: "mouseover", - label: "mouseover test widget - image", - contentURL: require("self").data.url("moz_favicon.ico"), - contentScript: "var evt = document.createEvent('HTMLEvents'); " + - "evt.initEvent('mouseover', true, true ); " + - "document.body.firstElementChild.dispatchEvent(evt);", - contentScriptWhen: "end", - onMouseover: function() { - test.pass("onMouseover called"); - this.destroy(); - doneTest(); - } - })); - - // event: onmouseout + image - tests.push(function testOnmouseoutEventImage() testSingleWidget({ - id: "mouseout", - label: "mouseout test widget - image", - contentURL: require("self").data.url("moz_favicon.ico"), - contentScript: "var evt = document.createEvent('HTMLEvents'); " + - "evt.initEvent('mouseout', true, true ); " + - "document.body.firstElementChild.dispatchEvent(evt);", - contentScriptWhen: "end", - onMouseout: function() { - test.pass("onMouseout called"); - this.destroy(); - doneTest(); - } - })); - - // test multiple widgets - tests.push(function testMultipleWidgets() { - let w1 = widgets.Widget({id: "first", label: "first widget", content: "first content"}); - let w2 = widgets.Widget({id: "second", label: "second widget", content: "second content"}); - - w1.destroy(); - w2.destroy(); - - doneTest(); - }); - - // test updating widget content - let loads = 0; - tests.push(function testUpdatingWidgetContent() testSingleWidget({ - id: "content", - label: "content update test widget", - content: "<div id='me'>foo</div>", - contentScript: "self.postMessage(1)", - contentScriptWhen: "ready", - onMessage: function(message) { - if (!this.flag) { - this.content = "<div id='me'>bar</div>"; - this.flag = 1; - } - else { - test.assertEqual(this.content, "<div id='me'>bar</div>"); - this.destroy(); - doneTest(); - } - } - })); - - // test updating widget contentURL - let url1 = "data:text/html,<body>foodle</body>"; - let url2 = "data:text/html,<body>nistel</body>"; - - tests.push(function testUpdatingContentURL() testSingleWidget({ - id: "content", - label: "content update test widget", - contentURL: url1, - contentScript: "self.postMessage(document.location.href);", - contentScriptWhen: "end", - onMessage: function(message) { - if (!this.flag) { - test.assertEqual(this.contentURL.toString(), url1); - test.assertEqual(message, url1); - this.contentURL = url2; - this.flag = 1; - } - else { - test.assertEqual(this.contentURL.toString(), url2); - test.assertEqual(message, url2); - this.destroy(); - doneTest(); - } - } - })); - - // test tooltip - tests.push(function testTooltip() testSingleWidget({ - id: "text", - label: "text widget", - content: "oh yeah", - tooltip: "foo", - contentScript: "self.postMessage(1)", - contentScriptWhen: "ready", - onMessage: function(message) { - test.assertEqual(this.tooltip, "foo", "tooltip matches"); - this.destroy(); - doneTest(); - } - })); - - // test tooltip fallback to label - tests.push(function testTooltipFallback() testSingleWidget({ - id: "fallback", - label: "fallback", - content: "oh yeah", - contentScript: "self.postMessage(1)", - contentScriptWhen: "ready", - onMessage: function(message) { - test.assertEqual(this.tooltip, this.label, "tooltip fallbacks to label"); - this.destroy(); - doneTest(); - } - })); - - // test updating widget tooltip - let updated = false; - tests.push(function testUpdatingTooltip() testSingleWidget({ - id: "tooltip", - label: "tooltip update test widget", - tooltip: "foo", - content: "<div id='me'>foo</div>", - contentScript: "self.postMessage(1)", - contentScriptWhen: "ready", - onMessage: function(message) { - this.tooltip = "bar"; - test.assertEqual(this.tooltip, "bar", "tooltip gets updated"); - this.destroy(); - doneTest(); - } - })); - - // test allow attribute - tests.push(function testDefaultAllow() testSingleWidget({ - id: "allow", - label: "allow.script attribute", - content: "<script>document.title = 'ok';</script>", - contentScript: "self.postMessage(document.title)", - onMessage: function(message) { - test.assertEqual(message, "ok", "scripts are evaluated by default"); - this.destroy(); - doneTest(); - } - })); - - tests.push(function testExplicitAllow() testSingleWidget({ - id: "allow", - label: "allow.script attribute", - allow: {script: true}, - content: "<script>document.title = 'ok';</script>", - contentScript: "self.postMessage(document.title)", - onMessage: function(message) { - test.assertEqual(message, "ok", "scripts are evaluated when we want to"); - this.destroy(); - doneTest(); - } - })); - - tests.push(function testExplicitDisallow() testSingleWidget({ - id: "allow", - label: "allow.script attribute", - content: "<script>document.title = 'ok';</script>", - allow: {script: false}, - contentScript: "self.postMessage(document.title)", - onMessage: function(message) { - test.assertNotEqual(message, "ok", "scripts aren't evaluated when " + - "explicitly blocked it"); - this.destroy(); - doneTest(); - } - })); - - // test multiple windows - tests.push(function testMultipleWindows() { - tabBrowser.addTab("about:blank", { inNewWindow: true, onLoad: function(e) { - let browserWindow = e.target.defaultView; - let doc = browserWindow.document; - function container() doc.getElementById("addon-bar"); - function widgetCount2() container() ? container().childNodes.length : 0; - let widgetStartCount2 = widgetCount2(); - - let w1Opts = {id:"first", label: "first widget", content: "first content"}; - let w1 = testSingleWidget(w1Opts); - test.assertEqual(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first widget"); - - let w2Opts = {id:"second", label: "second widget", content: "second content"}; - let w2 = testSingleWidget(w2Opts); - test.assertEqual(widgetCount2(), widgetStartCount2 + 2, "2nd window has correct number of child elements after second widget"); - - w1.destroy(); - test.assertEqual(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first destroy"); - w2.destroy(); - test.assertEqual(widgetCount2(), widgetStartCount2, "2nd window has correct number of child elements after second destroy"); - - closeBrowserWindow(browserWindow, function() { - doneTest(); - }); - }}); - }); - - // test window closing - tests.push(function testWindowClosing() { - // 1/ Create a new widget - let w1Opts = { - id:"first", - label: "first widget", - content: "first content", - contentScript: "self.port.on('event', function () self.port.emit('event'))" - }; - let widget = testSingleWidget(w1Opts); - let windows = require("windows").browserWindows; - - // 2/ Retrieve a WidgetView for the initial browser window - let acceptDetach = false; - let mainView = widget.getView(windows.activeWindow); - test.assert(mainView, "Got first widget view"); - mainView.on("detach", function () { - // 8/ End of our test. Accept detach event only when it occurs after - // widget.destroy() - if (acceptDetach) - doneTest(); - else - test.fail("View on initial window should not be destroyed"); - }); - mainView.port.on("event", function () { - // 7/ Receive event sent during 6/ and cleanup our test - acceptDetach = true; - widget.destroy(); - }); - - // 3/ First: open a new browser window - windows.open({ - url: "about:blank", - onOpen: function(window) { - // 4/ Retrieve a WidgetView for this new window - let view = widget.getView(window); - test.assert(view, "Got second widget view"); - view.port.on("event", function () { - test.fail("We should not receive event on the detach view"); - }); - view.on("detach", function () { - // The related view is destroyed - // 6/ Send a custom event - test.assertRaises(function () { - view.port.emit("event"); - }, - /The widget has been destroyed and can no longer be used./, - "emit on a destroyed view should throw"); - widget.port.emit("event"); - }); - - // 5/ Destroy this window - window.close(); - } - }); - }); - - tests.push(function testAddonBarHide() { - // Hide the addon-bar - browserWindow.setToolbarVisibility(container(), false); - - // Then open a browser window and verify that the addon-bar remains hidden - tabBrowser.addTab("about:blank", { inNewWindow: true, onLoad: function(e) { - let browserWindow = e.target.defaultView; - let doc = browserWindow.document; - function container2() doc.getElementById("addon-bar"); - function widgetCount2() container2() ? container2().childNodes.length : 0; - let widgetStartCount2 = widgetCount2(); - - let w1Opts = {id:"first", label: "first widget", content: "first content"}; - let w1 = testSingleWidget(w1Opts); - test.assertEqual(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after widget creation"); - - w1.destroy(); - test.assertEqual(widgetCount2(), widgetStartCount2, "2nd window has correct number of child elements after widget destroy"); - - test.assert(container().collapsed, "1st window has an hidden addon-bar"); - test.assert(container2().collapsed, "2nd window has an hidden addon-bar"); - - browserWindow.setToolbarVisibility(container(), true); - - closeBrowserWindow(browserWindow, function() { - doneTest(); - }); - }}); - }); - - // test widget.width - tests.push(function testWidgetWidth() testSingleWidget({ - id: "text", - label: "test widget.width", - content: "test width", - width: 200, - contentScript: "self.postMessage(1)", - contentScriptWhen: "ready", - onMessage: function(message) { - test.assertEqual(this.width, 200); - - let node = widgetNode(0); - test.assertEqual(this.width, node.style.minWidth.replace("px", "")); - test.assertEqual(this.width, node.firstElementChild.style.width.replace("px", "")); - this.width = 300; - test.assertEqual(this.width, node.style.minWidth.replace("px", "")); - test.assertEqual(this.width, node.firstElementChild.style.width.replace("px", "")); - - this.destroy(); - doneTest(); - } - })); - - // test click handler not respond to right-click - let clickCount = 0; - tests.push(function testNoRightClick() testSingleWidget({ - id: "click-content", - label: "click test widget - content", - content: "<div id='me'>foo</div>", - contentScript: "var evt = document.createEvent('MouseEvents'); " + - "evt.initMouseEvent('click', true, true, window, " + - " 0, 0, 0, 0, 0, false, false, false, false, 2, null); " + - "document.getElementById('me').dispatchEvent(evt); " + - "evt = document.createEvent('HTMLEvents'); " + - "evt.initEvent('click', true, true ); " + - "document.getElementById('me').dispatchEvent(evt); " + - "evt = document.createEvent('HTMLEvents'); " + - "evt.initEvent('mouseover', true, true ); " + - "document.getElementById('me').dispatchEvent(evt);", - contentScriptWhen: "end", - onClick: function() clickCount++, - onMouseover: function() { - test.assertEqual(clickCount, 1, "right click wasn't sent to click handler"); - this.destroy(); - doneTest(); - } - })); - - // kick off test execution - doneTest(); -}; - -exports.testPanelWidget1 = function testPanelWidget1(test) { - const widgets = require("widget"); - - let widget1 = widgets.Widget({ - id: "panel1", - label: "panel widget 1", - content: "<div id='me'>foo</div>", - contentScript: "var evt = document.createEvent('HTMLEvents'); " + - "evt.initEvent('click', true, true ); " + - "document.body.dispatchEvent(evt);", - contentScriptWhen: "end", - panel: require("panel").Panel({ - contentURL: "data:text/html,<body>Look ma, a panel!</body>", - onShow: function() { - widget1.destroy(); - test.pass("panel displayed on click"); - test.done(); - } - }) - }); - test.waitUntilDone(); -}; - -exports.testPanelWidget2 = function testPanelWidget2(test) { - const widgets = require("widget"); - test.assertRaises( - function() { - widgets.Widget({ - id: "panel2", - label: "panel widget 2", - panel: {} - }); - }, - "The option \"panel\" must be one of the following types: null, undefined, object", - "widget.panel must be a Panel object" - ); -}; - -exports.testPanelWidget3 = function testPanelWidget3(test) { - const widgets = require("widget"); - let onClickCalled = false; - let widget3 = widgets.Widget({ - id: "panel3", - label: "panel widget 3", - content: "<div id='me'>foo</div>", - contentScript: "var evt = document.createEvent('HTMLEvents'); " + - "evt.initEvent('click', true, true ); " + - "document.body.firstElementChild.dispatchEvent(evt);", - contentScriptWhen: "end", - onClick: function() { - onClickCalled = true; - this.panel.show(); - }, - panel: require("panel").Panel({ - contentURL: "data:text/html,<body>Look ma, a panel!</body>", - onShow: function() { - test.assert( - onClickCalled, - "onClick called on click for widget with both panel and onClick" - ); - widget3.destroy(); - test.done(); - } - }) - }); - test.waitUntilDone(); -}; - -exports.testWidgetMessaging = function testWidgetMessaging(test) { - test.waitUntilDone(); - let origMessage = "foo"; - const widgets = require("widget"); - let widget = widgets.Widget({ - id: "foo", - label: "foo", - content: "<bar>baz</bar>", - contentScriptWhen: "end", - contentScript: "self.on('message', function(data) { self.postMessage(data); }); self.postMessage('ready');", - onMessage: function(message) { - if (message == "ready") - widget.postMessage(origMessage); - else { - test.assertEqual(origMessage, message); - widget.destroy(); - test.done(); - } - } - }); -}; - -exports.testWidgetViews = function testWidgetViews(test) { - test.waitUntilDone(); - const widgets = require("widget"); - let widget = widgets.Widget({ - id: "foo", - label: "foo", - content: "<bar>baz</bar>", - contentScriptWhen: "ready", - contentScript: "self.on('message', function(data) self.postMessage(data)); self.postMessage('ready')", - onAttach: function(view) { - test.pass("WidgetView created"); - view.on("message", function () { - test.pass("Got message in WidgetView"); - widget.destroy(); - }); - view.on("detach", function () { - test.pass("WidgetView destroyed"); - test.done(); - }); - } - }); - -}; - -exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(test) { - test.waitUntilDone(); - const widgets = require("widget"); - let view = null; - let widget = widgets.Widget({ - id: "foo", - label: "foo", - content: "<div id='me'>foo</div>", - contentScript: "var evt = document.createEvent('HTMLEvents'); " + - "evt.initEvent('click', true, true ); " + - "document.getElementById('me').dispatchEvent(evt);", - contentScriptWhen: "ready", - onAttach: function(attachView) { - view = attachView; - test.pass("Got attach event"); - }, - onClick: function (eventView) { - test.assertEqual(view, eventView, - "event first argument is equal to the WidgetView"); - let view2 = widget.getView(require("windows").browserWindows.activeWindow); - test.assertEqual(view, view2, - "widget.getView return the same WidgetView"); - widget.destroy(); - test.done(); - } - }); -}; - -exports.testWidgetViewsCustomEvents = function testWidgetViewsCustomEvents(test) { - test.waitUntilDone(); - const widgets = require("widget"); - let widget = widgets.Widget({ - id: "foo", - label: "foo", - content: "<div id='me'>foo</div>", - contentScript: "self.port.emit('event', 'ok');", - contentScriptWhen: "ready", - onAttach: function(view) { - view.port.on("event", function (data) { - test.assertEqual(data, "ok", - "event argument is valid on WidgetView"); - }); - }, - }); - widget.port.on("event", function (data) { - test.assertEqual(data, "ok", - "event argument is valid on Widget"); - widget.destroy(); - test.done(); - }); -}; - -exports.testWidgetViewsTooltip = function testWidgetViewsTooltip(test) { - test.waitUntilDone(); - const widgets = require("widget"); - - let widget = new widgets.Widget({ - id: "foo", - label: "foo", - content: "foo" - }); - let view = widget.getView(require("windows").browserWindows.activeWindow); - widget.tooltip = null; - test.assertEqual(view.tooltip, "foo", - "view tooltip defaults to base widget label"); - test.assertEqual(widget.tooltip, "foo", - "tooltip defaults to base widget label"); - widget.destroy(); - test.done(); -}; - -exports.testWidgetMove = function testWidgetMove(test) { - test.waitUntilDone(); - - let windowUtils = require("window-utils"); - let widgets = require("widget"); - - let browserWindow = windowUtils.activeBrowserWindow; - let doc = browserWindow.document; - - let label = "unique-widget-label"; - let origMessage = "message after node move"; - let gotFirstReady = false; - - let widget = widgets.Widget({ - id: "foo", - label: label, - content: "<bar>baz</bar>", - contentScriptWhen: "ready", - contentScript: "self.on('message', function(data) { self.postMessage(data); }); self.postMessage('ready');", - onMessage: function(message) { - if (message == "ready") { - if (!gotFirstReady) { - test.pass("Got first ready event"); - let widgetNode = doc.querySelector('toolbaritem[label="' + label + '"]'); - let parent = widgetNode.parentNode; - parent.insertBefore(widgetNode, parent.firstChild); - gotFirstReady = true; - } else { - test.pass("Got second ready event"); - widget.postMessage(origMessage); - } - } - else { - test.assertEqual(origMessage, message, "Got message after node move"); - widget.destroy(); - test.done(); - } - } - }); -}; - -/* -The bug is exhibited when a widget with HTML content has it's content -changed to new HTML content with a pound in it. Because the src of HTML -content is converted to a data URI, the underlying iframe doesn't -consider the content change a navigation change, so doesn't load -the new content. -*/ -exports.testWidgetWithPound = function testWidgetWithPound(test) { - test.waitUntilDone(); - - function getWidgetContent(widget) { - let windowUtils = require("window-utils"); - let browserWindow = windowUtils.activeBrowserWindow; - let doc = browserWindow.document; - let widgetNode = doc.querySelector('toolbaritem[label="' + widget.label + '"]'); - test.assert(widgetNode, 'found widget node in the front-end'); - return widgetNode.firstChild.contentDocument.body.innerHTML; - } - - let widgets = require("widget"); - let count = 0; - let widget = widgets.Widget({ - id: "1", - label: "foo", - content: "foo", - contentScript: "window.addEventListener('load', self.postMessage, false);", - onMessage: function() { - count++; - if (count == 1) { - widget.content = "foo#"; - } - else { - test.assertEqual(getWidgetContent(widget), "foo#", "content updated to pound?"); - widget.destroy(); - test.done(); - } - } - }); -}; - -/******************* helpers *********************/ - -// Helper for calling code at window close -function closeBrowserWindow(window, callback) { - require("timer").setTimeout(function() { - window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload, false); - callback(); - }, false); - window.close(); - }, 0); -} - -// ADD NO TESTS BELOW THIS LINE! /////////////////////////////////////////////// - -// If the module doesn't support the app we're being run in, require() will -// throw. In that case, remove all tests above from exports, and add one dummy -// test that passes. -try { - require("widget"); -} -catch (err) { - // This bug should be mentioned in the error message. - let bug = "https://bugzilla.mozilla.org/show_bug.cgi?id=560716"; - if (err.message.indexOf(bug) < 0) - throw err; - for (let [prop, val] in Iterator(exports)) { - if (/^test/.test(prop) && typeof(val) === "function") - delete exports[prop]; - } - exports.testAppNotSupported = function (test) { - test.pass("context-menu does not support this application."); - }; -} - diff --git a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-windows.js b/tools/addon-sdk-1.4/packages/addon-kit/tests/test-windows.js deleted file mode 100644 index e2824f8..0000000 --- a/tools/addon-sdk-1.4/packages/addon-kit/tests/test-windows.js +++ /dev/null @@ -1,342 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is Mozilla. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Felipe Gomes <felipc@gmail.com> (Original author) - * Irakli Gozalishvili <gozala@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -const {Cc, Ci} = require("chrome"); -const { setTimeout } = require("timer"); -const { Loader } = require('./helpers'); -const wm = Cc["@mozilla.org/appshell/window-mediator;1"]. - getService(Ci.nsIWindowMediator); -let browserWindows; - -function getTestRunnerWindow() wm.getMostRecentWindow("test:runner") - -exports.testOpenAndCloseWindow = function(test) { - test.waitUntilDone(); - - test.assertEqual(browserWindows.length, 1, "Only one window open"); - - browserWindows.open({ - url: "data:text/html,<title>windows API test</title>", - onOpen: function(window) { - test.assertEqual(this, browserWindows, - "The 'this' object is the windows object."); - test.assertEqual(window.tabs.length, 1, "Only one tab open"); - test.assertEqual(browserWindows.length, 2, "Two windows open"); - window.tabs.activeTab.on('ready', function onReady(tab) { - tab.removeListener('ready', onReady); - test.assert(window.title.indexOf("windows API test") != -1, - "URL correctly loaded"); - window.close(); - }); - }, - onClose: function(window) { - test.assertEqual(window.tabs.length, 0, "Tabs were cleared"); - test.assertEqual(browserWindows.length, 1, "Only one window open"); - test.done(); - } - }); -}; - -exports.testAutomaticDestroy = function(test) { - - test.waitUntilDone(); - let windows = browserWindows; - - // Create a second windows instance that we will unload - let called = false; - let loader = Loader(module); - let windows2 = loader.require("windows").browserWindows; - windows2.on("open", function() { - called = true; - }); - - loader.unload(); - - // Fire a windows event and check that this unloaded instance is inactive - windows.open({ - url: "data:text/html,foo", - onOpen: function(window) { - setTimeout(function () { - test.assert(!called, - "Unloaded windows instance is destroyed and inactive"); - window.close(function () { - test.done(); - }); - }); - } - }); - -}; - -exports.testOnOpenOnCloseListeners = function(test) { - test.waitUntilDone(); - let windows = browserWindows; - - test.assertEqual(browserWindows.length, 1, "Only one window open"); - - let received = { - listener1: false, - listener2: false, - listener3: false, - listener4: false - } - - function listener1() { - test.assertEqual(this, windows, "The 'this' object is the windows object."); - if (received.listener1) - test.fail("Event received twice"); - received.listener1 = true; - } - - function listener2() { - if (received.listener2) - test.fail("Event received twice"); - received.listener2 = true; - } - - function listener3() { - test.assertEqual(this, windows, "The 'this' object is the windows object."); - if (received.listener3) - test.fail("Event received twice"); - received.listener3 = true; - } - - function listener4() { - if (received.listener4) - test.fail("Event received twice"); - received.listener4 = true; - } - - windows.on('open', listener1); - windows.on('open', listener2); - windows.on('close', listener3); - windows.on('close', listener4); - - function verify() { - test.assert(received.listener1, "onOpen handler called"); - test.assert(received.listener2, "onOpen handler called"); - test.assert(received.listener3, "onClose handler called"); - test.assert(received.listener4, "onClose handler called"); - - windows.removeListener('open', listener1); - windows.removeListener('open', listener2); - windows.removeListener('close', listener3); - windows.removeListener('close', listener4); - test.done(); - } - - - windows.open({ - url: "data:text/html,foo", - onOpen: function(window) { - window.close(verify); - } - }); -}; - -exports.testWindowTabsObject = function(test) { - test.waitUntilDone(); - - browserWindows.open({ - url: "data:text/html,<title>tab 1</title>", - onOpen: function onOpen(window) { - test.assertEqual(window.tabs.length, 1, "Only 1 tab open"); - - window.tabs.open({ - url: "data:text/html,<title>tab 2</title>", - inBackground: true, - onReady: function onReady(newTab) { - test.assertEqual(window.tabs.length, 2, "New tab open"); - test.assertEqual(newTab.title, "tab 2", "Correct new tab title"); - test.assertEqual(window.tabs.activeTab.title, "tab 1", "Correct active tab"); - - let i = 1; - for each (let tab in window.tabs) - test.assertEqual(tab.title, "tab " + i++, "Correct title"); - - window.close(); - } - }); - }, - onClose: function onClose(window) { - test.assertEqual(window.tabs.length, 0, "No more tabs on closed window"); - test.done(); - } - }); -}; - -exports.testActiveWindow = function(test) { - const xulApp = require("xul-app"); - if (xulApp.versionInRange(xulApp.platformVersion, "1.9.2", "1.9.2.*")) { - test.pass("This test is disabled on 3.6. For more information, see bug 598525"); - return; - } - - let windows = browserWindows; - - // API window objects - let window2, window3; - - // Raw window objects - let nonBrowserWindow = getTestRunnerWindow(), rawWindow2, rawWindow3; - - test.waitUntilDone(); - - let testSteps = [ - function() { - test.assertEqual(windows.length, 3, "Correct number of browser windows"); - let count = 0; - for (let window in windows) - count++; - test.assertEqual(count, 3, "Correct number of windows returned by iterator"); - - rawWindow2.focus(); - continueAfterFocus(rawWindow2); - }, - function() { - nonBrowserWindow.focus(); - continueAfterFocus(nonBrowserWindow); - }, - function() { - /** - * Bug 614079: This test fails intermittently on some specific linux - * environnements, without being able to reproduce it in same - * distribution with same window manager. - * Disable it until being able to reproduce it easily. - - // On linux, focus is not consistent, so we can't be sure - // what window will be on top. - // Here when we focus "non-browser" window, - // Any Browser window may be selected as "active". - test.assert(windows.activeWindow == window2 || windows.activeWindow == window3, - "Non-browser windows aren't handled by this module"); - */ - window2.activate(); - continueAfterFocus(rawWindow2); - }, - function() { - test.assertEqual(windows.activeWindow.title, window2.title, "Correct active window - 2"); - window3.activate(); - continueAfterFocus(rawWindow3); - }, - function() { - test.assertEqual(windows.activeWindow.title, window3.title, "Correct active window - 3"); - nonBrowserWindow.focus(); - finishTest(); - } - ]; - - windows.open({ - url: "data:text/html,<title>window 2</title>", - onOpen: function(window) { - window2 = window; - rawWindow2 = wm.getMostRecentWindow("navigator:browser"); - - windows.open({ - url: "data:text/html,<title>window 3</title>", - onOpen: function(window) { - window.tabs.activeTab.on('ready', function onReady() { - window3 = window; - rawWindow3 = wm.getMostRecentWindow("navigator:browser"); - nextStep() - }); - } - }); - } - }); - - function nextStep() { - if (testSteps.length > 0) - testSteps.shift()(); - } - - function continueAfterFocus(targetWindow) { - - // Based on SimpleTest.waitForFocus - var fm = Cc["@mozilla.org/focus-manager;1"]. - getService(Ci.nsIFocusManager); - - var childTargetWindow = {}; - fm.getFocusedElementForWindow(targetWindow, true, childTargetWindow); - childTargetWindow = childTargetWindow.value; - - var focusedChildWindow = {}; - if (fm.activeWindow) { - fm.getFocusedElementForWindow(fm.activeWindow, true, focusedChildWindow); - focusedChildWindow = focusedChildWindow.value; - } - - var focused = (focusedChildWindow == childTargetWindow); - if (focused) { - nextStep(); - } else { - childTargetWindow.addEventListener("focus", function focusListener() { - childTargetWindow.removeEventListener("focus", focusListener, true); - nextStep(); - }, true); - } - - } - - function finishTest() { - window3.close(function() { - window2.close(function() { - test.done(); - }); - }); - } -}; - -// If the module doesn't support the app we're being run in, require() will -// throw. In that case, remove all tests above from exports, and add one dummy -// test that passes. -try { - browserWindows = require("windows").browserWindows; -} -catch (err) { - // This bug should be mentioned in the error message. - let bug = "https://bugzilla.mozilla.org/show_bug.cgi?id=571449"; - if (err.message.indexOf(bug) < 0) - throw err; - for (let [prop, val] in Iterator(exports)) { - if (/^test/.test(prop) && typeof(val) === "function") - delete exports[prop]; - } - exports.testAppNotSupported = function (test) { - test.pass("the windows module does not support this application."); - }; -} |