--- a/browser/components/extensions/ext-commands.js
+++ b/browser/components/extensions/ext-commands.js
@@ -60,17 +60,19 @@ CommandList.prototype = {
}
}
WindowListManager.removeOpenListener(this.windowOpenListener);
},
/**
* Creates a Map from commands for each command in the manifest.commands object.
+ *
* @param {Object} manifest The manifest JSON object.
+ * @returns {Map<string, object>}
*/
loadCommandsFromManifest(manifest) {
let commands = new Map();
// For Windows, chrome.runtime expects 'win' while chrome.commands
// expects 'windows'. We can special case this for now.
let os = PlatformInfo.os == "win" ? "windows" : PlatformInfo.os;
for (let name of Object.keys(manifest.commands)) {
let command = manifest.commands[name];
@@ -99,18 +101,18 @@ CommandList.prototype = {
this.keysetsMap.set(window, keyset);
},
/**
* Builds a XUL Key element and attaches an onCommand listener which
* emits a command event with the provided name when fired.
*
* @param {Document} doc The XUL document.
- * @param {String} name The name of the command.
- * @param {String} shortcut The shortcut provided in the manifest.
+ * @param {string} name The name of the command.
+ * @param {string} shortcut The shortcut provided in the manifest.
* @see https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/key
*
* @returns {Document} The newly created Key element.
*/
buildKey(doc, name, shortcut) {
let keyElement = this.buildKeyFromShortcut(doc, shortcut);
// We need to have the attribute "oncommand" for the "command" listener to fire,
@@ -132,18 +134,17 @@ CommandList.prototype = {
return keyElement;
},
/**
* Builds a XUL Key element from the provided shortcut.
*
* @param {Document} doc The XUL document.
- * @param {String} name The name of the command.
- * @param {String} shortcut The shortcut provided in the manifest.
+ * @param {string} shortcut The shortcut provided in the manifest.
*
* @see https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/key
* @returns {Document} The newly created Key element.
*/
buildKeyFromShortcut(doc, shortcut) {
let keyElement = doc.createElementNS(XUL_NS, "key");
let parts = shortcut.split("+");
@@ -169,35 +170,35 @@ CommandList.prototype = {
*
* For example:
*
* input | output
* ---------------------------------------
* "PageUP" | "VK_PAGE_UP"
* "Delete" | "VK_DELETE"
*
- * @param {String} key The chrome key (e.g. "PageUp", "Space", ...)
- * @return The constructed value for the Key's 'keycode' attribute.
+ * @param {string} chromeKey The chrome key (e.g. "PageUp", "Space", ...)
+ * @returns {string} The constructed value for the Key's 'keycode' attribute.
*/
getKeycodeAttribute(chromeKey) {
return `VK${chromeKey.replace(/([A-Z])/g, "_$&").toUpperCase()}`;
},
/**
* Determines the corresponding XUL modifiers from the chrome modifiers.
*
* For example:
*
* input | output
* ---------------------------------------
* ["Ctrl", "Shift"] | "accel shift"
* ["MacCtrl"] | "control"
*
* @param {Array} chromeModifiers The array of chrome modifiers.
- * @return The constructed value for the Key's 'modifiers' attribute.
+ * @returns {string} The constructed value for the Key's 'modifiers' attribute.
*/
getModifiersAttribute(chromeModifiers) {
let modifiersMap = {
"Alt": "alt",
"Command": "accel",
"Ctrl": "accel",
"MacCtrl": "control",
"Shift": "shift",
--- a/browser/components/extensions/ext-pageAction.js
+++ b/browser/components/extensions/ext-pageAction.js
@@ -129,16 +129,18 @@ PageAction.prototype = {
return this.buttons.get(window);
},
/**
* Triggers this page action for the given window, with the same effects as
* if it were clicked by a user.
*
* This has no effect if the page action is hidden for the selected tab.
+ *
+ * @param {Window} window
*/
triggerAction(window) {
let pageAction = pageActionMap.get(this.extension);
if (pageAction.getProperty(window.gBrowser.selectedTab, "show")) {
pageAction.handleClick(window);
}
},
--- a/browser/components/extensions/test/browser/browser_ext_tabs_onHighlighted.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_onHighlighted.js
@@ -31,16 +31,20 @@ add_task(function* testTabEvents() {
} else {
events[info.tabIds[0]] = ["onHighlighted"];
}
});
/**
* Asserts that the expected events are fired for the tab with id = tabId.
* The events associated to the specified tab are removed after this check is made.
+ *
+ * @param {number} tabId
+ * @param {Array<string>} expectedEvents
+ * @returns {Promise}
*/
function expectEvents(tabId, expectedEvents) {
browser.test.log(`Expecting events: ${expectedEvents.join(", ")}`);
return new Promise(resolve => {
setTimeout(resolve, 0);
}).then(() => {
browser.test.assertEq(expectedEvents.length, events[tabId].length,
@@ -50,30 +54,36 @@ add_task(function* testTabEvents() {
`Got expected ${name} event`);
}
delete events[tabId];
});
}
/**
* Opens a new tab and asserts that the correct events are fired.
+ *
+ * @param {number} windowId
+ * @returns {Promise}
*/
function openTab(windowId) {
return browser.tabs.create({windowId}).then(tab => {
tabIds.push(tab.id);
browser.test.log(`Opened tab ${tab.id}`);
return expectEvents(tab.id, [
"onActivated",
"onHighlighted",
]);
});
}
/**
* Highlights an existing tab and asserts that the correct events are fired.
+ *
+ * @param {number} tabId
+ * @returns {Promise}
*/
function highlightTab(tabId) {
browser.test.log(`Highlighting tab ${tabId}`);
return browser.tabs.update(tabId, {active: true}).then(tab => {
browser.test.assertEq(tab.id, tabId, `Tab ${tab.id} highlighted`);
return expectEvents(tab.id, [
"onActivated",
"onHighlighted",
--- a/toolkit/components/extensions/.eslintrc
+++ b/toolkit/components/extensions/.eslintrc
@@ -30,16 +30,31 @@
"rules": {
// Rules from the mozilla plugin
"mozilla/balanced-listeners": 2,
"mozilla/mark-test-function-used": 1,
"mozilla/no-aArgs": 1,
"mozilla/no-cpows-in-tests": 1,
"mozilla/var-only-at-top-level": 1,
+ "valid-jsdoc": [2, {
+ "prefer": {
+ "return": "returns",
+ },
+ "preferType": {
+ "Boolean": "boolean",
+ "Number": "number",
+ "String": "string",
+ "bool": "boolean",
+ },
+ "requireParamDescription": false,
+ "requireReturn": false,
+ "requireReturnDescription": false,
+ }],
+
// Braces only needed for multi-line arrow function blocks
// "arrow-body-style": [2, "as-needed"],
// Require spacing around =>
"arrow-spacing": 2,
// Always require spacing around a single line block
"block-spacing": 1,
@@ -441,19 +456,16 @@
"sort-vars": 0,
// Require a space immediately following the // in a line comment.
"spaced-comment": [2, "always"],
// Require "use strict" to be defined globally in the script.
"strict": [2, "global"],
- // Warn about invalid JSDoc comments.
- "valid-jsdoc": 0,
-
// Allow vars to be declared anywhere in the scope.
"vars-on-top": 0,
// Don't require immediate function invocation to be wrapped in parentheses.
"wrap-iife": 0,
// Don't require regex literals to be wrapped in parentheses (which
// supposedly prevent them from being mistaken for division operators).
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -1073,16 +1073,20 @@ this.Extension = function(addonData) {
* Directories should appear here only implicitly (as a prefix
* to file names)
*
* To make things easier, the value of "background" and "files"[] can
* be a function, which is converted to source that is run.
*
* The generated extension is stored in the system temporary directory,
* and an nsIFile object pointing to it is returned.
+ *
+ * @param {string} id
+ * @param {object} data
+ * @returns {nsIFile}
*/
this.Extension.generateXPI = function(id, data) {
let manifest = data.manifest;
if (!manifest) {
manifest = {};
}
let files = data.files;
@@ -1166,16 +1170,20 @@ this.Extension.generateXPI = function(id
return file;
};
/**
* A skeleton Extension-like object, used for testing, which installs an
* add-on via the add-on manager when startup() is called, and
* uninstalles it on shutdown().
+ *
+ * @param {string} id
+ * @param {nsIFile} file
+ * @param {nsIURI} rootURI
*/
function MockExtension(id, file, rootURI) {
this.id = id;
this.file = file;
this.rootURI = rootURI;
this._extension = null;
this._extensionPromise = new Promise(resolve => {
@@ -1224,16 +1232,20 @@ MockExtension.prototype = {
flushJarCache(this.file);
return OS.File.remove(this.file.path);
},
};
/**
* Generates a new extension using |Extension.generateXPI|, and initializes a
* new |Extension| instance which will execute it.
+ *
+ * @param {string} id
+ * @param {object} data
+ * @returns {Extension}
*/
this.Extension.generate = function(id, data) {
let file = this.generateXPI(id, data);
flushJarCache(file);
Services.ppmm.broadcastAsyncMessage("Extension:FlushJarCache", {path: file.path});
let fileURI = Services.io.newFileURI(file);
--- a/toolkit/components/extensions/ExtensionStorage.jsm
+++ b/toolkit/components/extensions/ExtensionStorage.jsm
@@ -63,16 +63,23 @@ this.ExtensionStorage = {
cache: new Map(),
listeners: new Map(),
extensionDir: Path.join(profileDir, "browser-extension-data"),
/**
* Sanitizes the given value, and returns a JSON-compatible
* representation of it, based on the privileges of the given global.
+ *
+ * @param {value} value
+ * The value to sanitize.
+ * @param {object} global
+ * The global for which to sanitize the value.
+ * @returns {value}
+ * The sanitized value.
*/
sanitize(value, global) {
// We can't trust that the global has privileges to access this
// value enough to clone it using a privileged JSON object.
let JSON_ = Cu.waiveXrays(global.JSON);
let json = JSON_.stringify(value, jsonReplacer);
return JSON.parse(json);
--- a/toolkit/components/extensions/ExtensionUtils.jsm
+++ b/toolkit/components/extensions/ExtensionUtils.jsm
@@ -203,16 +203,25 @@ class BaseContext {
forgetOnClose(obj) {
this.onClose.delete(obj);
}
/**
* A wrapper around MessageChannel.sendMessage which adds the extension ID
* to the recipient object, and ensures replies are not processed after the
* context has been unloaded.
+ *
+ * @param {nsIMessageManager} target
+ * @param {string} messageName
+ * @param {object} data
+ * @param {object} [options]
+ * @param {object} [options.sender]
+ * @param {object} [options.recipient]
+ *
+ * @returns {Promise}
*/
sendMessage(target, messageName, data, options = {}) {
options.recipient = options.recipient || {};
options.sender = options.sender || {};
options.recipient.extensionId = this.extension.id;
options.sender.extensionId = this.extension.id;
options.sender.contextId = this.contextId;
@@ -233,16 +242,19 @@ class BaseContext {
/**
* Normalizes the given error object for use by the target scope. If
* the target is an error object which belongs to that scope, it is
* returned as-is. If it is an ordinary object with a `message`
* property, it is converted into an error belonging to the target
* scope. If it is an Error object which does *not* belong to the
* clone scope, it is reported, and converted to an unexpected
* exception error.
+ *
+ * @param {Error|object} error
+ * @returns {Error}
*/
normalizeError(error) {
if (error instanceof this.cloneScope.Error) {
return error;
}
if (!instanceOf(error, "Object")) {
Cu.reportError(error);
error = {message: "An unexpected error occurred"};
--- a/toolkit/components/extensions/MessageChannel.jsm
+++ b/toolkit/components/extensions/MessageChannel.jsm
@@ -133,16 +133,17 @@ class FilteringMessageManager {
* An object containing either a `handler` or an `error` property.
* If no error occurs, `handler` will be a matching handler that
* was registered by `addHandler`. Otherwise, the `error` property
* will contain an object describing the error.
*
* data:
* An object describing the message, as defined in
* `MessageChannel.addListener`.
+ * @param {nsIMessageManager} messageManager
*/
constructor(messageName, callback, messageManager) {
this.messageName = messageName;
this.callback = callback;
this.messageManager = messageManager;
this.messageManager.addMessageListener(this.messageName, this);
@@ -346,17 +347,17 @@ this.MessageChannel = {
* The filter object to match against.
* @param {object} data
* The data object being matched.
* @param {boolean} [strict=false]
* If true, all properties in the `filter` object have a
* corresponding property in `data` with the same value. If
* false, properties present in both objects must have the same
* balue.
- * @returns {bool} True if the objects match.
+ * @returns {boolean} True if the objects match.
*/
matchesFilter(filter, data, strict = true) {
if (strict) {
return Object.keys(filter).every(key => {
return key in data && data[key] === filter[key];
});
}
return Object.keys(filter).every(key => {
@@ -424,18 +425,17 @@ this.MessageChannel = {
for (let target of [].concat(targets)) {
this.messageManagers.get(target).addHandler(messageName, handler);
}
},
/**
* Removes a message listener from the given message manager.
*
- * @param {nsIMessageSender} target
- * @param {nsIMessageSender|[nsIMessageSender]} targets
+ * @param {nsIMessageSender|Array<nsIMessageSender>} targets
* The message managers on which to stop listening.
* @param {string|number} messageName
* The name of the message to stop listening for.
* @param {MessageReceiver} handler
* The handler to stop dispatching to.
*/
removeListener(targets, messageName, handler) {
for (let target of [].concat(targets)) {
@@ -469,17 +469,17 @@ this.MessageChannel = {
* @param {object} [options.sender]
* A structured-clone-compatible object to identify the message
* sender. This object may also be used as a filter to prematurely
* abort responses when the sender is being destroyed.
* @see `abortResponses`.
* @param {integer} [options.responseType=RESPONSE_SINGLE]
* Specifies the type of response expected. See the `RESPONSE_*`
* contents for details.
- * @returns Promise
+ * @returns {Promise}
*/
sendMessage(target, messageName, data, options = {}) {
let sender = options.sender || {};
let recipient = options.recipient || {};
let responseType = options.responseType || this.RESPONSE_SINGLE;
let channelId = gChannelId++;
let message = {messageName, channelId, sender, recipient, data, responseType};
@@ -555,16 +555,20 @@ this.MessageChannel = {
/**
* Handles dispatching message callbacks from the message brokers to their
* appropriate `MessageReceivers`, and routing the responses back to the
* original senders.
*
* Each handler object is a `MessageReceiver` object as passed to
* `addListener`.
+ *
+ * @param {Array<MessageHandler>} handlers
+ * @param {object} data
+ * @param {nsIMessageSender|nsIMessageManagerOwner} data.target
*/
_handleMessage(handlers, data) {
// The target passed to `receiveMessage` is sometimes a message manager
// owner instead of a message manager, so make sure to convert it to a
// message manager first if necessary.
let {target} = data;
if (!(target instanceof Ci.nsIMessageSender)) {
target = target.messageManager;
@@ -617,16 +621,20 @@ this.MessageChannel = {
this._addPendingResponse(deferred);
},
/**
* Handles message callbacks from the response brokers.
*
* Each handler object is a deferred object created by `sendMessage`, and
* should be resolved or rejected based on the contents of the response.
+ *
+ * @param {Array<MessageHandler>} handlers
+ * @param {object} data
+ * @param {nsIMessageSender|nsIMessageManagerOwner} data.target
*/
_handleResponse(handlers, data) {
// If we have an error at this point, we have handler to report it to,
// so just log it.
if (handlers.length == 0) {
Cu.reportError(`No matching message response handler for ${data.messageName}`);
} else if (handlers.length > 1) {
Cu.reportError(`Multiple matching response handlers for ${data.messageName}`);
@@ -657,16 +665,18 @@ this.MessageChannel = {
* messageManager:
* The message manager the response will be sent or received on.
*
* When the promise resolves or rejects, it will be removed from the
* list.
*
* These values are used to clear pending responses when execution
* contexts are destroyed.
+ *
+ * @param {Deferred} deferred
*/
_addPendingResponse(deferred) {
let cleanup = () => {
this.pendingResponses.delete(deferred);
};
this.pendingResponses.add(deferred);
deferred.promise.then(cleanup, cleanup);
},
--- a/toolkit/components/extensions/Schemas.jsm
+++ b/toolkit/components/extensions/Schemas.jsm
@@ -140,43 +140,51 @@ class Context {
}
/**
* Returns an error result object with the given message, for return
* by Type normalization functions.
*
* If the context has a `currentTarget` value, this is prepended to
* the message to indicate the location of the error.
+ *
+ * @param {string} message
+ * @returns {object}
*/
error(message) {
if (this.currentTarget) {
return {error: `Error processing ${this.currentTarget}: ${message}`};
}
return {error: message};
}
/**
* Creates an `Error` object belonging to the current unprivileged
* scope. If there is no unprivileged scope associated with this
* context, the message is returned as a string.
*
* If the context has a `currentTarget` value, this is prepended to
* the message, in the same way as for the `error` method.
+ *
+ * @param {string} message
+ * @returns {Error}
*/
makeError(message) {
let {error} = this.error(message);
if (this.cloneScope) {
return new this.cloneScope.Error(error);
}
return error;
}
/**
* Logs the given error to the console. May be overridden to enable
* custom logging.
+ *
+ * @param {Error|string} error
*/
logError(error) {
Cu.reportError(error);
}
/**
* Returns the name of the value currently being normalized. For a
* nested object, this is usually approximately equivalent to the
@@ -193,16 +201,20 @@ class Context {
/**
* Appends the given component to the `currentTarget` path to indicate
* that it is being processed, calls the given callback function, and
* then restores the original path.
*
* This is used to identify the path of the property being processed
* when reporting type errors.
+ *
+ * @param {string} component
+ * @param {function} callback
+ * @returns {*}
*/
withPath(component, callback) {
this.path.push(component);
try {
return callback();
} finally {
this.path.pop();
}
@@ -304,37 +316,45 @@ class Entry {
* message will be emitted.
*/
this.deprecated = false;
if ("deprecated" in schema) {
this.deprecated = schema.deprecated;
}
/**
+ * @property {string} [preprocessor]
* If set to a string value, and a preprocessor of the same is
* defined in the validation context, it will be applied to this
* value prior to any normalization.
*/
this.preprocessor = schema.preprocess || null;
}
/**
* Preprocess the given value with the preprocessor declared in
* `preprocessor`.
+ *
+ * @param {*} value
+ * @param {Context} context
+ * @returns {*}
*/
preprocess(value, context) {
if (this.preprocessor) {
return context.preprocessors[this.preprocessor](value, context);
}
return value;
}
/**
* Logs a deprecation warning for this entry, based on the value of
* its `deprecated` property.
+ *
+ * @param {Context} context
+ * @param {value} [value]
*/
logDeprecation(context, value = null) {
let message = "This property is deprecated";
if (typeof(this.deprecated) == "string") {
message = this.deprecated;
if (message.includes("${value}")) {
try {
value = JSON.stringify(value);
@@ -346,16 +366,19 @@ class Entry {
}
context.logError(context.makeError(message));
}
/**
* Checks whether the entry is deprecated and, if so, logs a
* deprecation message.
+ *
+ * @param {Context} context
+ * @param {value} [value]
*/
checkDeprecated(context, value = null) {
if (this.deprecated) {
this.logDeprecation(context, value);
}
}
// Injects JS values for the entry into the extension API
--- a/toolkit/components/extensions/test/mochitest/test_ext_content_security_policy.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_content_security_policy.html
@@ -13,16 +13,18 @@
<script type="text/javascript">
"use strict";
/**
* Tests that content security policies for an add-on are actually applied to *
* documents that belong to it. This tests both the base policies and add-on
* specific policies, and ensures that the parsed policies applied to the
* document's principal match what was specified in the policy string.
+ *
+ * @param {object} [customCSP]
*/
function* testPolicy(customCSP = null) {
let baseURL;
let baseCSP = {
"object-src": ["blob:", "filesystem:", "https://*", "moz-extension:", "'self'"],
"script-src": ["'unsafe-eval'", "'unsafe-inline'", "blob:", "filesystem:", "https://*", "moz-extension:", "'self'"],
};
--- a/toolkit/modules/addons/WebNavigation.jsm
+++ b/toolkit/modules/addons/WebNavigation.jsm
@@ -80,56 +80,62 @@ var Manager = {
}
if (this.listeners.size == 0) {
this.uninit();
}
},
/**
- * Support nsIObserver interface to observe the urlbar autocomplete events used
- * to keep track of the urlbar user interaction.
+ * Support nsIObserver interface to observe the urlbar autocomplete events used
+ * to keep track of the urlbar user interaction.
*/
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
/**
- * Observe autocomplete-did-enter-text topic to track the user interaction with
- * the awesome bar.
+ * Observe autocomplete-did-enter-text topic to track the user interaction with
+ * the awesome bar.
+ *
+ * @param {nsIAutoCompleteInput} subject
+ * @param {string} topic
+ * @param {string} data
*/
observe: function(subject, topic, data) {
if (topic == "autocomplete-did-enter-text") {
this.onURLBarAutoCompletion(subject, topic, data);
}
},
/**
- * Recognize the type of urlbar user interaction (e.g. typing a new url,
- * clicking on an url generated from a searchengine or a keyword, or a
- * bookmark found by the urlbar autocompletion).
+ * Recognize the type of urlbar user interaction (e.g. typing a new url,
+ * clicking on an url generated from a searchengine or a keyword, or a
+ * bookmark found by the urlbar autocompletion).
+ *
+ * @param {nsIAutoCompleteInput} input
*/
- onURLBarAutoCompletion(subject, topic, data) {
- if (subject && subject instanceof Ci.nsIAutoCompleteInput) {
+ onURLBarAutoCompletion(input) {
+ if (input && input instanceof Ci.nsIAutoCompleteInput) {
// We are only interested in urlbar autocompletion events
- if (subject.id !== "urlbar") {
+ if (input.id !== "urlbar") {
return;
}
- let controller = subject.popup.view.QueryInterface(Ci.nsIAutoCompleteController);
- let idx = subject.popup.selectedIndex;
+ let controller = input.popup.view.QueryInterface(Ci.nsIAutoCompleteController);
+ let idx = input.popup.selectedIndex;
let tabTransistionData = {
from_address_bar: true,
};
if (idx < 0 || idx >= controller.matchCount) {
// Recognize when no valid autocomplete results has been selected.
tabTransistionData.typed = true;
} else {
let value = controller.getValueAt(idx);
- let action = subject._parseActionUrl(value);
+ let action = input._parseActionUrl(value);
if (action) {
// Detect keywork and generated and more typed scenarios.
switch (action.type) {
case "keyword":
tabTransistionData.keyword = true;
break;
case "searchengine":
@@ -169,18 +175,26 @@ var Manager = {
}
}
this.setRecentTabTransitionData(tabTransistionData);
}
},
/**
- * Keep track of a recent user interaction and cache it in a
- * map associated to the current selected tab.
+ * Keep track of a recent user interaction and cache it in a
+ * map associated to the current selected tab.
+ *
+ * @param {object} tabTransitionData
+ * @param {boolean} [tabTransitionData.auto_bookmark]
+ * @param {boolean} [tabTransitionData.from_address_bar]
+ * @param {boolean} [tabTransitionData.generated]
+ * @param {boolean} [tabTransitionData.keyword]
+ * @param {boolean} [tabTransitionData.link]
+ * @param {boolean} [tabTransitionData.typed]
*/
setRecentTabTransitionData(tabTransitionData) {
let window = RecentWindow.getMostRecentBrowserWindow();
if (window && window.gBrowser && window.gBrowser.selectedTab &&
window.gBrowser.selectedTab.linkedBrowser) {
let browser = window.gBrowser.selectedTab.linkedBrowser;
// Get recent tab transition data to update if any.
@@ -191,40 +205,43 @@ var Manager = {
prevData,
tabTransitionData
);
this.recentTabTransitionData.set(browser, newData);
}
},
/**
- * Retrieve recent data related to a recent user interaction give a
- * given tab's linkedBrowser (only if is is more recent than the
- * `RECENT_DATA_THRESHOLD`).
+ * Retrieve recent data related to a recent user interaction give a
+ * given tab's linkedBrowser (only if is is more recent than the
+ * `RECENT_DATA_THRESHOLD`).
*
- * NOTE: this method is used to retrieve the tab transition data
- * collected when one of the `onCommitted`, `onHistoryStateUpdated`
- * or `onReferenceFragmentUpdated` events has been received.
+ * NOTE: this method is used to retrieve the tab transition data
+ * collected when one of the `onCommitted`, `onHistoryStateUpdated`
+ * or `onReferenceFragmentUpdated` events has been received.
+ *
+ * @param {XULBrowserElement} browser
+ * @returns {object}
*/
getAndForgetRecentTabTransitionData(browser) {
let data = this.recentTabTransitionData.get(browser);
this.recentTabTransitionData.delete(browser);
// Return an empty object if there isn't any tab transition data
// or if it's less recent than RECENT_DATA_THRESHOLD.
if (!data || (data.time - Date.now()) > RECENT_DATA_THRESHOLD) {
return {};
}
return data;
},
/**
- * Receive messages from the WebNavigationContent.js framescript
- * over message manager events.
+ * Receive messages from the WebNavigationContent.js framescript
+ * over message manager events.
*/
receiveMessage({name, data, target}) {
switch (name) {
case "Extension:StateChange":
this.onStateChange(target, data);
break;
case "Extension:DocumentChange":
--- a/toolkit/modules/addons/WebNavigationFrames.jsm
+++ b/toolkit/modules/addons/WebNavigationFrames.jsm
@@ -19,17 +19,17 @@ function getWindowId(window) {
function getParentWindowId(window) {
return getWindowId(window.parent);
}
/**
* Retrieve the DOMWindow associated to the docShell passed as parameter.
*
* @param {nsIDocShell} docShell - the docShell that we want to get the DOMWindow from.
- * @return {nsIDOMWindow} - the DOMWindow associated to the docShell.
+ * @returns {nsIDOMWindow} - the DOMWindow associated to the docShell.
*/
function docShellToWindow(docShell) {
return docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
}
/**
* The FrameDetail object which represents a frame in WebExtensions APIs.
@@ -42,33 +42,33 @@ function docShellToWindow(docShell) {
* @property {boolean} errorOccurred - Indicates whether an error is occurred during the last load
* happened on this frame (NOT YET SUPPORTED).
*/
/**
* Convert a docShell object into its internal FrameDetail representation.
*
* @param {nsIDocShell} docShell - the docShell object to be converted into a FrameDetail JSON object.
- * @return {FrameDetail} the FrameDetail JSON object which represents the docShell.
+ * @returns {FrameDetail} the FrameDetail JSON object which represents the docShell.
*/
function convertDocShellToFrameDetail(docShell) {
let window = docShellToWindow(docShell);
return {
windowId: getWindowId(window),
parentWindowId: getParentWindowId(window),
url: window.location.href,
};
}
/**
* A generator function which iterates over a docShell tree, given a root docShell.
*
- * @param {nsIDocShell} docShell - the root docShell object
- * @return {Iterator<DocShell>} the FrameDetail JSON object which represents the docShell.
+ * @param {nsIDocShell} docShell - the root docShell object
+ * @returns {Iterator<DocShell>} the FrameDetail JSON object which represents the docShell.
*/
function* iterateDocShellTree(docShell) {
let docShellsEnum = docShell.getDocShellEnumerator(
Ci.nsIDocShellTreeItem.typeContent,
Ci.nsIDocShell.ENUMERATE_FORWARDS
);
while (docShellsEnum.hasMoreElements()) {
@@ -99,19 +99,19 @@ function getFrameId(window) {
}
/**
* Search for a frame starting from the passed root docShell and
* convert it to its related frame detail representation.
*
* @param {number} frameId - the frame ID of the frame to retrieve, as
* described in getFrameId.
- * @param {nsIDocShell} docShell - the root docShell object
- * @return {nsIDocShell?} the docShell with the given frameId, or null
- * if no match.
+ * @param {nsIDocShell} rootDocShell - the root docShell object
+ * @returns {nsIDocShell?} the docShell with the given frameId, or null
+ * if no match.
*/
function findDocShell(frameId, rootDocShell) {
for (let docShell of iterateDocShellTree(rootDocShell)) {
if (frameId == getFrameId(docShellToWindow(docShell))) {
return docShell;
}
}