Bug 1248563 - eslint cleanup of storage inspector code r=pbrosset
(In reply to Patrick Brosset [:pbrosset] [:pbro] from comment #4)
> Comment on attachment 8719821
> MozReview Request:
Bug 1248563 - eslint cleanup of storage inspector code
> r?=pbrosset
>
> https://reviewboard.mozilla.org/r/35133/#review31917
>
> Mostly good to go. My most important comment is about not disabling eslint
> entirely in head.js but instead coniguring the unused rule (which is what
> we're doing for other head.js files).
> No need to re-request review after the changed have been done.
Noted.
> One question: with these changes, can the storage inspector be un-ignored
> from .eslintignore, or are there other things left to clean up?
> If so, can you file another bug (good-first, mentored) to finish the cleanup?
>
Unfortunately, the blocker there is defo not a good first bug (
bug 1248447). There is also some CPOW stuff in tests too that should be fixed.
> ::: devtools/client/shared/widgets/TableWidget.js:858
> (Diff revision 1)
> > - return;
> > + return true;
> > }
> >
> > if (event.button == 0 && event.originalTarget == this.header) {
> > return this.table.sortBy(this.id);
>
> Why does this event handler callback even return a value at all?
> `sortBy` doesn't seem to return anything useful anyway.
> ESLint complains about multiple returns when they don't seem to be of the
> same type.
> But this would pass ESLint rules and, I think, be correct:
>
> ```
> if (event.originalTarget == this.column) {
> return;
> }
>
> if (event.button == 0 && event.originalTarget == this.header) {
> this.table.sortBy(this.id)
> }
> ```
>
Changed.
> ::: devtools/client/shared/widgets/TreeWidget.js:487
> (Diff revision 1)
> > + items[this.level];
>
> nit: maybe put each condition on its own line?
> ```
> let label = items[this.level].label ||
> items[this.level].id ||
> items[this.level];
> ```
>
Done
> ::: devtools/client/storage/panel.js:1
> (Diff revision 1)
> > -/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
> > +/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ // eslint-disable-line
>
> I'm not a fan of adding yet another comment at the end of this already long
> line.
> Can't this emacs config line be wrapped on 2 lines?
>
Nope.
> If not, I would advise changing our .eslintrc instead by adding another
> regex part in our max-len ignorePattern regex:
>
> `"max-len": [1, 80, 2, {"ignoreUrls": true, "ignorePattern":
> "\\s*require\\s*\\(|^\\s*loader\\.lazy|-\\*- Mode"}],`
>
Well, It doesn't necessarily contain "Mode" but appending |-\\- works just fine.
> ::: devtools/client/storage/test/head.js:7
> (Diff revision 1)
> > +/* eslint-disable */
>
> I'm guessing you've disabled this whole block because eslint complains about
> unused globals, right?
> If so, there's a better solution than just disabling eslint altogether. Add
> this comment to the top of this head.js file:
>
> ```
> /* eslint no-unused-vars: [2, {"vars": "local"}] */
> ```
>
> This makes sure eslint doesn't complain about unused globals variables in
> this file (but will still complain about unused local variables).
>
I hadn't noticed this... perfect!
> ::: devtools/client/storage/test/head.js:8
> (Diff revision 1)
> > var { console } = Cu.import("resource://gre/modules/Console.jsm", {});
>
> I think you don't need to import console in tests, it's already defined by
> the test runner.
>
Yup, already removed it.
> ::: devtools/client/storage/test/head.js:90
> (Diff revision 1)
> > -function* openTabAndSetupStorage(url) {
> > +function* openTabAndSetupStorage(url) { // eslint-disable-line
>
> This can then be removed.
>
Done
> ::: devtools/client/storage/test/head.js:200
> (Diff revision 1)
> > -function* finishTests() {
> > +function* finishTests() { // eslint-disable-line
>
> And this.
>
Done
> ::: devtools/client/storage/test/head.js:295
> (Diff revision 1)
> > - function fetchError(aProp) {
> > + function fetchError(prop) { // eslint-disable-line
>
> And this.
>
Done
> ::: devtools/client/storage/test/head.js:328
> (Diff revision 1)
> > -function findVariableViewProperties(aRules, aParsed) {
> > +function findVariableViewProperties(ruleArray, parsed) { // eslint-disable-line
>
> And this.
>
Done
> ::: devtools/client/storage/test/head.js:488
> (Diff revision 1)
> > -function* selectTreeItem(ids) {
> > +function* selectTreeItem(ids) { // eslint-disable-line
>
> And this.
>
Done
> ::: devtools/client/storage/test/head.js:509
> (Diff revision 1)
> > -function* selectTableItem(id) {
> > +function* selectTableItem(id) { // eslint-disable-line
>
> And this.
>
Done
> ::: devtools/client/storage/test/head.js:526
> (Diff revision 1)
> > -function once(target, eventName, useCapture=false) {
> > +function once(target, eventName, useCapture = false) { // eslint-disable-line
>
> And this!
>
Done
> ::: devtools/server/actors/storage.js:1808
> (Diff revision 1)
> > - this.childActorPool.set(store, new actor(this));
> > + // Let's use an upper-case constructor to avoid eslint errors.
> > + let Actor = actor;
> > + this.childActorPool.set(store, new Actor(this));
>
> I find this a little easier to read (and no need for the eslint comment):
>
> ```
> for (let [store, ActorConstructor] of storageTypePool) {
> this.childActorPool.set(store, new ActorConstructor(this));
> }
> ```
Changed.
MozReview-Commit-ID: ECnnGUHakMA
--- a/devtools/.eslintrc
+++ b/devtools/.eslintrc
@@ -87,17 +87,17 @@
// Enforces spacing between keys and values in object literal properties.
"key-spacing": [1, {"beforeColon": false, "afterColon": true}],
// Allow mixed 'LF' and 'CRLF' as linebreaks.
"linebreak-style": 0,
// Don't enforce the maximum depth that blocks can be nested. The complexity
// rule is a better rule to check this.
"max-depth": 0,
// Maximum length of a line.
- "max-len": [1, 80, 2, {"ignoreUrls": true, "ignorePattern": "\\s*require\\s*\\(|^\\s*loader\\.lazy"}],
+ "max-len": [1, 80, 2, {"ignoreUrls": true, "ignorePattern": "\\s*require\\s*\\(|^\\s*loader\\.lazy|-\\*-"}],
// Maximum depth callbacks can be nested.
"max-nested-callbacks": [2, 3],
// Don't limit the number of parameters that can be used in a function.
"max-params": 0,
// Don't limit the maximum number of statement allowed in a function. We
// already have the complexity rule that's a better measurement.
"max-statements": 0,
// Require a capital letter for constructors, only check if all new
--- a/devtools/client/shared/widgets/TableWidget.js
+++ b/devtools/client/shared/widgets/TableWidget.js
@@ -1,43 +1,44 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
-const {Cc, Ci, Cu} = require("chrome");
+const {Ci, Cu} = require("chrome");
const EventEmitter = require("devtools/shared/event-emitter");
loader.lazyImporter(this, "setNamedTimeout",
"resource://devtools/client/shared/widgets/ViewHelpers.jsm");
loader.lazyImporter(this, "clearNamedTimeout",
"resource://devtools/client/shared/widgets/ViewHelpers.jsm");
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const HTML_NS = "http://www.w3.org/1999/xhtml";
const AFTER_SCROLL_DELAY = 100;
-// Different types of events emitted by the Various components of the TableWidget
+// Different types of events emitted by the Various components of the
+// TableWidget.
const EVENTS = {
- TABLE_CLEARED: "table-cleared",
+ CELL_EDIT: "cell-edit",
COLUMN_SORTED: "column-sorted",
COLUMN_TOGGLED: "column-toggled",
+ HEADER_CONTEXT_MENU: "header-context-menu",
+ ROW_CONTEXT_MENU: "row-context-menu",
ROW_SELECTED: "row-selected",
ROW_UPDATED: "row-updated",
- HEADER_CONTEXT_MENU: "header-context-menu",
- ROW_CONTEXT_MENU: "row-context-menu",
SCROLL_END: "scroll-end"
};
Object.defineProperty(this, "EVENTS", {
value: EVENTS,
enumerable: true,
writable: false
});
-// Maximum number of character visible in any cell in the table. This is to avoid
-// making the cell take up all the space in a row.
+// Maximum number of character visible in any cell in the table. This is to
+// avoid making the cell take up all the space in a row.
const MAX_VISIBLE_STRING_SIZE = 100;
/**
* A table widget with various features like resizble/toggleable columns,
* sorting, keyboard navigation etc.
*
* @param {nsIDOMNode} node
* The container element for the table widget.
@@ -47,17 +48,17 @@ const MAX_VISIBLE_STRING_SIZE = 100;
* - uniqueId: the column which will be the unique identifier of each
* entry in the table. Default: name.
* - emptyText: text to display when no entries in the table to display.
* - highlightUpdated: true to highlight the changed/added row.
* - removableColumns: Whether columns are removeable. If set to false,
* the context menu in the headers will not appear.
* - firstColumn: key of the first column that should appear.
*/
-function TableWidget(node, options={}) {
+function TableWidget(node, options = {}) {
EventEmitter.decorate(this);
this.document = node.ownerDocument;
this.window = this.document.defaultView;
this._parent = node;
let {initialColumns, emptyText, uniqueId, highlightUpdated, removableColumns,
firstColumn} = options;
@@ -78,33 +79,34 @@ function TableWidget(node, options={}) {
this.placeholder = this.document.createElementNS(XUL_NS, "label");
this.placeholder.className = "plain table-widget-empty-text";
this.placeholder.setAttribute("flex", "1");
this._parent.appendChild(this.placeholder);
this.items = new Map();
this.columns = new Map();
- // Setup the column headers context menu to allow users to hide columns at will
+ // Setup the column headers context menu to allow users to hide columns at
+ // will.
if (this.removableColumns) {
- this.onPopupCommand = this.onPopupCommand.bind(this)
+ this.onPopupCommand = this.onPopupCommand.bind(this);
this.setupHeadersContextMenu();
}
if (initialColumns) {
this.setColumns(initialColumns, uniqueId);
} else if (this.emptyText) {
this.setPlaceholderText(this.emptyText);
}
this.bindSelectedRow = (event, id) => {
this.selectedRow = id;
};
this.on(EVENTS.ROW_SELECTED, this.bindSelectedRow);
-};
+}
TableWidget.prototype = {
items: null,
/**
* Getter for the headers context menu popup id.
*/
@@ -157,19 +159,19 @@ TableWidget.prototype = {
/**
* Sets the text to be shown when the table is empty.
*/
setPlaceholderText: function(text) {
this.placeholder.setAttribute("value", text);
},
/**
- * Prepares the context menu for the headers of the table columns. This context
- * menu allows users to toggle various columns, only with an exception of the
- * unique columns and when only two columns are visible in the table.
+ * Prepares the context menu for the headers of the table columns. This
+ * context menu allows users to toggle various columns, only with an exception
+ * of the unique columns and when only two columns are visible in the table.
*/
setupHeadersContextMenu: function() {
let popupset = this.document.getElementsByTagName("popupset")[0];
if (!popupset) {
popupset = this.document.createElementNS(XUL_NS, "popupset");
this.document.documentElement.appendChild(popupset);
}
@@ -303,17 +305,18 @@ TableWidget.prototype = {
*/
selectNextRow: function() {
for (let column of this.columns.values()) {
column.selectNextRow();
}
},
/**
- * Selects the previous row. Cycles over to the last row if first row is selected
+ * Selects the previous row. Cycles over to the last row if first row is
+ * selected.
*/
selectPreviousRow: function() {
for (let column of this.columns.values()) {
column.selectPreviousRow();
}
},
/**
@@ -425,19 +428,19 @@ TableWidget.prototype = {
this.emit(EVENTS.COLUMN_SORTED, column);
this.sortedOn = column;
if (!this.items.size) {
return;
}
let sortedItems = this.columns.get(column).sort([...this.items.values()]);
- for (let [id, column] of this.columns) {
- if (id != column) {
- column.sort(sortedItems);
+ for (let [id, col] of this.columns) {
+ if (id != col) {
+ col.sort(sortedItems);
}
}
},
/**
* Calls the afterScroll function when the user has stopped scrolling
*/
onScroll: function() {
@@ -668,18 +671,18 @@ Column.prototype = {
if (index == -1) {
index = this.cells.length - 1;
}
this.selectRowAt(index);
},
/**
* Pushes the `item` object into the column. If this column is sorted on,
- * then inserts the object at the right position based on the column's id key's
- * value.
+ * then inserts the object at the right position based on the column's id
+ * key's value.
*
* @returns {number}
* The index of the currently pushed item.
*/
push: function(item) {
let value = item[this.id];
if (this.sorted) {
@@ -851,17 +854,17 @@ Column.prototype = {
* for sorting.
*/
onClick: function(event) {
if (event.originalTarget == this.column) {
return;
}
if (event.button == 0 && event.originalTarget == this.header) {
- return this.table.sortBy(this.id);
+ this.table.sortBy(this.id);
}
},
/**
* Mousedown event handler for the column. Used to select rows.
*/
onMousedown: function(event) {
if (event.originalTarget == this.column ||
@@ -965,17 +968,17 @@ Cell.prototype = {
this._value = value;
if (value == null) {
this.label.setAttribute("value", "");
return;
}
if (!(value instanceof Ci.nsIDOMNode) &&
value.length > MAX_VISIBLE_STRING_SIZE) {
- value = value .substr(0, MAX_VISIBLE_STRING_SIZE) + "\u2026"; // …
+ value = value .substr(0, MAX_VISIBLE_STRING_SIZE) + "\u2026";
}
if (value instanceof Ci.nsIDOMNode) {
this.label.removeAttribute("value");
while (this.label.firstChild) {
this.label.removeChild(this.label.firstChild);
}
@@ -996,21 +999,21 @@ Cell.prototype = {
/**
* Flashes the cell for a brief time. This when done for ith cells in all
* columns, makes it look like the row is being highlighted/flashed.
*/
flash: function() {
this.label.classList.remove("flash-out");
// Cause a reflow so that the animation retriggers on adding back the class
- let a = this.label.parentNode.offsetWidth;
+ let a = this.label.parentNode.offsetWidth; // eslint-disable-line
this.label.classList.add("flash-out");
},
focus: function() {
this.label.focus();
},
destroy: function() {
this.label.remove();
this.label = null;
}
-}
+};
--- a/devtools/client/shared/widgets/TreeWidget.js
+++ b/devtools/client/shared/widgets/TreeWidget.js
@@ -1,32 +1,32 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
-const Services = require("Services")
const HTML_NS = "http://www.w3.org/1999/xhtml";
const EventEmitter = require("devtools/shared/event-emitter");
/**
* A tree widget with keyboard navigation and collapsable structure.
*
* @param {nsIDOMNode} node
* The container element for the tree widget.
* @param {Object} options
* - emptyText {string}: text to display when no entries in the table.
- * - defaultType {string}: The default type of the tree items. For ex. 'js'
+ * - defaultType {string}: The default type of the tree items. For ex.
+ * 'js'
* - sorted {boolean}: Defaults to true. If true, tree items are kept in
* lexical order. If false, items will be kept in insertion order.
*/
-function TreeWidget(node, options={}) {
+function TreeWidget(node, options = {}) {
EventEmitter.decorate(this);
this.document = node.ownerDocument;
this.window = this.document.defaultView;
this._parent = node;
this.emptyText = options.emptyText || "";
this.defaultType = options.defaultType;
@@ -38,17 +38,17 @@ function TreeWidget(node, options={}) {
this.placeholder.className = "tree-widget-empty-text";
this._parent.appendChild(this.placeholder);
if (this.emptyText) {
this.setPlaceholderText(this.emptyText);
}
// A map to hold all the passed attachment to each leaf in the tree.
this.attachments = new Map();
-};
+}
TreeWidget.prototype = {
_selectedLabel: null,
_selectedItem: null,
/**
* Select any node in the tree.
@@ -215,17 +215,18 @@ TreeWidget.prototype = {
},
clearSelection: function() {
this.selectedItem = -1;
},
/**
* Adds an item in the tree. The item can be added as a child to any node in
- * the tree. The method will also create any subnode not present in the process.
+ * the tree. The method will also create any subnode not present in the
+ * process.
*
* @param {[string|object]} items
* An array of either string or objects where each increasing index
* represents an item corresponding to an equivalent depth in the tree.
* Each array element can be either just a string with the value as the
* id of of that item as well as the display value, or it can be an
* object with the following propeties:
* - id {string} The id of the item
@@ -261,17 +262,17 @@ TreeWidget.prototype = {
/**
* Removes the specified item and all of its child items from the tree.
*
* @param {array} item
* The array of ids leading up to the item.
*/
remove: function(item) {
- this.root.remove(item)
+ this.root.remove(item);
this.attachments.delete(JSON.stringify(item));
// Display the empty tree text
if (this.root.items.size == 0 && this.emptyText) {
this.setPlaceholderText(this.emptyText);
}
},
/**
@@ -332,17 +333,17 @@ TreeWidget.prototype = {
},
/**
* Keypress handler for this tree. Used to select next and previous visible
* items, as well as collapsing and expanding any item.
*/
onKeypress: function(event) {
let currentSelected = this._selectedLabel;
- switch(event.keyCode) {
+ switch (event.keyCode) {
case event.DOM_VK_UP:
this.selectPreviousItem();
break;
case event.DOM_VK_DOWN:
this.selectNextItem();
break;
@@ -399,34 +400,34 @@ module.exports.TreeWidget = TreeWidget;
* The parent item for this item.
* @param {string|DOMElement} label
* Either the dom node to be used as the item, or the string to be
* displayed for this node in the tree
* @param {string} type
* The type of the current node. For ex. "js"
*/
function TreeItem(document, parent, label, type) {
- this.document = document
+ this.document = document;
this.node = this.document.createElementNS(HTML_NS, "li");
this.node.setAttribute("tabindex", "0");
this.isRoot = !parent;
this.parent = parent;
if (this.parent) {
this.level = this.parent.level + 1;
}
- if (!!label) {
+ if (label) {
this.label = this.document.createElementNS(HTML_NS, "div");
this.label.setAttribute("empty", "true");
this.label.setAttribute("level", this.level);
this.label.className = "tree-widget-item";
if (type) {
this.label.setAttribute("type", type);
}
if (typeof label == "string") {
- this.label.textContent = label
+ this.label.textContent = label;
} else {
this.label.appendChild(label);
}
this.node.appendChild(this.label);
}
this.children = this.document.createElementNS(HTML_NS, "ul");
if (this.isRoot) {
this.children.className = "tree-widget-container";
@@ -449,18 +450,18 @@ TreeItem.prototype = {
parent: null,
children: null,
level: 0,
/**
- * Adds the item to the sub tree contained by this node. The item to be inserted
- * can be a direct child of this node, or further down the tree.
+ * Adds the item to the sub tree contained by this node. The item to be
+ * inserted can be a direct child of this node, or further down the tree.
*
* @param {array} items
* Same as TreeWidget.add method's argument
* @param {string} defaultType
* The default type of the item to be used when items[i].type is null
* @param {boolean} sorted
* true if the tree items are inserted in a lexically sorted manner.
* Otherwise, false if the item are to be appended to their parent.
@@ -468,26 +469,28 @@ TreeItem.prototype = {
add: function(items, defaultType, sorted) {
if (items.length == this.level) {
// This is the exit condition of recursive TreeItem.add calls
return;
}
// Get the id and label corresponding to this level inside the tree.
let id = items[this.level].id || items[this.level];
if (this.items.has(id)) {
- // An item with same id already exists, thus calling the add method of that
- // child to add the passed node at correct position.
+ // An item with same id already exists, thus calling the add method of
+ // that child to add the passed node at correct position.
this.items.get(id).add(items, defaultType, sorted);
return;
}
// No item with the id `id` exists, so we create one and call the add
// method of that item.
- // The display string of the item can be the label, the id, or the item itself
- // if its a plain string.
- let label = items[this.level].label || items[this.level].id || items[this.level];
+ // The display string of the item can be the label, the id, or the item
+ // itself if its a plain string.
+ let label = items[this.level].label ||
+ items[this.level].id ||
+ items[this.level];
let node = items[this.level].node;
if (node) {
// The item is supposed to be a DOMNode, so we fetch the textContent in
// order to find the correct sorted location of this new item.
label = node.textContent;
}
let treeItem = new TreeItem(this.document, this, node || label,
items[this.level].type || defaultType);
--- a/devtools/client/storage/panel.js
+++ b/devtools/client/storage/panel.js
@@ -1,17 +1,16 @@
/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
-const {Cu} = require("chrome");
const EventEmitter = require("devtools/shared/event-emitter");
loader.lazyRequireGetter(this, "StorageFront",
"devtools/server/actors/storage", true);
loader.lazyRequireGetter(this, "StorageUI",
"devtools/client/storage/ui", true);
var StoragePanel = this.StoragePanel =
--- a/devtools/client/storage/test/browser_storage_basic.js
+++ b/devtools/client/storage/test/browser_storage_basic.js
@@ -57,18 +57,18 @@ const testCases = [
["obj-s1"]],
[["indexedDB", "https://sectest1.example.org", "idb-s2"],
["obj-s2"]],
[["indexedDB", "https://sectest1.example.org", "idb-s1", "obj-s1"],
[6, 7]],
[["indexedDB", "https://sectest1.example.org", "idb-s2", "obj-s2"],
[16]],
[["Cache", "http://test1.example.org", "plop"],
- [MAIN_DOMAIN + "404_cached_file.js", MAIN_DOMAIN + "browser_storage_basic.js"]],
-
+ [MAIN_DOMAIN + "404_cached_file.js",
+ MAIN_DOMAIN + "browser_storage_basic.js"]],
];
/**
* Test that the desired number of tree items are present
*/
function testTree() {
let doc = gPanelWindow.document;
for (let item of testCases) {
--- a/devtools/client/storage/test/head.js
+++ b/devtools/client/storage/test/head.js
@@ -1,15 +1,16 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
-var { console } = Cu.import("resource://gre/modules/Console.jsm", {});
+/* eslint no-unused-vars: [2, {"vars": "local"}] */
+
var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
var { TargetFactory } = require("devtools/client/framework/target");
var promise = require("promise");
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
const SPLIT_CONSOLE_PREF = "devtools.toolbox.splitconsoleEnabled";
const STORAGE_PREF = "devtools.storage.enabled";
const DUMPEMIT_PREF = "devtools.dump.emit";
@@ -87,23 +88,23 @@ function addTab(url) {
*/
function* openTabAndSetupStorage(url) {
let content = yield addTab(url);
gWindow = content.wrappedJSObject;
// Setup the async storages in main window and for all its iframes
let callSetup = function*(win) {
- if (typeof(win.setup) == "function") {
+ if (typeof (win.setup) == "function") {
yield win.setup();
}
- for(var i = 0; i < win.frames.length; i++) {
+ for (let i = 0; i < win.frames.length; i++) {
yield callSetup(win.frames[i]);
}
- }
+ };
yield callSetup(gWindow);
// open storage inspector
return yield openStoragePanel();
}
/**
* Open the toolbox, with the storage tool visible.
@@ -249,159 +250,155 @@ function* click(node) {
}, 200);
return def;
}
/**
* Recursively expand the variables view up to a given property.
*
- * @param aOptions
+ * @param options
* Options for view expansion:
* - rootVariable: start from the given scope/variable/property.
* - expandTo: string made up of property names you want to expand.
* For example: "body.firstChild.nextSibling" given |rootVariable:
* document|.
* @return object
* A promise that is resolved only when the last property in |expandTo|
* is found, and rejected otherwise. Resolution reason is always the
* last property - |nextSibling| in the example above. Rejection is
* always the last property that was found.
*/
-function variablesViewExpandTo(aOptions) {
- let root = aOptions.rootVariable;
- let expandTo = aOptions.expandTo.split(".");
+function variablesViewExpandTo(options) {
+ let root = options.rootVariable;
+ let expandTo = options.expandTo.split(".");
let lastDeferred = promise.defer();
- function getNext(aProp) {
+ function getNext(prop) {
let name = expandTo.shift();
- let newProp = aProp.get(name);
+ let newProp = prop.get(name);
if (expandTo.length > 0) {
ok(newProp, "found property " + name);
if (newProp && newProp.expand) {
newProp.expand();
getNext(newProp);
} else {
- lastDeferred.reject(aProp);
+ lastDeferred.reject(prop);
}
} else if (newProp) {
lastDeferred.resolve(newProp);
} else {
- lastDeferred.reject(aProp);
+ lastDeferred.reject(prop);
}
}
- function fetchError(aProp) {
- lastDeferred.reject(aProp);
- }
-
if (root && root.expand) {
root.expand();
getNext(root);
} else {
lastDeferred.resolve(root);
}
return lastDeferred.promise;
}
/**
* Find variables or properties in a VariablesView instance.
*
- * @param array aRules
+ * @param array ruleArray
* The array of rules you want to match. Each rule is an object with:
* - name (string|regexp): property name to match.
* - value (string|regexp): property value to match.
* - dontMatch (boolean): make sure the rule doesn't match any property.
- * @param boolean aParsed
+ * @param boolean parsed
* true if we want to test the rules in the parse value section of the
* storage sidebar
* @return object
* A promise object that is resolved when all the rules complete
* matching. The resolved callback is given an array of all the rules
* you wanted to check. Each rule has a new property: |matchedProp|
* which holds a reference to the Property object instance from the
* VariablesView. If the rule did not match, then |matchedProp| is
* undefined.
*/
-function findVariableViewProperties(aRules, aParsed) {
+function findVariableViewProperties(ruleArray, parsed) {
// Initialize the search.
function init() {
- // If aParsed is true, we are checking rules in the parsed value section of
+ // If parsed is true, we are checking rules in the parsed value section of
// the storage sidebar. That scope uses a blank variable as a placeholder
// Thus, adding a blank parent to each name
- if (aParsed) {
- aRules = aRules.map(({name, value, dontMatch}) => {
+ if (parsed) {
+ ruleArray = ruleArray.map(({name, value, dontMatch}) => {
return {name: "." + name, value, dontMatch};
});
}
// Separate out the rules that require expanding properties throughout the
// view.
let expandRules = [];
- let rules = aRules.filter((aRule) => {
- if (typeof aRule.name == "string" && aRule.name.indexOf(".") > -1) {
- expandRules.push(aRule);
+ let rules = ruleArray.filter(rule => {
+ if (typeof rule.name == "string" && rule.name.indexOf(".") > -1) {
+ expandRules.push(rule);
return false;
}
return true;
});
// Search through the view those rules that do not require any properties to
// be expanded. Build the array of matchers, outstanding promises to be
// resolved.
let outstanding = [];
finder(rules, gUI.view, outstanding);
// Process the rules that need to expand properties.
let lastStep = processExpandRules.bind(null, expandRules);
- // Return the results - a promise resolved to hold the updated aRules array.
- let returnResults = onAllRulesMatched.bind(null, aRules);
+ // Return the results - a promise resolved to hold the updated ruleArray.
+ let returnResults = onAllRulesMatched.bind(null, ruleArray);
return promise.all(outstanding).then(lastStep).then(returnResults);
}
- function onMatch(aProp, aRule, aMatched) {
- if (aMatched && !aRule.matchedProp) {
- aRule.matchedProp = aProp;
+ function onMatch(prop, rule, matched) {
+ if (matched && !rule.matchedProp) {
+ rule.matchedProp = prop;
}
}
- function finder(rules, aView, aPromises) {
- for (let scope of aView) {
+ function finder(rules, view, promises) {
+ for (let scope of view) {
for (let [, prop] of scope) {
for (let rule of rules) {
let matcher = matchVariablesViewProperty(prop, rule);
- aPromises.push(matcher.then(onMatch.bind(null, prop, rule)));
+ promises.push(matcher.then(onMatch.bind(null, prop, rule)));
}
}
}
}
function processExpandRules(rules) {
let rule = rules.shift();
if (!rule) {
return promise.resolve(null);
}
let deferred = promise.defer();
let expandOptions = {
- rootVariable: gUI.view.getScopeAtIndex(aParsed ? 1 : 0),
+ rootVariable: gUI.view.getScopeAtIndex(parsed ? 1 : 0),
expandTo: rule.name
};
- variablesViewExpandTo(expandOptions).then(function onSuccess(aProp) {
+ variablesViewExpandTo(expandOptions).then(function onSuccess(prop) {
let name = rule.name;
let lastName = name.split(".").pop();
rule.name = lastName;
- let matched = matchVariablesViewProperty(aProp, rule);
- return matched.then(onMatch.bind(null, aProp, rule)).then(function() {
+ let matched = matchVariablesViewProperty(prop, rule);
+ return matched.then(onMatch.bind(null, prop, rule)).then(function() {
rule.name = name;
});
}, function onFailure() {
return promise.resolve(null);
}).then(processExpandRules.bind(null, rules)).then(function() {
deferred.resolve(null);
});
@@ -425,56 +422,56 @@ function findVariableViewProperties(aRul
return init();
}
/**
* Check if a given Property object from the variables view matches the given
* rule.
*
- * @param object aProp
+ * @param object prop
* The variable's view Property instance.
- * @param object aRule
+ * @param object rule
* Rules for matching the property. See findVariableViewProperties() for
* details.
* @return object
* A promise that is resolved when all the checks complete. Resolution
* result is a boolean that tells your promise callback the match
* result: true or false.
*/
-function matchVariablesViewProperty(aProp, aRule) {
- function resolve(aResult) {
- return promise.resolve(aResult);
+function matchVariablesViewProperty(prop, rule) {
+ function resolve(result) {
+ return promise.resolve(result);
}
- if (!aProp) {
+ if (!prop) {
return resolve(false);
}
- if (aRule.name) {
- let match = aRule.name instanceof RegExp ?
- aRule.name.test(aProp.name) :
- aProp.name == aRule.name;
+ if (rule.name) {
+ let match = rule.name instanceof RegExp ?
+ rule.name.test(prop.name) :
+ prop.name == rule.name;
if (!match) {
return resolve(false);
}
}
- if ("value" in aRule) {
- let displayValue = aProp.displayValue;
- if (aProp.displayValueClassName == "token-string") {
+ if ("value" in rule) {
+ let displayValue = prop.displayValue;
+ if (prop.displayValueClassName == "token-string") {
displayValue = displayValue.substring(1, displayValue.length - 1);
}
- let match = aRule.value instanceof RegExp ?
- aRule.value.test(displayValue) :
- displayValue == aRule.value;
+ let match = rule.value instanceof RegExp ?
+ rule.value.test(displayValue) :
+ displayValue == rule.value;
if (!match) {
- info("rule " + aRule.name + " did not match value, expected '" +
- aRule.value + "', found '" + displayValue + "'");
+ info("rule " + rule.name + " did not match value, expected '" +
+ rule.value + "', found '" + displayValue + "'");
return resolve(false);
}
}
return resolve(true);
}
/**
@@ -516,17 +513,17 @@ function* selectTableItem(id) {
/**
* Wait for eventName on target.
* @param {Object} target An observable object that either supports on/off or
* addEventListener/removeEventListener
* @param {String} eventName
* @param {Boolean} [useCapture] for addEventListener/removeEventListener
* @return A promise that resolves when the event has been handled
*/
-function once(target, eventName, useCapture=false) {
+function once(target, eventName, useCapture = false) {
info("Waiting for event: '" + eventName + "' on " + target + ".");
let deferred = promise.defer();
for (let [add, remove] of [
["addEventListener", "removeEventListener"],
["addListener", "removeListener"],
["on", "off"]
--- a/devtools/client/storage/ui.js
+++ b/devtools/client/storage/ui.js
@@ -64,16 +64,17 @@ var StorageUI = this.StorageUI = functio
this.onHostSelect = this.onHostSelect.bind(this);
this.tree.on("select", this.onHostSelect);
let tableNode = this._panelDoc.getElementById("storage-table");
this.table = new TableWidget(tableNode, {
emptyText: L10N.getStr("table.emptyText"),
highlightUpdated: true,
});
+
this.displayObjectSidebar = this.displayObjectSidebar.bind(this);
this.table.on(TableWidget.EVENTS.ROW_SELECTED, this.displayObjectSidebar);
this.handleScrollEnd = this.handleScrollEnd.bind(this);
this.table.on(TableWidget.EVENTS.SCROLL_END, this.handleScrollEnd);
this.sidebar = this._panelDoc.getElementById("storage-sidebar");
this.sidebar.setAttribute("width", "300");
@@ -145,17 +146,17 @@ StorageUI.prototype = {
/**
* Event handler for "stores-cleared" event coming from the storage actor.
*
* @param {object} argument0
* An object containing which storage types were cleared
*/
onCleared: function(response) {
- let [type, host, db, objectStore] = this.tree.selectedItem;
+ let [type, host] = this.tree.selectedItem;
if (response.hasOwnProperty(type) && response[type].indexOf(host) > -1) {
this.table.clear();
this.hideSidebar();
this.emit("store-objects-cleared");
}
},
/**
@@ -214,17 +215,17 @@ StorageUI.prototype = {
if (name.length == 3) {
name.splice(2, 1);
}
this.tree.add([type, host, ...name]);
if (!this.tree.selectedItem) {
this.tree.selectedItem = [type, host, name[0], name[1]];
this.fetchStorageObjects(type, host, [JSON.stringify(name)], 1);
}
- } catch(ex) {
+ } catch (ex) {
// Do nothing
}
}
if (this.tree.isSelected([type, host])) {
this.fetchStorageObjects(type, host, added[type][host], 1);
}
}
@@ -312,17 +313,19 @@ StorageUI.prototype = {
* @param {number} reason
* 3 for loading next 50 items, 2 for update, 1 for new row in an
* existing table and 0 when populating a table for the first time
* for the given host/type
*/
fetchStorageObjects: function(type, host, names, reason) {
let fetchOpts = reason === 3 ? {offset: this.itemOffset}
: {};
- this.storageTypes[type].getStoreObjects(host, names, fetchOpts).then(({data}) => {
+ let storageType = this.storageTypes[type];
+
+ storageType.getStoreObjects(host, names, fetchOpts).then(({data}) => {
if (!data.length) {
this.emit("store-objects-updated");
return;
}
if (this.shouldResetColumns) {
this.resetColumns(data[0], type);
}
this.populateTable(data, reason);
@@ -336,24 +339,25 @@ StorageUI.prototype = {
*
* @param {object} storageTypes
* List of storages and their corresponding hosts returned by the
* StorageFront.listStores call.
*/
populateStorageTree: function(storageTypes) {
this.storageTypes = {};
for (let type in storageTypes) {
- // Ignore `from` field, which is just a protocol.js implementation artifact
+ // Ignore `from` field, which is just a protocol.js implementation
+ // artifact.
if (type === "from") {
continue;
}
let typeLabel = type;
try {
typeLabel = L10N.getStr("tree.labels." + type);
- } catch(e) {
+ } catch (e) {
console.error("Unable to localize tree label type:" + type);
}
this.tree.add([{id: type, label: typeLabel, type: "store"}]);
if (!storageTypes[type].hosts) {
continue;
}
this.storageTypes[type] = storageTypes[type];
for (let host in storageTypes[type].hosts) {
@@ -361,17 +365,17 @@ StorageUI.prototype = {
for (let name of storageTypes[type].hosts[host]) {
try {
let names = JSON.parse(name);
this.tree.add([type, host, ...names]);
if (!this.tree.selectedItem) {
this.tree.selectedItem = [type, host, names[0], names[1]];
this.fetchStorageObjects(type, host, [name], 0);
}
- } catch(ex) {
+ } catch (ex) {
// Do Nothing
}
}
if (!this.tree.selectedItem) {
this.tree.selectedItem = [type, host];
this.fetchStorageObjects(type, host, null, 0);
}
}
@@ -571,18 +575,19 @@ StorageUI.prototype = {
let uniqueKey = null;
for (let key in data) {
if (!uniqueKey) {
this.table.uniqueId = uniqueKey = key;
}
columns[key] = key;
try {
columns[key] = L10N.getStr("table.headers." + type + "." + key);
- } catch(e) {
- console.error("Unable to localize table header type:" + type + " key:" + key);
+ } catch (e) {
+ console.error("Unable to localize table header type:" + type +
+ " key:" + key);
}
}
this.table.setColumns(columns, null, HIDDEN_COLUMNS);
this.shouldResetColumns = false;
this.hideSidebar();
},
/**
@@ -638,21 +643,23 @@ StorageUI.prototype = {
event.preventDefault();
}
},
/**
* Handles endless scrolling for the table
*/
handleScrollEnd: function() {
- if (!this.shouldLoadMoreItems) return;
+ if (!this.shouldLoadMoreItems) {
+ return;
+ }
this.shouldLoadMoreItems = false;
this.itemOffset += 50;
let item = this.tree.selectedItem;
- let [type, host, db, objectStore] = item;
+ let [type, host] = item;
let names = null;
if (item.length > 2) {
names = [JSON.stringify(item.slice(2))];
}
this.fetchStorageObjects(type, host, names, 3);
}
};
--- a/devtools/server/actors/storage.js
+++ b/devtools/server/actors/storage.js
@@ -711,27 +711,27 @@ var cookieHelpers = {
return null;
},
observe: function(subject, topic, data) {
switch (topic) {
case "cookie-changed":
let cookie = subject.QueryInterface(Ci.nsICookie2);
cookieHelpers.onCookieChanged(cookie, topic, data);
- break;
+ break;
}
},
handleParentRequest: function(msg) {
switch (msg.json.method) {
case "onCookieChanged":
let [cookie, topic, data] = msg.data.args;
cookie = JSON.parse(cookie);
cookieHelpers.onCookieChanged(cookie, topic, data);
- break;
+ break;
}
},
handleChildRequest: function(msg) {
switch (msg.json.method) {
case "getCookiesFromHost":
let host = msg.data.args[0];
let cookies = cookieHelpers.getCookiesFromHost(host);
@@ -759,19 +759,19 @@ exports.setupParentProcessForCookies = f
mm.addMessageListener("storage:storage-cookie-request-parent",
cookieHelpers.handleChildRequest);
DebuggerServer.once("disconnected-from-child:" + prefix,
handleMessageManagerDisconnected);
gTrackedMessageManager.set("cookies", mm);
- function handleMessageManagerDisconnected(evt, { mm: disconnected_mm }) {
+ function handleMessageManagerDisconnected(evt, { mm: disconnectedMm }) {
// filter out not subscribed message managers
- if (disconnected_mm !== mm || !gTrackedMessageManager.has("cookies")) {
+ if (disconnectedMm !== mm || !gTrackedMessageManager.has("cookies")) {
return;
}
// Although "disconnected-from-child" implies that the child is already
// disconnected this is not the case. The disconnection takes place after
// this method has finished. This gives us chance to clean up items within
// the parent process e.g. observers.
cookieHelpers.removeCookieObservers();
@@ -789,17 +789,17 @@ exports.setupParentProcessForCookies = f
args[0] = JSON.stringify(args[0]);
}
try {
mm.sendAsyncMessage("storage:storage-cookie-request-child", {
method: methodName,
args: args
});
- } catch(e) {
+ } catch (e) {
// We may receive a NS_ERROR_NOT_INITIALIZED if the target window has
// been closed. This can legitimately happen in between test runs.
}
}
};
/**
* Helper method to create the overriden object required in
@@ -832,30 +832,30 @@ function getObjectForLocalOrSessionStora
return location.href;
}
return location.protocol + "//" + location.host;
},
populateStoresForHost: function(host, window) {
try {
this.hostVsStores.set(host, window[type]);
- } catch(ex) {
+ } catch (ex) {
// Exceptions happen when local or session storage is inaccessible
}
return null;
},
populateStoresForHosts: function() {
this.hostVsStores = new Map();
try {
for (let window of this.windows) {
this.hostVsStores.set(this.getHostName(window.location),
window[type]);
}
- } catch(ex) {
+ } catch (ex) {
// Exceptions happen when local or session storage is inaccessible
}
return null;
},
observe: function(subject, topic, data) {
if (topic != "dom-storage2-changed" || data != type) {
return null;
@@ -917,21 +917,16 @@ StorageActors.createActor({
* The Session Storage actor and front.
*/
StorageActors.createActor({
typeName: "sessionStorage",
observationTopic: "dom-storage2-changed",
storeObjectType: "storagestoreobject"
}, getObjectForLocalOrSessionStorage("sessionStorage"));
-
-let CacheAttributes = [
- "url",
- "status",
-];
types.addDictType("cacheobject", {
"url": "string",
"status": "string"
});
// Array of Cache store objects
types.addDictType("cachestoreobject", {
total: "number",
@@ -940,23 +935,25 @@ types.addDictType("cachestoreobject", {
});
StorageActors.createActor({
typeName: "Cache",
storeObjectType: "cachestoreobject"
}, {
getCachesForHost: Task.async(function*(host) {
let uri = Services.io.newURI(host, null, null);
- let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
+ let principal =
+ Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
- // The first argument tells if you want to get |content| cache or |chrome| cache.
+ // The first argument tells if you want to get |content| cache or |chrome|
+ // cache.
// The |content| cache is the cache explicitely named by the web content
// (service worker or web page).
- // The |chrome| cache is the cache implicitely cached by the platform, hosting the
- // source file of the service worker.
+ // The |chrome| cache is the cache implicitely cached by the platform,
+ // hosting the source file of the service worker.
let { CacheStorage } = this.storageActor.window;
let cache = new CacheStorage("content", principal);
return cache;
}),
preListStores: Task.async(function*() {
for (let host of this.hosts) {
yield this.populateStoresForHost(host);
@@ -976,28 +973,32 @@ StorageActors.createActor({
return {
actor: this.actorID,
hosts: hosts
};
},
getNamesForHost: function(host) {
// UI code expect each name to be a JSON string of an array :/
- return [...this.hostVsStores.get(host).keys()].map(a => JSON.stringify([a]));
+ return [...this.hostVsStores.get(host).keys()].map(a => {
+ return JSON.stringify([a]);
+ });
},
getValuesForHost: Task.async(function*(host, name) {
- if (!name) return [];
+ if (!name) {
+ return [];
+ }
// UI is weird and expect a JSON stringified array... and pass it back :/
name = JSON.parse(name)[0];
let cache = this.hostVsStores.get(host).get(name);
let requests = yield cache.keys();
let results = [];
- for(let request of requests) {
+ for (let request of requests) {
let response = yield cache.match(request);
// Unwrap the response to get access to all its properties if the
// response happen to be 'opaque', when it is a Cross Origin Request.
response = response.cloneUnfiltered();
results.push(yield this.processEntry(request, response));
}
return results;
}),
@@ -1011,17 +1012,17 @@ StorageActors.createActor({
getHostName: function(location) {
if (!location.host) {
return location.href;
}
return location.protocol + "//" + location.host;
},
- populateStoresForHost: Task.async(function*(host, window) {
+ populateStoresForHost: Task.async(function*(host) {
let storeMap = new Map();
let caches = yield this.getCachesForHost(host);
for (let name of (yield caches.keys())) {
storeMap.set(name, (yield caches.open(name)));
}
this.hostVsStores.set(host, storeMap);
}),
@@ -1376,17 +1377,17 @@ StorageActors.createActor({
case "backToChild":
let func = msg.json.args.shift();
let deferred = unresolvedPromises.get(func);
if (deferred) {
unresolvedPromises.delete(func);
deferred.resolve(msg.json.args[0]);
}
- break;
+ break;
}
});
let unresolvedPromises = new Map();
function callParentProcessAsync(methodName, ...args) {
let deferred = promise.defer();
unresolvedPromises.set(methodName, deferred);
@@ -1444,17 +1445,18 @@ var indexedDBHelpers = {
*/
openWithOrigin: function(host, name) {
let principal;
if (/^(about:|chrome:)/.test(host)) {
principal = Services.scriptSecurityManager.getSystemPrincipal();
} else {
let uri = Services.io.newURI(host, null, null);
- principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
+ principal = Services.scriptSecurityManager
+ .createCodebasePrincipal(uri, {});
}
return require("indexedDB").openForPrincipal(principal, name);
},
/**
* Fetches all the databases and their metadata for the given `host`.
*/
@@ -1728,19 +1730,19 @@ exports.setupParentProcessForIndexedDB =
mm.addMessageListener("storage:storage-indexedDB-request-parent",
indexedDBHelpers.handleChildRequest);
DebuggerServer.once("disconnected-from-child:" + prefix,
handleMessageManagerDisconnected);
gTrackedMessageManager.set("indexedDB", mm);
- function handleMessageManagerDisconnected(evt, { mm: disconnected_mm }) {
+ function handleMessageManagerDisconnected(evt, { mm: disconnectedMm }) {
// filter out not subscribed message managers
- if (disconnected_mm !== mm || !gTrackedMessageManager.has("indexedDB")) {
+ if (disconnectedMm !== mm || !gTrackedMessageManager.has("indexedDB")) {
return;
}
gTrackedMessageManager.delete("indexedDB");
// unregister for director-script requests handlers from the parent process
// (if any)
mm.removeMessageListener("storage:storage-indexedDB-request-parent",
@@ -1797,18 +1799,18 @@ var StorageActor = exports.StorageActor
this.childActorPool = new Map();
this.childWindowPool = new Set();
// Fetch all the inner iframe windows in this tab.
this.fetchChildWindows(this.parentActor.docShell);
// Initialize the registered store types
- for (let [store, actor] of storageTypePool) {
- this.childActorPool.set(store, new actor(this));
+ for (let [store, ActorConstructor] of storageTypePool) {
+ this.childActorPool.set(store, new ActorConstructor(this));
}
// Notifications that help us keep track of newly added windows and windows
// that got removed
Services.obs.addObserver(this, "content-document-global-created", false);
Services.obs.addObserver(this, "inner-window-destroyed", false);
this.onPageChange = this.onPageChange.bind(this);
@@ -2084,15 +2086,15 @@ var StorageActor = exports.StorageActor
}
return null;
}
});
/**
* Front for the Storage Actor.
*/
-var StorageFront = exports.StorageFront = protocol.FrontClass(StorageActor, {
+exports.StorageFront = protocol.FrontClass(StorageActor, {
initialize: function(client, tabForm) {
protocol.Front.prototype.initialize.call(this, client);
this.actorID = tabForm.storageActor;
this.manage(this);
}
});