Bug 340432 - Add the ability to cancel site permission changes

This commit is contained in:
janekptacijarabaci 2018-04-26 07:06:14 +02:00 • committed by Roy Tam
commit 6462ac2979
4 changed files with 161 additions and 98 deletions

View file

@ -28,7 +28,7 @@ browser.jar:
content/browser/preferences/languages.js content/browser/preferences/languages.js
* content/browser/preferences/main.xul * content/browser/preferences/main.xul
content/browser/preferences/main.js content/browser/preferences/main.js
* content/browser/preferences/permissions.xul content/browser/preferences/permissions.xul
* content/browser/preferences/permissions.js * content/browser/preferences/permissions.js
* content/browser/preferences/preferences.xul * content/browser/preferences/preferences.xul
content/browser/preferences/privacy.xul content/browser/preferences/privacy.xul

View file

@ -3,12 +3,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://gre/modules/Services.jsm");
const nsIPermissionManager = Components.interfaces.nsIPermissionManager; const nsIPermissionManager = Components.interfaces.nsIPermissionManager;
const nsICookiePermission = Components.interfaces.nsICookiePermission; const nsICookiePermission = Components.interfaces.nsICookiePermission;
const NOTIFICATION_FLUSH_PERMISSIONS = "flush-pending-permissions"; const NOTIFICATION_FLUSH_PERMISSIONS = "flush-pending-permissions";
function Permission(host, rawHost, type, capability) function Permission(host, rawHost, type, capability)
{ {
this.host = host; this.host = host;
this.rawHost = rawHost; this.rawHost = rawHost;
@ -17,18 +19,19 @@ function Permission(host, rawHost, type, capability)
} }
var gPermissionManager = { var gPermissionManager = {
_type : "", _type : "",
_permissions : [], _permissions : [],
_pm : Components.classes["@mozilla.org/permissionmanager;1"] _permissionsToAdd : new Map(),
.getService(Components.interfaces.nsIPermissionManager), _permissionsToDelete : new Map(),
_bundle : null, _bundle : null,
_tree : null, _tree : null,
_observerRemoved : false,
_view: { _view: {
_rowCount: 0, _rowCount: 0,
get rowCount() get rowCount()
{ {
return this._rowCount; return this._rowCount;
}, },
getCellText: function (aRow, aColumn) getCellText: function (aRow, aColumn)
{ {
@ -56,7 +59,7 @@ var gPermissionManager = {
return ""; return "";
} }
}, },
_getCapabilityString: function (aCapability) _getCapabilityString: function (aCapability)
{ {
var stringKey = null; var stringKey = null;
@ -76,44 +79,48 @@ var gPermissionManager = {
} }
return this._bundle.getString(stringKey); return this._bundle.getString(stringKey);
}, },
addPermission: function (aCapability) addPermission: function (aCapability)
{ {
var textbox = document.getElementById("url"); var textbox = document.getElementById("url");
var host = textbox.value.replace(/^\s*([-\w]*:\/+)?/, ""); // trim any leading space and scheme var host = textbox.value.replace(/^\s*([-\w]*:\/+)?/, ""); // trim any leading space and scheme
try { try {
var ioService = Components.classes["@mozilla.org/network/io-service;1"] var uri = Services.io.newURI("http://" + host, null, null);
.getService(Components.interfaces.nsIIOService);
var uri = ioService.newURI("http://"+host, null, null);
host = uri.host; host = uri.host;
} catch(ex) { } catch(ex) {
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var message = this._bundle.getString("invalidURI"); var message = this._bundle.getString("invalidURI");
var title = this._bundle.getString("invalidURITitle"); var title = this._bundle.getString("invalidURITitle");
promptService.alert(window, title, message); Services.prompt.alert(window, title, message);
return; return;
} }
var capabilityString = this._getCapabilityString(aCapability); var capabilityString = this._getCapabilityString(aCapability);
// check whether the permission already exists, if not, add it // check whether the permission already exists, if not, add it
var exists = false; let hostExists = false;
let capabilityExists = false;
for (var i = 0; i < this._permissions.length; ++i) { for (var i = 0; i < this._permissions.length; ++i) {
if (this._permissions[i].rawHost == host) { if (this._permissions[i].rawHost == host) {
// Avoid calling the permission manager if the capability settings are hostExists = true;
// the same. Otherwise allow the call to the permissions manager to capabilityExists = this._permissions[i].capability == capabilityString;
// update the listbox for us. if (!capabilityExists) {
exists = this._permissions[i].capability == capabilityString; this._permissions[i].capability = capabilityString;
}
break; break;
} }
} }
if (!exists) {
host = (host.charAt(0) == ".") ? host.substring(1,host.length) : host; let permissionParams = {host: host, type: this._type, capability: aCapability};
var uri = ioService.newURI("http://" + host, null, null); if (!hostExists) {
this._pm.add(uri, this._type, aCapability); this._permissionsToAdd.set(host, permissionParams);
this._addPermission(permissionParams);
} }
else if (!capabilityExists) {
this._permissionsToAdd.set(host, permissionParams);
this._handleCapabilityChange();
}
textbox.value = ""; textbox.value = "";
textbox.focus(); textbox.focus();
@ -123,14 +130,58 @@ var gPermissionManager = {
// enable "remove all" button as needed // enable "remove all" button as needed
document.getElementById("removeAllPermissions").disabled = this._permissions.length == 0; document.getElementById("removeAllPermissions").disabled = this._permissions.length == 0;
}, },
_removePermission: function(aPermission)
{
this._removePermissionFromList(aPermission.host);
// If this permission was added during this session, let's remove
// it from the pending adds list to prevent calls to the
// permission manager.
let isNewPermission = this._permissionsToAdd.delete(aPermission.host);
if (!isNewPermission) {
this._permissionsToDelete.set(aPermission.host, aPermission);
}
},
_handleCapabilityChange: function ()
{
// Re-do the sort, if the status changed from Block to Allow
// or vice versa, since if we're sorted on status, we may no
// longer be in order.
if (this._lastPermissionSortColumn.id == "statusCol") {
this._resortPermissions();
}
this._tree.treeBoxObject.invalidate();
},
_addPermission: function(aPermission)
{
this._addPermissionToList(aPermission);
++this._view._rowCount;
this._tree.treeBoxObject.rowCountChanged(this._view.rowCount - 1, 1);
// Re-do the sort, since we inserted this new item at the end.
this._resortPermissions();
},
_resortPermissions: function()
{
gTreeUtils.sort(this._tree, this._view, this._permissions,
this._lastPermissionSortColumn,
this._permissionsComparator,
this._lastPermissionSortColumn,
!this._lastPermissionSortAscending); // keep sort direction
},
onHostInput: function (aSiteField) onHostInput: function (aSiteField)
{ {
document.getElementById("btnSession").disabled = !aSiteField.value; document.getElementById("btnSession").disabled = !aSiteField.value;
document.getElementById("btnBlock").disabled = !aSiteField.value; document.getElementById("btnBlock").disabled = !aSiteField.value;
document.getElementById("btnAllow").disabled = !aSiteField.value; document.getElementById("btnAllow").disabled = !aSiteField.value;
}, },
onWindowKeyPress: function (aEvent) onWindowKeyPress: function (aEvent)
{ {
if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE) if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE)
@ -142,14 +193,14 @@ var gPermissionManager = {
if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN) if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN)
document.getElementById("btnAllow").click(); document.getElementById("btnAllow").click();
}, },
onLoad: function () onLoad: function ()
{ {
this._bundle = document.getElementById("bundlePreferences"); this._bundle = document.getElementById("bundlePreferences");
var params = window.arguments[0]; var params = window.arguments[0];
this.init(params); this.init(params);
}, },
init: function (aParams) init: function (aParams)
{ {
if (this._type) { if (this._type) {
@ -159,14 +210,14 @@ var gPermissionManager = {
this._type = aParams.permissionType; this._type = aParams.permissionType;
this._manageCapability = aParams.manageCapability; this._manageCapability = aParams.manageCapability;
var permissionsText = document.getElementById("permissionsText"); var permissionsText = document.getElementById("permissionsText");
while (permissionsText.hasChildNodes()) while (permissionsText.hasChildNodes())
permissionsText.removeChild(permissionsText.firstChild); permissionsText.removeChild(permissionsText.firstChild);
permissionsText.appendChild(document.createTextNode(aParams.introText)); permissionsText.appendChild(document.createTextNode(aParams.introText));
document.title = aParams.windowTitle; document.title = aParams.windowTitle;
document.getElementById("btnBlock").hidden = !aParams.blockVisible; document.getElementById("btnBlock").hidden = !aParams.blockVisible;
document.getElementById("btnSession").hidden = !aParams.sessionVisible; document.getElementById("btnSession").hidden = !aParams.sessionVisible;
document.getElementById("btnAllow").hidden = !aParams.allowVisible; document.getElementById("btnAllow").hidden = !aParams.allowVisible;
@ -184,21 +235,23 @@ var gPermissionManager = {
var os = Components.classes["@mozilla.org/observer-service;1"] var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService); .getService(Components.interfaces.nsIObserverService);
os.notifyObservers(null, NOTIFICATION_FLUSH_PERMISSIONS, this._type); Services.obs.notifyObservers(null, NOTIFICATION_FLUSH_PERMISSIONS, this._type);
os.addObserver(this, "perm-changed", false); Services.obs.addObserver(this, "perm-changed", false);
this._loadPermissions(); this._loadPermissions();
urlField.focus(); urlField.focus();
}, },
uninit: function () uninit: function ()
{ {
var os = Components.classes["@mozilla.org/observer-service;1"] if (!this._observerRemoved) {
.getService(Components.interfaces.nsIObserverService); Services.obs.removeObserver(this, "perm-changed");
os.removeObserver(this, "perm-changed");
this._observerRemoved = true;
}
}, },
observe: function (aSubject, aTopic, aData) observe: function (aSubject, aTopic, aData)
{ {
if (aTopic == "perm-changed") { if (aTopic == "perm-changed") {
@ -209,15 +262,7 @@ var gPermissionManager = {
return; return;
if (aData == "added") { if (aData == "added") {
this._addPermissionToList(permission); this._addPermission(permission);
++this._view._rowCount;
this._tree.treeBoxObject.rowCountChanged(this._view.rowCount - 1, 1);
// Re-do the sort, since we inserted this new item at the end.
gTreeUtils.sort(this._tree, this._view, this._permissions,
this._lastPermissionSortColumn,
this._permissionsComparator,
this._lastPermissionSortColumn,
!this._lastPermissionSortAscending); // keep sort direction
} }
else if (aData == "changed") { else if (aData == "changed") {
for (var i = 0; i < this._permissions.length; ++i) { for (var i = 0; i < this._permissions.length; ++i) {
@ -226,32 +271,14 @@ var gPermissionManager = {
break; break;
} }
} }
// Re-do the sort, if the status changed from Block to Allow this._handleCapabilityChange();
// or vice versa, since if we're sorted on status, we may no
// longer be in order.
if (this._lastPermissionSortColumn == "statusCol") {
gTreeUtils.sort(this._tree, this._view, this._permissions,
this._lastPermissionSortColumn,
this._permissionsComparator,
this._lastPermissionSortColumn,
!this._lastPermissionSortAscending); // keep sort direction
}
this._tree.treeBoxObject.invalidate();
} }
else if (aData == "deleted") { else if (aData == "deleted") {
for (var i = 0; i < this._permissions.length; i++) { this._removePermissionFromList(permission);
if (this._permissions[i].host == permission.host) {
this._permissions.splice(i, 1);
this._view._rowCount--;
this._tree.treeBoxObject.rowCountChanged(this._view.rowCount - 1, -1);
this._tree.treeBoxObject.invalidate();
break;
}
}
} }
} }
}, },
onPermissionSelected: function () onPermissionSelected: function ()
{ {
var hasSelection = this._tree.view.selection.count > 0; var hasSelection = this._tree.view.selection.count > 0;
@ -268,8 +295,8 @@ var gPermissionManager = {
gTreeUtils.deleteSelectedItems(this._tree, this._view, this._permissions, removedPermissions); gTreeUtils.deleteSelectedItems(this._tree, this._view, this._permissions, removedPermissions);
for (var i = 0; i < removedPermissions.length; ++i) { for (var i = 0; i < removedPermissions.length; ++i) {
var p = removedPermissions[i]; var p = removedPermissions[i];
this._pm.remove(p.host, p.type); this._removePermission(p);
} }
document.getElementById("removePermission").disabled = !this._permissions.length; document.getElementById("removePermission").disabled = !this._permissions.length;
document.getElementById("removeAllPermissions").disabled = !this._permissions.length; document.getElementById("removeAllPermissions").disabled = !this._permissions.length;
}, },
@ -282,12 +309,12 @@ var gPermissionManager = {
gTreeUtils.deleteAll(this._tree, this._view, this._permissions, removedPermissions); gTreeUtils.deleteAll(this._tree, this._view, this._permissions, removedPermissions);
for (var i = 0; i < removedPermissions.length; ++i) { for (var i = 0; i < removedPermissions.length; ++i) {
var p = removedPermissions[i]; var p = removedPermissions[i];
this._pm.remove(p.host, p.type); this._removePermission(p);
} }
document.getElementById("removePermission").disabled = true; document.getElementById("removePermission").disabled = true;
document.getElementById("removeAllPermissions").disabled = true; document.getElementById("removeAllPermissions").disabled = true;
}, },
onPermissionKeyPress: function (aEvent) onPermissionKeyPress: function (aEvent)
{ {
if (aEvent.keyCode == KeyEvent.DOM_VK_DELETE if (aEvent.keyCode == KeyEvent.DOM_VK_DELETE
@ -298,7 +325,7 @@ var gPermissionManager = {
this.onPermissionDeleted(); this.onPermissionDeleted();
} }
}, },
_lastPermissionSortColumn: "", _lastPermissionSortColumn: "",
_lastPermissionSortAscending: false, _lastPermissionSortAscending: false,
_permissionsComparator : function (a, b) _permissionsComparator : function (a, b)
@ -309,16 +336,35 @@ var gPermissionManager = {
onPermissionSort: function (aColumn) onPermissionSort: function (aColumn)
{ {
this._lastPermissionSortAscending = gTreeUtils.sort(this._tree, this._lastPermissionSortAscending = gTreeUtils.sort(this._tree,
this._view, this._view,
this._permissions, this._permissions,
aColumn, aColumn,
this._permissionsComparator, this._permissionsComparator,
this._lastPermissionSortColumn, this._lastPermissionSortColumn,
this._lastPermissionSortAscending); this._lastPermissionSortAscending);
this._lastPermissionSortColumn = aColumn; this._lastPermissionSortColumn = aColumn;
}, },
onApplyChanges: function()
{
// Stop observing permission changes since we are about
// to write out the pending adds/deletes and don't need
// to update the UI
this.uninit();
for (let permissionParams of this._permissionsToAdd.values()) {
let uri = Services.io.newURI("http://" + permissionParams.host, null, null);
Services.perms.add(uri, permissionParams.type, permissionParams.capability);
}
for (let p of this._permissionsToDelete.values()) {
Services.perms.remove(p.host, p.type);
}
window.close();
},
_loadPermissions: function () _loadPermissions: function ()
{ {
this._tree = document.getElementById("permissionsTree"); this._tree = document.getElementById("permissionsTree");
@ -326,12 +372,12 @@ var gPermissionManager = {
// load permissions into a table // load permissions into a table
var count = 0; var count = 0;
var enumerator = this._pm.enumerator; var enumerator = Services.perms.enumerator;
while (enumerator.hasMoreElements()) { while (enumerator.hasMoreElements()) {
var nextPermission = enumerator.getNext().QueryInterface(Components.interfaces.nsIPermission); var nextPermission = enumerator.getNext().QueryInterface(Components.interfaces.nsIPermission);
this._addPermissionToList(nextPermission); this._addPermissionToList(nextPermission);
} }
this._view._rowCount = this._permissions.length; this._view._rowCount = this._permissions.length;
// sort and display the table // sort and display the table
@ -341,7 +387,7 @@ var gPermissionManager = {
// disable "remove all" button if there are none // disable "remove all" button if there are none
document.getElementById("removeAllPermissions").disabled = this._permissions.length == 0; document.getElementById("removeAllPermissions").disabled = this._permissions.length == 0;
}, },
_addPermissionToList: function (aPermission) _addPermissionToList: function (aPermission)
{ {
if (aPermission.type == this._type && if (aPermission.type == this._type &&
@ -355,15 +401,28 @@ var gPermissionManager = {
aPermission.type, aPermission.type,
capabilityString); capabilityString);
this._permissions.push(p); this._permissions.push(p);
} }
}, },
setHost: function (aHost) setHost: function (aHost)
{ {
document.getElementById("url").value = aHost; document.getElementById("url").value = aHost;
} }
}; };
_removePermissionFromList: function (aHost)
{
for (let i = 0; i < this._permissions.length; ++i) {
if (this._permissions[i].host == aHost) {
this._permissions.splice(i, 1);
this._view._rowCount--;
this._tree.treeBoxObject.rowCountChanged(this._view.rowCount - 1, -1);
this._tree.treeBoxObject.invalidate();
break;
}
}
},
function setHost(aHost) function setHost(aHost)
{ {
gPermissionManager.setHost(aHost); gPermissionManager.setHost(aHost);

View file

@ -62,8 +62,8 @@
<treechildren/> <treechildren/>
</tree> </tree>
</vbox> </vbox>
<hbox align="end"> <vbox>
<hbox class="actionButtons" flex="1"> <hbox class="actionButtons" align="left" flex="1">
<button id="removePermission" disabled="true" <button id="removePermission" disabled="true"
accesskey="&removepermission.accesskey;" accesskey="&removepermission.accesskey;"
icon="remove" label="&removepermission.label;" icon="remove" label="&removepermission.label;"
@ -72,12 +72,14 @@
icon="clear" label="&removeallpermissions.label;" icon="clear" label="&removeallpermissions.label;"
accesskey="&removeallpermissions.accesskey;" accesskey="&removeallpermissions.accesskey;"
oncommand="gPermissionManager.onAllPermissionsDeleted();"/> oncommand="gPermissionManager.onAllPermissionsDeleted();"/>
<spacer flex="1"/> </hbox>
#ifndef XP_MACOSX <spacer flex="1"/>
<hbox class="actionButtons" align="right" flex="1">
<button oncommand="close();" icon="close" <button oncommand="close();" icon="close"
label="&button.close.label;" accesskey="&button.close.accesskey;"/> label="&button.cancel.label;" accesskey="&button.cancel.accesskey;" />
#endif <button id="btnApplyChanges" oncommand="gPermissionManager.onApplyChanges();" icon="save"
label="&button.ok.label;" accesskey="&button.ok.accesskey;"/>
</hbox> </hbox>
<resizer type="window" dir="bottomend"/> <resizer type="window" dir="bottomend"/>
</hbox> </vbox>
</window> </window>

View file

@ -3,7 +3,7 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!ENTITY window.title "Exceptions"> <!ENTITY window.title "Exceptions">
<!ENTITY window.width "36em"> <!ENTITY window.width "45em">
<!ENTITY treehead.sitename.label "Site"> <!ENTITY treehead.sitename.label "Site">
<!ENTITY treehead.status.label "Status"> <!ENTITY treehead.status.label "Status">
@ -21,6 +21,8 @@
<!ENTITY allow.accesskey "A"> <!ENTITY allow.accesskey "A">
<!ENTITY windowClose.key "w"> <!ENTITY windowClose.key "w">
<!ENTITY button.close.label "Close"> <!ENTITY button.cancel.label "Cancel">
<!ENTITY button.close.accesskey "C"> <!ENTITY button.cancel.accesskey "C">
<!ENTITY button.ok.label "Save Changes">
<!ENTITY button.ok.accesskey "S">