moebius#339: Make it possible to add cookies, local and session storage entries

Issue #31
https://github.com/MoonchildProductions/moebius/pull/339
This commit is contained in:
janekptacijarabaci 2018-03-02 17:52:34 +01:00 committed by Roy Tam
commit 6d865bfda3
13 changed files with 309 additions and 43 deletions

View file

@ -160,12 +160,20 @@ function StorageUI(front, target, panelWin, toolbox) {
this._tablePopup = this._panelDoc.getElementById("storage-table-popup");
this._tablePopup.addEventListener("popupshowing", this.onTablePopupShowing);
this.onAddItem = this.onAddItem.bind(this);
this.onRemoveItem = this.onRemoveItem.bind(this);
this.onRemoveAllFrom = this.onRemoveAllFrom.bind(this);
this.onRemoveAll = this.onRemoveAll.bind(this);
this.onRemoveAllSessionCookies = this.onRemoveAllSessionCookies.bind(this);
this.onRemoveTreeItem = this.onRemoveTreeItem.bind(this);
this._addButton = this._panelDoc.getElementById("add-button");
this._addButton.addEventListener("command", this.onAddItem);
this._tablePopupAddItem = this._panelDoc.getElementById(
"storage-table-popup-add");
this._tablePopupAddItem.addEventListener("command", this.onAddItem);
this._tablePopupDelete = this._panelDoc.getElementById(
"storage-table-popup-delete");
this._tablePopupDelete.addEventListener("command", this.onRemoveItem);
@ -221,6 +229,8 @@ StorageUI.prototype = {
this.searchBox = null;
this._treePopup.removeEventListener("popupshowing", this.onTreePopupShowing);
this._addButton.removeEventListener("command", this.onAddItem);
this._tablePopupAddItem.removeEventListener("command", this.onAddItem);
this._treePopupDeleteAll.removeEventListener("command", this.onRemoveAll);
this._treePopupDeleteAllSessionCookies.removeEventListener("command",
this.onRemoveAllSessionCookies);
@ -243,7 +253,7 @@ StorageUI.prototype = {
this.table.clearSelection();
},
getCurrentActor: function () {
getCurrentFront: function () {
let type = this.table.datatype;
return this.storageTypes[type];
@ -264,9 +274,9 @@ StorageUI.prototype = {
},
editItem: function (eventType, data) {
let actor = this.getCurrentActor();
let front = this.getCurrentFront();
actor.editItem(data);
front.editItem(data);
},
/**
@ -520,7 +530,7 @@ StorageUI.prototype = {
// The indexedDB type could have sub-type data to fetch.
// If having names specified, then it means
// we are fetching details of specific database or of object store.
if (type == "indexedDB" && names) {
if (type === "indexedDB" && names) {
let [ dbName, objectStoreName ] = JSON.parse(names[0]);
if (dbName) {
subType = "database";
@ -529,6 +539,15 @@ StorageUI.prototype = {
subType = "object store";
}
}
this.actorSupportsAddItem = yield this._target.actorHasMethod(type, "addItem");
this.actorSupportsRemoveItem =
yield this._target.actorHasMethod(type, "removeItem");
this.actorSupportsRemoveAll =
yield this._target.actorHasMethod(type, "removeAll");
this.actorSupportsRemoveAllSessionCookies =
yield this._target.actorHasMethod(type, "removeAllSessionCookies");
yield this.resetColumns(type, host, subType);
}
@ -536,12 +555,34 @@ StorageUI.prototype = {
if (data.length) {
this.populateTable(data, reason);
}
yield this.updateToolbar();
this.emit("store-objects-updated");
} catch (ex) {
console.error(ex);
}
}),
/**
* Updates the toolbar hiding and showing buttons as appropriate.
*/
updateToolbar: Task.async(function* () {
let item = this.tree.selectedItem;
let howManyNodesIn = item ? item.length : 0;
// The first node is just a title e.g. "Cookies" so we need to be at least
// 2 nodes in to show the add button.
let canAdd = this.actorSupportsAddItem && howManyNodesIn > 1;
if (canAdd) {
this._addButton.hidden = false;
this._addButton.setAttribute("tooltiptext",
L10N.getFormatStr("storage.popupMenu.addItemLabel"));
} else {
this._addButton.hidden = true;
this._addButton.removeAttribute("tooltiptext");
}
}),
/**
* Populates the storage tree which displays the list of storages present for
* the page.
@ -777,11 +818,19 @@ StorageUI.prototype = {
* the storage tree
*/
onHostSelect: function (event, item) {
if (!item) {
return;
}
this.table.clear();
this.hideSidebar();
this.searchBox.value = "";
let [type, host] = item;
this.table.host = host;
this.table.datatype = type;
this.updateToolbar();
let names = null;
if (!host) {
return;
@ -814,7 +863,7 @@ StorageUI.prototype = {
let editableFields = [];
let hiddenFields = [];
let privateFields = [];
let fields = yield this.getCurrentActor().getFields(subtype);
let fields = yield this.getCurrentFront().getFields(subtype);
fields.forEach(f => {
if (!uniqueKey) {
@ -949,33 +998,47 @@ StorageUI.prototype = {
},
/**
* Fires before a cell context menu with the "Delete" action is shown.
* If the currently selected storage object doesn't support removing items, prevent
* showing the menu.
* Fires before a cell context menu with the "Add" or "Delete" action is
* shown. If the currently selected storage object doesn't support adding or
* removing items, prevent showing the menu.
*/
onTablePopupShowing: function (event) {
let selectedItem = this.tree.selectedItem;
let type = selectedItem[0];
let actor = this.getCurrentActor();
// IndexedDB only supports removing items from object stores (level 4 of the tree)
if (!actor.removeItem || (type === "indexedDB" && selectedItem.length !== 4)) {
if ((!this.actorSupportsAddItem && !this.actorSupportsRemoveItem &&
type !== "cookies") ||
(type === "indexedDB" && selectedItem.length !== 4)) {
event.preventDefault();
return;
}
let rowId = this.table.contextMenuRowId;
let data = this.table.items.get(rowId);
let name = data[this.table.uniqueId];
let separatorRegex = new RegExp(SEPARATOR_GUID, "g");
let label = addEllipsis((name + "").replace(separatorRegex, "-"));
if (this.actorSupportsRemoveItem) {
let name = data[this.table.uniqueId];
let separatorRegex = new RegExp(SEPARATOR_GUID, "g");
let label = addEllipsis((name + "").replace(separatorRegex, "-"));
this._tablePopupDelete.setAttribute("label",
L10N.getFormatStr("storage.popupMenu.deleteLabel", label));
this._tablePopupDelete.hidden = false;
this._tablePopupDelete.setAttribute("label",
L10N.getFormatStr("storage.popupMenu.deleteLabel", label));
} else {
this._tablePopupDelete.hidden = true;
}
if (this.actorSupportsAddItem) {
this._tablePopupAddItem.hidden = false;
this._tablePopupAddItem.setAttribute("label",
L10N.getFormatStr("storage.popupMenu.addItemLabel"));
} else {
this._tablePopupAddItem.hidden = true;
}
let showDeleteAllSessionCookies = false;
if (selectedItem && actor.removeAllSessionCookies) {
if (this.actorSupportsRemoveAllSessionCookies) {
if (type === "cookies" && selectedItem.length === 2) {
showDeleteAllSessionCookies = true;
}
@ -1000,13 +1063,12 @@ StorageUI.prototype = {
if (selectedItem) {
let type = selectedItem[0];
let actor = this.storageTypes[type];
// The delete all (aka clear) action is displayed for IndexedDB object stores
// (level 4 of tree), for Cache objects (level 3) and for the whole host (level 2)
// for other storage types (cookies, localStorage, ...).
let showDeleteAll = false;
if (actor.removeAll) {
if (this.actorSupportsRemoveAll) {
let level;
if (type == "indexedDB") {
level = 4;
@ -1026,7 +1088,7 @@ StorageUI.prototype = {
// The delete all session cookies action is displayed for cookie object stores
// (level 2 of tree)
let showDeleteAllSessionCookies = false;
if (actor.removeAllSessionCookies) {
if (this.actorSupportsRemoveAllSessionCookies) {
if (type === "cookies" && selectedItem.length === 2) {
showDeleteAllSessionCookies = true;
}
@ -1054,45 +1116,55 @@ StorageUI.prototype = {
}
},
/**
* Handles adding an item from the storage
*/
onAddItem: function () {
if (!this.tree.selectedItem) {
return;
}
let front = this.getCurrentFront();
let [, host] = this.tree.selectedItem;
// Prepare to scroll into view.
this.table.scrollIntoViewOnUpdate = true;
this.table.editBookmark = createGUID();
front.addItem(this.table.editBookmark, host);
},
/**
* Handles removing an item from the storage
*/
onRemoveItem: function () {
let [, host, ...path] = this.tree.selectedItem;
let actor = this.getCurrentActor();
let front = this.getCurrentFront();
let rowId = this.table.contextMenuRowId;
let data = this.table.items.get(rowId);
let name = data[this.table.uniqueId];
if (path.length > 0) {
name = JSON.stringify([...path, name]);
}
actor.removeItem(host, name);
front.removeItem(host, name);
},
/**
* 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 the correct value only after the
// table data from server are successfully fetched (and that's async).
let [type, host, ...path] = this.tree.selectedItem;
let actor = this.storageTypes[type];
let [, host, ...path] = this.tree.selectedItem;
let front = this.getCurrentFront();
let name = path.length > 0 ? JSON.stringify(path) : undefined;
actor.removeAll(host, name);
front.removeAll(host, name);
},
/**
* Handles removing all session cookies from the storage
*/
onRemoveAllSessionCookies: function () {
// Cannot use this.currentActor() if the handler is called from the
// tree context menu: it returns the correct value only after the
// table data from server is successfully fetched (and that's async).
let [, host, ...path] = this.tree.selectedItem;
let actor = this.getCurrentActor();
let front = this.getCurrentFront();
let name = path.length > 0 ? JSON.stringify(path) : undefined;
actor.removeAllSessionCookies(host, name);
front.removeAllSessionCookies(host, name);
},
/**
@ -1101,11 +1173,11 @@ StorageUI.prototype = {
*/
onRemoveAllFrom: function () {
let [, host] = this.tree.selectedItem;
let actor = this.getCurrentActor();
let front = this.getCurrentFront();
let rowId = this.table.contextMenuRowId;
let data = this.table.items.get(rowId);
actor.removeAll(host, data.host);
front.removeAll(host, data.host);
},
onRemoveTreeItem: function () {
@ -1119,9 +1191,9 @@ StorageUI.prototype = {
},
removeDatabase: function (host, dbName) {
let actor = this.storageTypes.indexedDB;
let front = this.getCurrentFront();
actor.removeDatabase(host, dbName).then(result => {
front.removeDatabase(host, dbName).then(result => {
if (result.blocked) {
let notificationBox = this._toolbox.getNotificationBox();
notificationBox.appendNotification(
@ -1141,8 +1213,17 @@ StorageUI.prototype = {
},
removeCache: function (host, cacheName) {
let actor = this.storageTypes.Cache;
let front = this.getCurrentFront();
actor.removeItem(host, JSON.stringify([ cacheName ]));
front.removeItem(host, JSON.stringify([ cacheName ]));
},
};
// Helper Functions
function createGUID() {
return "{cccccccc-cccc-4ccc-yccc-cccccccccccc}".replace(/[cy]/g, c => {
let r = Math.random() * 16 | 0, v = c == "c" ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}