1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
10 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
11 Cu.import("resource://gre/modules/Services.jsm");
13 XPCOMUtils.defineLazyGetter(this, "gLangBundle", () =>
14 Services.strings.createBundle("chrome://global/locale/languageNames.properties"));
16 const kPermissionType = "translate";
17 const kLanguagesPref = "browser.translation.neverForLanguages";
19 function Tree(aId, aData)
22 this._tree = document.getElementById(aId);
23 this._tree.treeBoxObject.view = this;
27 get boxObject() this._tree.treeBoxObject,
28 get isEmpty() !this._data.length,
29 get hasSelection() this.selection.count > 0,
30 getSelectedItems: function() {
33 let rc = this.selection.getRangeCount();
34 for (let i = 0; i < rc; ++i) {
35 let min = {}, max = {};
36 this.selection.getRangeAt(i, min, max);
37 for (let j = min.value; j <= max.value; ++j)
38 result.push(this._data[j]);
44 // nsITreeView implementation
45 get rowCount() this._data.length,
46 getCellText: function (aRow, aColumn) this._data[aRow],
47 isSeparator: function(aIndex) false,
48 isSorted: function() false,
49 isContainer: function(aIndex) false,
50 setTree: function(aTree) {},
51 getImageSrc: function(aRow, aColumn) {},
52 getProgressMode: function(aRow, aColumn) {},
53 getCellValue: function(aRow, aColumn) {},
54 cycleHeader: function(column) {},
55 getRowProperties: function(row) "",
56 getColumnProperties: function(column) "",
57 getCellProperties: function(row, column) "",
58 QueryInterface: XPCOMUtils.generateQI([Ci.nsITreeView])
63 this.langCode = aCode;
64 this._label = gLangBundle.GetStringFromName(aCode);
68 toString: function() this._label
71 let gTranslationExceptions = {
74 // Re-using an open dialog, clear the old observers.
78 // Load site permissions into an array.
80 let enumerator = Services.perms.enumerator;
81 while (enumerator.hasMoreElements()) {
82 let perm = enumerator.getNext().QueryInterface(Ci.nsIPermission);
84 if (perm.type == kPermissionType &&
85 perm.capability == Services.perms.DENY_ACTION) {
86 this._sites.push(perm.host);
89 Services.obs.addObserver(this, "perm-changed", false);
92 this._siteTree = new Tree("sitesTree", this._sites);
93 this.onSiteSelected();
95 this._langs = this.getLanguageExceptions();
96 Services.prefs.addObserver(kLanguagesPref, this, false);
97 this._langTree = new Tree("languagesTree", this._langs);
98 this.onLanguageSelected();
101 // Get the list of languages we don't translate as an array.
102 getLanguageExceptions: function() {
103 let langs = Services.prefs.getCharPref(kLanguagesPref);
107 let result = langs.split(",").map(code => new Lang(code));
113 observe: function(aSubject, aTopic, aData) {
114 if (aTopic == "perm-changed") {
115 if (aData == "cleared") {
116 if (!this._sites.length)
118 let removed = this._sites.splice(0, this._sites.length);
119 this._siteTree.boxObject.rowCountChanged(0, - removed.length);
122 let perm = aSubject.QueryInterface(Ci.nsIPermission);
123 if (perm.type != kPermissionType)
126 if (aData == "added") {
127 if (perm.capability != Services.perms.DENY_ACTION)
129 this._sites.push(perm.host);
131 let boxObject = this._siteTree.boxObject;
132 boxObject.rowCountChanged(0, 1);
133 boxObject.invalidate();
135 else if (aData == "deleted") {
136 let index = this._sites.indexOf(perm.host);
139 this._sites.splice(index, 1);
140 this._siteTree.boxObject.rowCountChanged(index, -1);
141 this.onSiteSelected();
145 this.onSiteSelected();
147 else if (aTopic == "nsPref:changed") {
148 this._langs = this.getLanguageExceptions();
149 let change = this._langs.length - this._langTree.rowCount;
150 this._langTree._data = this._langs;
151 let boxObject = this._langTree.boxObject;
153 boxObject.rowCountChanged(0, change);
154 boxObject.invalidate();
155 this.onLanguageSelected();
159 _handleButtonDisabling: function(aTree, aIdPart) {
160 let empty = aTree.isEmpty;
161 document.getElementById("removeAll" + aIdPart + "s").disabled = empty;
162 document.getElementById("remove" + aIdPart).disabled =
163 empty || !aTree.hasSelection;
166 onLanguageSelected: function() {
167 this._handleButtonDisabling(this._langTree, "Language");
170 onSiteSelected: function() {
171 this._handleButtonDisabling(this._siteTree, "Site");
174 onLanguageDeleted: function() {
175 let langs = Services.prefs.getCharPref(kLanguagesPref);
179 let removed = this._langTree.getSelectedItems().map(l => l.langCode);
181 langs = langs.split(",").filter(l => removed.indexOf(l) == -1);
182 Services.prefs.setCharPref(kLanguagesPref, langs.join(","));
185 onAllLanguagesDeleted: function() {
186 Services.prefs.setCharPref(kLanguagesPref, "");
189 onSiteDeleted: function() {
190 let removedSites = this._siteTree.getSelectedItems();
191 for (let host of removedSites)
192 Services.perms.remove(host, kPermissionType);
195 onAllSitesDeleted: function() {
196 if (this._siteTree.isEmpty)
199 let removedSites = this._sites.splice(0, this._sites.length);
200 this._siteTree.boxObject.rowCountChanged(0, -removedSites.length);
202 for (let host of removedSites)
203 Services.perms.remove(host, kPermissionType);
205 this.onSiteSelected();
208 onSiteKeyPress: function(aEvent) {
209 if (aEvent.keyCode == KeyEvent.DOM_VK_DELETE)
210 this.onSiteDeleted();
213 onLanguageKeyPress: function() {
214 if (aEvent.keyCode == KeyEvent.DOM_VK_DELETE)
215 this.onLanguageDeleted();
218 onWindowKeyPress: function(aEvent) {
219 if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE)
224 Services.obs.removeObserver(this, "perm-changed");
225 Services.prefs.removeObserver(kLanguagesPref, this);