зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1231434 - Add 'Delete All' context menu entry to storage inspector. r=mratcliffe
This commit is contained in:
Родитель
d8f23fae58
Коммит
4840f48bea
|
@ -6,3 +6,6 @@
|
|||
|
||||
<!-- LOCALIZATION NOTE : Placeholder for the searchbox that allows you to filter the table items. -->
|
||||
<!ENTITY searchBox.placeholder "Filter items">
|
||||
|
||||
<!-- LOCALIZATION NOTE : Label of popup menu action to delete all storage items. -->
|
||||
<!ENTITY storage.popupMenu.deleteAllLabel "Delete All">
|
||||
|
|
|
@ -119,3 +119,7 @@ storage.parsedValue.label=Parsed Value
|
|||
# LOCALIZATION NOTE (storage.popupMenu.deleteLabel):
|
||||
# Label of popup menu action to delete storage item.
|
||||
storage.popupMenu.deleteLabel=Delete “%S”
|
||||
|
||||
# LOCALIZATION NOTE (storage.popupMenu.deleteAllLabel):
|
||||
# Label of popup menu action to delete all storage items.
|
||||
storage.popupMenu.deleteAllFromLabel=Delete All From “%S”
|
||||
|
|
|
@ -803,6 +803,9 @@ TableWidget.prototype = {
|
|||
if (typeof item == "string") {
|
||||
item = this.items.get(item);
|
||||
}
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
let removed = this.items.delete(item[this.uniqueId]);
|
||||
|
||||
if (!removed) {
|
||||
|
|
|
@ -20,6 +20,8 @@ const EventEmitter = require("devtools/shared/event-emitter");
|
|||
* 'js'
|
||||
* - sorted {boolean}: Defaults to true. If true, tree items are kept in
|
||||
* lexical order. If false, items will be kept in insertion order.
|
||||
* - contextMenuId {string}: ID of context menu to be displayed on
|
||||
* tree items.
|
||||
*/
|
||||
function TreeWidget(node, options = {}) {
|
||||
EventEmitter.decorate(this);
|
||||
|
@ -31,6 +33,7 @@ function TreeWidget(node, options = {}) {
|
|||
this.emptyText = options.emptyText || "";
|
||||
this.defaultType = options.defaultType;
|
||||
this.sorted = options.sorted !== false;
|
||||
this.contextMenuId = options.contextMenuId;
|
||||
|
||||
this.setupRoot();
|
||||
|
||||
|
@ -53,30 +56,31 @@ TreeWidget.prototype = {
|
|||
/**
|
||||
* Select any node in the tree.
|
||||
*
|
||||
* @param {array} id
|
||||
* @param {array} ids
|
||||
* An array of ids leading upto the selected item
|
||||
*/
|
||||
set selectedItem(id) {
|
||||
set selectedItem(ids) {
|
||||
if (this._selectedLabel) {
|
||||
this._selectedLabel.classList.remove("theme-selected");
|
||||
}
|
||||
let currentSelected = this._selectedLabel;
|
||||
if (id == -1) {
|
||||
if (ids == -1) {
|
||||
this._selectedLabel = this._selectedItem = null;
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(id)) {
|
||||
if (!Array.isArray(ids)) {
|
||||
return;
|
||||
}
|
||||
this._selectedLabel = this.root.setSelectedItem(id);
|
||||
this._selectedLabel = this.root.setSelectedItem(ids);
|
||||
if (!this._selectedLabel) {
|
||||
this._selectedItem = null;
|
||||
} else {
|
||||
if (currentSelected != this._selectedLabel) {
|
||||
this.ensureSelectedVisible();
|
||||
}
|
||||
this._selectedItem =
|
||||
JSON.parse(this._selectedLabel.parentNode.getAttribute("data-id"));
|
||||
this._selectedItem = ids;
|
||||
this.emit("select", this._selectedItem,
|
||||
this.attachments.get(JSON.stringify(ids)));
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -120,9 +124,16 @@ TreeWidget.prototype = {
|
|||
*/
|
||||
setupRoot: function() {
|
||||
this.root = new TreeItem(this.document);
|
||||
if (this.contextMenuId) {
|
||||
this.root.children.addEventListener("contextmenu", (event) => {
|
||||
let menu = this.document.getElementById(this.contextMenuId);
|
||||
menu.openPopupAtScreen(event.screenX, event.screenY, true);
|
||||
});
|
||||
}
|
||||
|
||||
this._parent.appendChild(this.root.children);
|
||||
|
||||
this.root.children.addEventListener("click", e => this.onClick(e));
|
||||
this.root.children.addEventListener("mousedown", e => this.onClick(e));
|
||||
this.root.children.addEventListener("keypress", e => this.onKeypress(e));
|
||||
},
|
||||
|
||||
|
@ -315,21 +326,17 @@ TreeWidget.prototype = {
|
|||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.hasAttribute("expanded")) {
|
||||
target.removeAttribute("expanded");
|
||||
} else {
|
||||
target.setAttribute("expanded", "true");
|
||||
}
|
||||
if (this._selectedLabel) {
|
||||
this._selectedLabel.classList.remove("theme-selected");
|
||||
}
|
||||
|
||||
if (this._selectedLabel != target) {
|
||||
let ids = target.parentNode.getAttribute("data-id");
|
||||
this._selectedItem = JSON.parse(ids);
|
||||
this.emit("select", this._selectedItem, this.attachments.get(ids));
|
||||
this._selectedLabel = target;
|
||||
this.selectedItem = JSON.parse(ids);
|
||||
}
|
||||
target.classList.add("theme-selected");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -337,7 +344,6 @@ TreeWidget.prototype = {
|
|||
* items, as well as collapsing and expanding any item.
|
||||
*/
|
||||
onKeypress: function(event) {
|
||||
let currentSelected = this._selectedLabel;
|
||||
switch (event.keyCode) {
|
||||
case event.DOM_VK_UP:
|
||||
this.selectPreviousItem();
|
||||
|
@ -367,11 +373,6 @@ TreeWidget.prototype = {
|
|||
default: return;
|
||||
}
|
||||
event.preventDefault();
|
||||
if (this._selectedLabel != currentSelected) {
|
||||
let ids = JSON.stringify(this._selectedItem);
|
||||
this.emit("select", this._selectedItem, this.attachments.get(ids));
|
||||
this.ensureSelectedVisible();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,8 +23,15 @@
|
|||
<commandset id="editMenuCommands"/>
|
||||
|
||||
<popupset id="storagePopupSet">
|
||||
<menupopup id="storage-tree-popup">
|
||||
<menuitem id="storage-tree-popup-delete-all"
|
||||
label="&storage.popupMenu.deleteAllLabel;"/>
|
||||
</menupopup>
|
||||
<menupopup id="storage-table-popup">
|
||||
<menuitem id="storage-table-popup-delete"/>
|
||||
<menuitem id="storage-table-popup-delete-all-from"/>
|
||||
<menuitem id="storage-table-popup-delete-all"
|
||||
label="&storage.popupMenu.deleteAllLabel;"/>
|
||||
</menupopup>
|
||||
</popupset>
|
||||
|
||||
|
|
|
@ -15,12 +15,15 @@ support-files =
|
|||
head.js
|
||||
|
||||
[browser_storage_basic.js]
|
||||
[browser_storage_cookies_delete_all.js]
|
||||
[browser_storage_cookies_edit.js]
|
||||
[browser_storage_cookies_edit_keyboard.js]
|
||||
[browser_storage_cookies_tab_navigation.js]
|
||||
[browser_storage_dynamic_updates.js]
|
||||
[browser_storage_localstorage_edit.js]
|
||||
[browser_storage_delete.js]
|
||||
[browser_storage_delete_all.js]
|
||||
[browser_storage_delete_tree.js]
|
||||
[browser_storage_overflow.js]
|
||||
[browser_storage_search.js]
|
||||
skip-if = os == "linux" && e10s # Bug 1240804 - unhandled promise rejections
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/* 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/. */
|
||||
|
||||
/* import-globals-from head.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test deleting all cookies
|
||||
|
||||
function* performDelete(store, rowName, deleteAll) {
|
||||
let contextMenu = gPanelWindow.document.getElementById(
|
||||
"storage-table-popup");
|
||||
let menuDeleteAllItem = contextMenu.querySelector(
|
||||
"#storage-table-popup-delete-all");
|
||||
let menuDeleteAllFromItem = contextMenu.querySelector(
|
||||
"#storage-table-popup-delete-all-from");
|
||||
|
||||
let storeName = store.join(" > ");
|
||||
|
||||
yield selectTreeItem(store);
|
||||
|
||||
let eventWait = gUI.once("store-objects-updated");
|
||||
|
||||
let cells = getRowCells(rowName);
|
||||
yield waitForContextMenu(contextMenu, cells.name, () => {
|
||||
info(`Opened context menu in ${storeName}, row '${rowName}'`);
|
||||
if (deleteAll) {
|
||||
menuDeleteAllItem.click();
|
||||
} else {
|
||||
menuDeleteAllFromItem.click();
|
||||
let hostName = cells.host.value;
|
||||
ok(menuDeleteAllFromItem.getAttribute("label").includes(hostName),
|
||||
`Context menu item label contains '${hostName}'`);
|
||||
}
|
||||
});
|
||||
|
||||
yield eventWait;
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
|
||||
|
||||
info("test state before delete");
|
||||
yield checkState([
|
||||
[["cookies", "test1.example.org"], ["c1", "c3", "cs2", "uc1"]],
|
||||
[["cookies", "sectest1.example.org"], ["cs2", "sc1", "uc1"]],
|
||||
]);
|
||||
|
||||
info("delete all from domain");
|
||||
// delete only cookies that match the host exactly
|
||||
yield performDelete(["cookies", "test1.example.org"], "c1", false);
|
||||
|
||||
info("test state after delete all from domain");
|
||||
yield checkState([
|
||||
// Domain cookies (.example.org) must not be deleted.
|
||||
[["cookies", "test1.example.org"], ["cs2", "uc1"]],
|
||||
[["cookies", "sectest1.example.org"], ["cs2", "sc1", "uc1"]],
|
||||
]);
|
||||
|
||||
info("delete all");
|
||||
// delete all cookies for host, including domain cookies
|
||||
yield performDelete(["cookies", "sectest1.example.org"], "uc1", true);
|
||||
|
||||
info("test state after delete all");
|
||||
yield checkState([
|
||||
// Domain cookies (.example.org) are deleted too, so deleting in sectest1
|
||||
// also removes stuff from test1.
|
||||
[["cookies", "test1.example.org"], []],
|
||||
[["cookies", "sectest1.example.org"], []],
|
||||
]);
|
||||
|
||||
yield finishTests();
|
||||
});
|
|
@ -28,10 +28,11 @@ add_task(function* () {
|
|||
yield selectTreeItem([store, host]);
|
||||
|
||||
let row = getRowCells(rowName);
|
||||
|
||||
ok(gUI.table.items.has(rowName),
|
||||
`There is a row '${rowName}' in ${store} > ${host}`);
|
||||
|
||||
let eventWait = gUI.once("store-objects-updated");
|
||||
|
||||
yield waitForContextMenu(contextMenu, row[cellToClick], () => {
|
||||
info(`Opened context menu in ${store} > ${host}, row '${rowName}'`);
|
||||
menuDeleteItem.click();
|
||||
|
@ -39,7 +40,7 @@ add_task(function* () {
|
|||
`Context menu item label contains '${rowName}'`);
|
||||
});
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield eventWait;
|
||||
|
||||
ok(!gUI.table.items.has(rowName),
|
||||
`There is no row '${rowName}' in ${store} > ${host} after deletion`);
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* 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/. */
|
||||
|
||||
/* import-globals-from head.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test deleting all storage items
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
|
||||
|
||||
let contextMenu = gPanelWindow.document.getElementById("storage-table-popup");
|
||||
let menuDeleteAllItem = contextMenu.querySelector(
|
||||
"#storage-table-popup-delete-all");
|
||||
|
||||
info("test state before delete");
|
||||
const beforeState = [
|
||||
[["localStorage", "http://test1.example.org"],
|
||||
["ls1", "ls2"]],
|
||||
[["localStorage", "http://sectest1.example.org"],
|
||||
["iframe-u-ls1"]],
|
||||
[["localStorage", "https://sectest1.example.org"],
|
||||
["iframe-s-ls1"]],
|
||||
[["sessionStorage", "http://test1.example.org"],
|
||||
["ss1"]],
|
||||
[["sessionStorage", "http://sectest1.example.org"],
|
||||
["iframe-u-ss1", "iframe-u-ss2"]],
|
||||
[["sessionStorage", "https://sectest1.example.org"],
|
||||
["iframe-s-ss1"]],
|
||||
];
|
||||
|
||||
yield checkState(beforeState);
|
||||
|
||||
info("do the delete");
|
||||
const deleteHosts = [
|
||||
[["localStorage", "https://sectest1.example.org"], "iframe-s-ls1"],
|
||||
[["sessionStorage", "https://sectest1.example.org"], "iframe-s-ss1"],
|
||||
];
|
||||
|
||||
for (let [store, rowName] of deleteHosts) {
|
||||
let storeName = store.join(" > ");
|
||||
|
||||
yield selectTreeItem(store);
|
||||
|
||||
let eventWait = gUI.once("store-objects-cleared");
|
||||
|
||||
let cell = getRowCells(rowName).name;
|
||||
yield waitForContextMenu(contextMenu, cell, () => {
|
||||
info(`Opened context menu in ${storeName}, row '${rowName}'`);
|
||||
menuDeleteAllItem.click();
|
||||
});
|
||||
|
||||
yield eventWait;
|
||||
}
|
||||
|
||||
info("test state after delete");
|
||||
const afterState = [
|
||||
// iframes from the same host, one secure, one unsecure, are independent
|
||||
// from each other. Delete all in one doesn't touch the other one.
|
||||
[["localStorage", "http://test1.example.org"],
|
||||
["ls1", "ls2"]],
|
||||
[["localStorage", "http://sectest1.example.org"],
|
||||
["iframe-u-ls1"]],
|
||||
[["localStorage", "https://sectest1.example.org"],
|
||||
[]],
|
||||
[["sessionStorage", "http://test1.example.org"],
|
||||
["ss1"]],
|
||||
[["sessionStorage", "http://sectest1.example.org"],
|
||||
["iframe-u-ss1", "iframe-u-ss2"]],
|
||||
[["sessionStorage", "https://sectest1.example.org"],
|
||||
[]],
|
||||
];
|
||||
|
||||
yield checkState(afterState);
|
||||
|
||||
yield finishTests();
|
||||
});
|
|
@ -0,0 +1,60 @@
|
|||
/* 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/. */
|
||||
|
||||
/* import-globals-from head.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test deleting all storage items from the tree.
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
|
||||
|
||||
let contextMenu = gPanelWindow.document.getElementById("storage-tree-popup");
|
||||
let menuDeleteAllItem = contextMenu.querySelector(
|
||||
"#storage-tree-popup-delete-all");
|
||||
|
||||
info("test state before delete");
|
||||
yield checkState([
|
||||
[["cookies", "test1.example.org"], ["c1", "c3", "cs2", "uc1"]],
|
||||
[["localStorage", "http://test1.example.org"], ["ls1", "ls2"]],
|
||||
[["sessionStorage", "http://test1.example.org"], ["ss1"]],
|
||||
]);
|
||||
|
||||
info("do the delete");
|
||||
const deleteHosts = [
|
||||
["cookies", "test1.example.org"],
|
||||
["localStorage", "http://test1.example.org"],
|
||||
["sessionStorage", "http://test1.example.org"],
|
||||
];
|
||||
|
||||
for (let store of deleteHosts) {
|
||||
let storeName = store.join(" > ");
|
||||
|
||||
yield selectTreeItem(store);
|
||||
|
||||
let eventName = "store-objects-" +
|
||||
(store[0] == "cookies" ? "updated" : "cleared");
|
||||
let eventWait = gUI.once(eventName);
|
||||
|
||||
let selector = `[data-id='${JSON.stringify(store)}'] > .tree-widget-item`;
|
||||
let target = gPanelWindow.document.querySelector(selector);
|
||||
ok(target, `tree item found in ${storeName}`);
|
||||
yield waitForContextMenu(contextMenu, target, () => {
|
||||
info(`Opened tree context menu in ${storeName}`);
|
||||
menuDeleteAllItem.click();
|
||||
});
|
||||
|
||||
yield eventWait;
|
||||
}
|
||||
|
||||
info("test state after delete");
|
||||
yield checkState([
|
||||
[["cookies", "test1.example.org"], []],
|
||||
[["localStorage", "http://test1.example.org"], []],
|
||||
[["sessionStorage", "http://test1.example.org"], []],
|
||||
]);
|
||||
|
||||
yield finishTests();
|
||||
});
|
|
@ -509,17 +509,13 @@ function matchVariablesViewProperty(prop, rule) {
|
|||
* The array id of the item in the tree
|
||||
*/
|
||||
function* selectTreeItem(ids) {
|
||||
// Expand tree as some/all items could be collapsed leading to click on an
|
||||
// incorrect tree item
|
||||
gUI.tree.expandAll();
|
||||
|
||||
let selector = "[data-id='" + JSON.stringify(ids) + "'] > .tree-widget-item";
|
||||
let target = gPanelWindow.document.querySelector(selector);
|
||||
ok(target, "tree item found with ids " + JSON.stringify(ids));
|
||||
/* If this item is already selected, return */
|
||||
if (gUI.tree.isSelected(ids)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let updated = gUI.once("store-objects-updated");
|
||||
|
||||
yield click(target);
|
||||
gUI.tree.selectedItem = ids;
|
||||
yield updated;
|
||||
}
|
||||
|
||||
|
@ -845,8 +841,35 @@ function waitForContextMenu(popup, button, onShown, onHidden) {
|
|||
popup.addEventListener("popupshown", onPopupShown);
|
||||
|
||||
info("wait for the context menu to open");
|
||||
button.scrollIntoView();
|
||||
let eventDetails = {type: "contextmenu", button: 2};
|
||||
EventUtils.synthesizeMouse(button, 2, 2, eventDetails,
|
||||
button.ownerDocument.defaultView);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the storage inspector state: check that given type/host exists
|
||||
* in the tree, and that the table contains rows with specified names.
|
||||
*
|
||||
* @param {Array} state Array of state specifications. For example,
|
||||
* [["cookies", "example.com"], ["c1", "c2"]] means to select the
|
||||
* "example.com" host in cookies and then verify there are "c1" and "c2"
|
||||
* cookies (and no other ones).
|
||||
*/
|
||||
function* checkState(state) {
|
||||
for (let [store, names] of state) {
|
||||
let storeName = store.join(" > ");
|
||||
info(`Selecting tree item ${storeName}`);
|
||||
yield selectTreeItem(store);
|
||||
|
||||
let items = gUI.table.items;
|
||||
|
||||
is(items.size, names.length,
|
||||
`There is correct number of rows in ${storeName}`);
|
||||
for (let name of names) {
|
||||
ok(items.has(name),
|
||||
`There is item with name '${name}' in ${storeName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,10 @@ var StorageUI = this.StorageUI = function StorageUI(front, target, panelWin) {
|
|||
this.front = front;
|
||||
|
||||
let treeNode = this._panelDoc.getElementById("storage-tree");
|
||||
this.tree = new TreeWidget(treeNode, {defaultType: "dir"});
|
||||
this.tree = new TreeWidget(treeNode, {
|
||||
defaultType: "dir",
|
||||
contextMenuId: "storage-tree-popup"
|
||||
});
|
||||
this.onHostSelect = this.onHostSelect.bind(this);
|
||||
this.tree.on("select", this.onHostSelect);
|
||||
|
||||
|
@ -111,14 +114,34 @@ var StorageUI = this.StorageUI = function StorageUI(front, target, panelWin) {
|
|||
this.handleKeypress = this.handleKeypress.bind(this);
|
||||
this._panelDoc.addEventListener("keypress", this.handleKeypress);
|
||||
|
||||
this.onPopupShowing = this.onPopupShowing.bind(this);
|
||||
this.onTreePopupShowing = this.onTreePopupShowing.bind(this);
|
||||
this._treePopup = this._panelDoc.getElementById("storage-tree-popup");
|
||||
this._treePopup.addEventListener("popupshowing", this.onTreePopupShowing);
|
||||
|
||||
this.onTablePopupShowing = this.onTablePopupShowing.bind(this);
|
||||
this._tablePopup = this._panelDoc.getElementById("storage-table-popup");
|
||||
this._tablePopup.addEventListener("popupshowing", this.onPopupShowing, false);
|
||||
this._tablePopup.addEventListener("popupshowing", this.onTablePopupShowing);
|
||||
|
||||
this.onRemoveItem = this.onRemoveItem.bind(this);
|
||||
this.onRemoveAllFrom = this.onRemoveAllFrom.bind(this);
|
||||
this.onRemoveAll = this.onRemoveAll.bind(this);
|
||||
|
||||
this._tablePopupDelete = this._panelDoc.getElementById(
|
||||
"storage-table-popup-delete");
|
||||
this._tablePopupDelete.addEventListener("command", this.onRemoveItem, false);
|
||||
this._tablePopupDelete.addEventListener("command", this.onRemoveItem);
|
||||
|
||||
this._tablePopupDeleteAllFrom = this._panelDoc.getElementById(
|
||||
"storage-table-popup-delete-all-from");
|
||||
this._tablePopupDeleteAllFrom.addEventListener("command",
|
||||
this.onRemoveAllFrom);
|
||||
|
||||
this._tablePopupDeleteAll = this._panelDoc.getElementById(
|
||||
"storage-table-popup-delete-all");
|
||||
this._tablePopupDeleteAll.addEventListener("command", this.onRemoveAll);
|
||||
|
||||
this._treePopupDeleteAll = this._panelDoc.getElementById(
|
||||
"storage-tree-popup-delete-all");
|
||||
this._treePopupDeleteAll.addEventListener("command", this.onRemoveAll);
|
||||
};
|
||||
|
||||
exports.StorageUI = StorageUI;
|
||||
|
@ -126,7 +149,6 @@ exports.StorageUI = StorageUI;
|
|||
StorageUI.prototype = {
|
||||
|
||||
storageTypes: null,
|
||||
shouldResetColumns: true,
|
||||
shouldLoadMoreItems: true,
|
||||
|
||||
set animationsEnabled(value) {
|
||||
|
@ -145,8 +167,16 @@ StorageUI.prototype = {
|
|||
this.searchBox.removeEventListener("input", this.filterItems);
|
||||
this.searchBox = null;
|
||||
|
||||
this._tablePopup.removeEventListener("popupshowing", this.onPopupShowing);
|
||||
this._treePopup.removeEventListener("popupshowing",
|
||||
this.onTreePopupShowing);
|
||||
this._treePopupDeleteAll.removeEventListener("command", this.onRemoveAll);
|
||||
|
||||
this._tablePopup.removeEventListener("popupshowing",
|
||||
this.onTablePopupShowing);
|
||||
this._tablePopupDelete.removeEventListener("command", this.onRemoveItem);
|
||||
this._tablePopupDeleteAllFrom.removeEventListener("command",
|
||||
this.onRemoveAllFrom);
|
||||
this._tablePopupDeleteAll.removeEventListener("command", this.onRemoveAll);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -391,10 +421,10 @@ StorageUI.prototype = {
|
|||
this.emit("store-objects-updated");
|
||||
return;
|
||||
}
|
||||
if (this.shouldResetColumns) {
|
||||
if (reason === REASON.POPULATE) {
|
||||
this.resetColumns(data[0], type);
|
||||
}
|
||||
this.table.host = host;
|
||||
}
|
||||
this.populateTable(data, reason);
|
||||
this.emit("store-objects-updated");
|
||||
|
||||
|
@ -437,7 +467,6 @@ StorageUI.prototype = {
|
|||
this.tree.add([type, host, ...names]);
|
||||
if (!this.tree.selectedItem) {
|
||||
this.tree.selectedItem = [type, host, names[0], names[1]];
|
||||
this.fetchStorageObjects(type, host, [name], REASON.POPULATE);
|
||||
}
|
||||
} catch (ex) {
|
||||
// Do Nothing
|
||||
|
@ -445,7 +474,6 @@ StorageUI.prototype = {
|
|||
}
|
||||
if (!this.tree.selectedItem) {
|
||||
this.tree.selectedItem = [type, host];
|
||||
this.fetchStorageObjects(type, host, null, REASON.POPULATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -625,7 +653,6 @@ StorageUI.prototype = {
|
|||
if (item.length > 2) {
|
||||
names = [JSON.stringify(item.slice(2))];
|
||||
}
|
||||
this.shouldResetColumns = true;
|
||||
this.fetchStorageObjects(type, host, names, REASON.POPULATE);
|
||||
this.itemOffset = 0;
|
||||
},
|
||||
|
@ -657,7 +684,6 @@ StorageUI.prototype = {
|
|||
}
|
||||
this.table.setColumns(columns, null, HIDDEN_COLUMNS);
|
||||
this.table.datatype = type;
|
||||
this.shouldResetColumns = false;
|
||||
this.hideSidebar();
|
||||
},
|
||||
|
||||
|
@ -757,23 +783,54 @@ StorageUI.prototype = {
|
|||
* If the current storage actor doesn't support removing items, prevent
|
||||
* showing the menu.
|
||||
*/
|
||||
onPopupShowing: function(event) {
|
||||
onTablePopupShowing: function(event) {
|
||||
if (!this.getCurrentActor().removeItem) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
const maxLen = ITEM_NAME_MAX_LENGTH;
|
||||
let [type] = this.tree.selectedItem;
|
||||
let rowId = this.table.contextMenuRowId;
|
||||
let data = this.table.items.get(rowId);
|
||||
let name = data[this.table.uniqueId];
|
||||
|
||||
const maxLen = ITEM_NAME_MAX_LENGTH;
|
||||
if (name.length > maxLen) {
|
||||
name = name.substr(0, maxLen) + L10N.ellipsis;
|
||||
}
|
||||
|
||||
this._tablePopupDelete.setAttribute("label",
|
||||
L10N.getFormatStr("storage.popupMenu.deleteLabel", name));
|
||||
|
||||
if (type === "cookies") {
|
||||
let host = data.host;
|
||||
if (host.length > maxLen) {
|
||||
host = host.substr(0, maxLen) + L10N.ellipsis;
|
||||
}
|
||||
|
||||
this._tablePopupDeleteAllFrom.hidden = false;
|
||||
this._tablePopupDeleteAllFrom.setAttribute("label",
|
||||
L10N.getFormatStr("storage.popupMenu.deleteAllFromLabel", host));
|
||||
} else {
|
||||
this._tablePopupDeleteAllFrom.hidden = true;
|
||||
}
|
||||
},
|
||||
|
||||
onTreePopupShowing: function(event) {
|
||||
let showMenu = false;
|
||||
let selectedItem = this.tree.selectedItem;
|
||||
// Never show menu on the 1st level item
|
||||
if (selectedItem && selectedItem.length > 1) {
|
||||
// this.currentActor() would return wrong value here
|
||||
let actor = this.storageTypes[selectedItem[0]];
|
||||
if (actor.removeAll) {
|
||||
showMenu = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!showMenu) {
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -787,4 +844,30 @@ StorageUI.prototype = {
|
|||
|
||||
actor.removeItem(host, data[this.table.uniqueId]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles removing all items from the storage
|
||||
*/
|
||||
onRemoveAll: function() {
|
||||
// Cannot use this.currentActor() if the handler is called from the
|
||||
// tree context menu: it returns correct value only after the table
|
||||
// data from server are successfully fetched (and that's async).
|
||||
let [type, host] = this.tree.selectedItem;
|
||||
let actor = this.storageTypes[type];
|
||||
|
||||
actor.removeAll(host);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles removing all cookies with exactly the same domain as the
|
||||
* cookie in the selected row.
|
||||
*/
|
||||
onRemoveAllFrom: function() {
|
||||
let [, host] = this.tree.selectedItem;
|
||||
let actor = this.getCurrentActor();
|
||||
let rowId = this.table.contextMenuRowId;
|
||||
let data = this.table.items.get(rowId);
|
||||
|
||||
actor.removeAll(host, data.host);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -686,8 +686,18 @@ StorageActors.createActor({
|
|||
this.removeCookie(host, name);
|
||||
}), {
|
||||
request: {
|
||||
host: Arg(0),
|
||||
name: Arg(1),
|
||||
host: Arg(0, "string"),
|
||||
name: Arg(1, "string"),
|
||||
},
|
||||
response: {}
|
||||
}),
|
||||
|
||||
removeAll: method(Task.async(function*(host, domain) {
|
||||
this.removeAllCookies(host, domain);
|
||||
}), {
|
||||
request: {
|
||||
host: Arg(0, "string"),
|
||||
domain: Arg(1, "nullable:string")
|
||||
},
|
||||
response: {}
|
||||
}),
|
||||
|
@ -696,11 +706,18 @@ StorageActors.createActor({
|
|||
cookieHelpers.onCookieChanged = this.onCookieChanged.bind(this);
|
||||
|
||||
if (!DebuggerServer.isInChildProcess) {
|
||||
this.getCookiesFromHost = cookieHelpers.getCookiesFromHost;
|
||||
this.addCookieObservers = cookieHelpers.addCookieObservers;
|
||||
this.removeCookieObservers = cookieHelpers.removeCookieObservers;
|
||||
this.editCookie = cookieHelpers.editCookie;
|
||||
this.removeCookie = cookieHelpers.removeCookie;
|
||||
this.getCookiesFromHost =
|
||||
cookieHelpers.getCookiesFromHost.bind(cookieHelpers);
|
||||
this.addCookieObservers =
|
||||
cookieHelpers.addCookieObservers.bind(cookieHelpers);
|
||||
this.removeCookieObservers =
|
||||
cookieHelpers.removeCookieObservers.bind(cookieHelpers);
|
||||
this.editCookie =
|
||||
cookieHelpers.editCookie.bind(cookieHelpers);
|
||||
this.removeCookie =
|
||||
cookieHelpers.removeCookie.bind(cookieHelpers);
|
||||
this.removeAllCookies =
|
||||
cookieHelpers.removeAllCookies.bind(cookieHelpers);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -722,6 +739,8 @@ StorageActors.createActor({
|
|||
callParentProcess.bind(null, "editCookie");
|
||||
this.removeCookie =
|
||||
callParentProcess.bind(null, "removeCookie");
|
||||
this.removeAllCookies =
|
||||
callParentProcess.bind(null, "removeAllCookies");
|
||||
|
||||
addMessageListener("storage:storage-cookie-request-child",
|
||||
cookieHelpers.handleParentRequest);
|
||||
|
@ -875,7 +894,7 @@ var cookieHelpers = {
|
|||
);
|
||||
},
|
||||
|
||||
removeCookie: function(host, name) {
|
||||
_removeCookies: function(host, opts = {}) {
|
||||
function hostMatches(cookieHost, matchHost) {
|
||||
if (cookieHost == null) {
|
||||
return matchHost == null;
|
||||
|
@ -889,7 +908,9 @@ var cookieHelpers = {
|
|||
let enumerator = Services.cookies.getCookiesFromHost(host);
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
|
||||
if (hostMatches(cookie.host, host) && cookie.name === name) {
|
||||
if (hostMatches(cookie.host, host) &&
|
||||
(!opts.name || cookie.name === opts.name) &&
|
||||
(!opts.domain || cookie.host === opts.domain)) {
|
||||
Services.cookies.remove(
|
||||
cookie.host,
|
||||
cookie.name,
|
||||
|
@ -901,6 +922,16 @@ var cookieHelpers = {
|
|||
}
|
||||
},
|
||||
|
||||
removeCookie: function(host, name) {
|
||||
if (name !== undefined) {
|
||||
this._removeCookies(host, { name });
|
||||
}
|
||||
},
|
||||
|
||||
removeAllCookies: function(host, domain) {
|
||||
this._removeCookies(host, { domain });
|
||||
},
|
||||
|
||||
addCookieObservers: function() {
|
||||
Services.obs.addObserver(cookieHelpers, "cookie-changed", false);
|
||||
return null;
|
||||
|
@ -969,6 +1000,11 @@ var cookieHelpers = {
|
|||
let name = msg.data.args[1];
|
||||
return cookieHelpers.removeCookie(host, name);
|
||||
}
|
||||
case "removeAllCookies": {
|
||||
let host = msg.data.args[0];
|
||||
let domain = msg.data.args[1];
|
||||
return cookieHelpers.removeAllCookies(host, domain);
|
||||
}
|
||||
default:
|
||||
console.error("ERR_DIRECTOR_PARENT_UNKNOWN_METHOD", msg.json.method);
|
||||
throw new Error("ERR_DIRECTOR_PARENT_UNKNOWN_METHOD");
|
||||
|
@ -1180,6 +1216,16 @@ function getObjectForLocalOrSessionStorage(type) {
|
|||
},
|
||||
response: {}
|
||||
}),
|
||||
|
||||
removeAll: method(Task.async(function*(host) {
|
||||
let storage = this.hostVsStores.get(host);
|
||||
storage.clear();
|
||||
}), {
|
||||
request: {
|
||||
host: Arg(0)
|
||||
},
|
||||
response: {}
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2078,7 +2124,7 @@ var StorageActor = exports.StorageActor = protocol.ActorClass({
|
|||
data: Arg(0, "json")
|
||||
},
|
||||
"stores-reloaded": {
|
||||
type: "storesRelaoded",
|
||||
type: "storesReloaded",
|
||||
data: Arg(0, "json")
|
||||
}
|
||||
},
|
||||
|
@ -2310,11 +2356,13 @@ var StorageActor = exports.StorageActor = protocol.ActorClass({
|
|||
this.boundUpdate[action][storeType] = {};
|
||||
}
|
||||
for (let host in data) {
|
||||
if (!this.boundUpdate[action][storeType][host] || action == "deleted") {
|
||||
this.boundUpdate[action][storeType][host] = data[host];
|
||||
} else {
|
||||
this.boundUpdate[action][storeType][host] =
|
||||
this.boundUpdate[action][storeType][host].concat(data[host]);
|
||||
if (!this.boundUpdate[action][storeType][host]) {
|
||||
this.boundUpdate[action][storeType][host] = [];
|
||||
}
|
||||
for (let name of data[host]) {
|
||||
if (!this.boundUpdate[action][storeType][host].includes(name)) {
|
||||
this.boundUpdate[action][storeType][host].push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (action == "added") {
|
||||
|
|
Загрузка…
Ссылка в новой задаче