summaryrefslogtreecommitdiffstats
path: root/devtools/client/storage/ui.js
diff options
context:
space:
mode:
authorjanekptacijarabaci <janekptacijarabaci@seznam.cz>2018-03-02 17:52:34 +0100
committerjanekptacijarabaci <janekptacijarabaci@seznam.cz>2018-03-02 17:52:34 +0100
commit166fb9f2893dcfb3375aa3227d116fb0ce2c6d42 (patch)
tree9bfd8bb159a20f00ff507ab9c27c22434155df23 /devtools/client/storage/ui.js
parent26e53627d6922b3b965afd76fc5d72e3cc1d9ba5 (diff)
downloadUXP-166fb9f2893dcfb3375aa3227d116fb0ce2c6d42.tar
UXP-166fb9f2893dcfb3375aa3227d116fb0ce2c6d42.tar.gz
UXP-166fb9f2893dcfb3375aa3227d116fb0ce2c6d42.tar.lz
UXP-166fb9f2893dcfb3375aa3227d116fb0ce2c6d42.tar.xz
UXP-166fb9f2893dcfb3375aa3227d116fb0ce2c6d42.zip
moebius#339: Make it possible to add cookies, local and session storage entries
Issue #31 https://github.com/MoonchildProductions/moebius/pull/339
Diffstat (limited to 'devtools/client/storage/ui.js')
-rw-r--r--devtools/client/storage/ui.js157
1 files changed, 119 insertions, 38 deletions
diff --git a/devtools/client/storage/ui.js b/devtools/client/storage/ui.js
index af0bfa375..27ad307b0 100644
--- a/devtools/client/storage/ui.js
+++ b/devtools/client/storage/ui.js
@@ -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,6 +555,7 @@ StorageUI.prototype = {
if (data.length) {
this.populateTable(data, reason);
}
+ yield this.updateToolbar();
this.emit("store-objects-updated");
} catch (ex) {
console.error(ex);
@@ -543,6 +563,27 @@ StorageUI.prototype = {
}),
/**
+ * 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;
}
@@ -1055,44 +1117,54 @@ 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);
+ });
+}