translationExceptions.js (6529B)
1 /* -*- indent-tabs-mode: nil; js-indent-level: 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/. */ 5 6 // TODO (Bug 1817084) Remove this file when we disable the extension 7 8 "use strict"; 9 10 const kPermissionType = "translate"; 11 const kLanguagesPref = "browser.translation.neverForLanguages"; 12 13 function Tree(aId, aData) { 14 this._data = aData; 15 this._tree = document.getElementById(aId); 16 this._tree.view = this; 17 } 18 19 Tree.prototype = { 20 get tree() { 21 return this._tree; 22 }, 23 get isEmpty() { 24 return !this._data.length; 25 }, 26 get hasSelection() { 27 return this.selection.count > 0; 28 }, 29 getSelectedItems() { 30 let result = []; 31 32 let rc = this.selection.getRangeCount(); 33 for (let i = 0; i < rc; ++i) { 34 let min = {}, 35 max = {}; 36 this.selection.getRangeAt(i, min, max); 37 for (let j = min.value; j <= max.value; ++j) { 38 result.push(this._data[j]); 39 } 40 } 41 42 return result; 43 }, 44 45 // nsITreeView implementation 46 get rowCount() { 47 return this._data.length; 48 }, 49 getCellText(aRow) { 50 return this._data[aRow]; 51 }, 52 isSeparator() { 53 return false; 54 }, 55 isSorted() { 56 return false; 57 }, 58 isContainer() { 59 return false; 60 }, 61 setTree() {}, 62 getImageSrc() {}, 63 getCellValue() {}, 64 cycleHeader() {}, 65 getRowProperties() { 66 return ""; 67 }, 68 getColumnProperties() { 69 return ""; 70 }, 71 getCellProperties() { 72 return ""; 73 }, 74 QueryInterface: ChromeUtils.generateQI(["nsITreeView"]), 75 }; 76 77 function Lang(aCode, label) { 78 this.langCode = aCode; 79 this._label = label; 80 } 81 82 Lang.prototype = { 83 toString() { 84 return this._label; 85 }, 86 }; 87 88 var gTranslationExceptions = { 89 onLoad() { 90 if (this._siteTree) { 91 // Re-using an open dialog, clear the old observers. 92 this.uninit(); 93 } 94 95 // Load site permissions into an array. 96 this._sites = []; 97 for (let perm of Services.perms.all) { 98 if ( 99 perm.type == kPermissionType && 100 perm.capability == Services.perms.DENY_ACTION 101 ) { 102 this._sites.push(perm.principal.origin); 103 } 104 } 105 Services.obs.addObserver(this, "perm-changed"); 106 this._sites.sort(); 107 108 this._siteTree = new Tree("sitesTree", this._sites); 109 this.onSiteSelected(); 110 111 this._langs = this.getLanguageExceptions(); 112 Services.prefs.addObserver(kLanguagesPref, this); 113 this._langTree = new Tree("languagesTree", this._langs); 114 this.onLanguageSelected(); 115 }, 116 117 // Get the list of languages we don't translate as an array. 118 getLanguageExceptions() { 119 let langs = Services.prefs.getCharPref(kLanguagesPref); 120 if (!langs) { 121 return []; 122 } 123 124 let langArr = langs.split(","); 125 let displayNames = Services.intl.getLanguageDisplayNames( 126 undefined, 127 langArr 128 ); 129 let result = langArr.map((lang, i) => new Lang(lang, displayNames[i])); 130 result.sort(); 131 132 return result; 133 }, 134 135 observe(aSubject, aTopic, aData) { 136 if (aTopic == "perm-changed") { 137 if (aData == "cleared") { 138 if (!this._sites.length) { 139 return; 140 } 141 let removed = this._sites.splice(0, this._sites.length); 142 this._siteTree.tree.rowCountChanged(0, -removed.length); 143 } else { 144 let perm = aSubject.QueryInterface(Ci.nsIPermission); 145 if (perm.type != kPermissionType) { 146 return; 147 } 148 149 if (aData == "added") { 150 if (perm.capability != Services.perms.DENY_ACTION) { 151 return; 152 } 153 this._sites.push(perm.principal.origin); 154 this._sites.sort(); 155 let tree = this._siteTree.tree; 156 tree.rowCountChanged(0, 1); 157 tree.invalidate(); 158 } else if (aData == "deleted") { 159 let index = this._sites.indexOf(perm.principal.origin); 160 if (index == -1) { 161 return; 162 } 163 this._sites.splice(index, 1); 164 this._siteTree.tree.rowCountChanged(index, -1); 165 this.onSiteSelected(); 166 return; 167 } 168 } 169 this.onSiteSelected(); 170 } else if (aTopic == "nsPref:changed") { 171 this._langs = this.getLanguageExceptions(); 172 let change = this._langs.length - this._langTree.rowCount; 173 this._langTree._data = this._langs; 174 let tree = this._langTree.tree; 175 if (change) { 176 tree.rowCountChanged(0, change); 177 } 178 tree.invalidate(); 179 this.onLanguageSelected(); 180 } 181 }, 182 183 _handleButtonDisabling(aTree, aIdPart) { 184 let empty = aTree.isEmpty; 185 document.getElementById("removeAll" + aIdPart + "s").disabled = empty; 186 document.getElementById("remove" + aIdPart).disabled = 187 empty || !aTree.hasSelection; 188 }, 189 190 onLanguageSelected() { 191 this._handleButtonDisabling(this._langTree, "Language"); 192 }, 193 194 onSiteSelected() { 195 this._handleButtonDisabling(this._siteTree, "Site"); 196 }, 197 198 onLanguageDeleted() { 199 let langs = Services.prefs.getCharPref(kLanguagesPref); 200 if (!langs) { 201 return; 202 } 203 204 let removed = this._langTree.getSelectedItems().map(l => l.langCode); 205 206 langs = langs.split(",").filter(l => !removed.includes(l)); 207 Services.prefs.setCharPref(kLanguagesPref, langs.join(",")); 208 }, 209 210 onAllLanguagesDeleted() { 211 Services.prefs.setCharPref(kLanguagesPref, ""); 212 }, 213 214 onSiteDeleted() { 215 let removedSites = this._siteTree.getSelectedItems(); 216 for (let origin of removedSites) { 217 let principal = 218 Services.scriptSecurityManager.createContentPrincipalFromOrigin(origin); 219 Services.perms.removeFromPrincipal(principal, kPermissionType); 220 } 221 }, 222 223 onAllSitesDeleted() { 224 if (this._siteTree.isEmpty) { 225 return; 226 } 227 228 let removedSites = this._sites.splice(0, this._sites.length); 229 this._siteTree.tree.rowCountChanged(0, -removedSites.length); 230 231 for (let origin of removedSites) { 232 let principal = 233 Services.scriptSecurityManager.createContentPrincipalFromOrigin(origin); 234 Services.perms.removeFromPrincipal(principal, kPermissionType); 235 } 236 237 this.onSiteSelected(); 238 }, 239 240 onSiteKeyPress(aEvent) { 241 if (aEvent.keyCode == KeyEvent.DOM_VK_DELETE) { 242 this.onSiteDeleted(); 243 } 244 }, 245 246 onLanguageKeyPress(aEvent) { 247 if (aEvent.keyCode == KeyEvent.DOM_VK_DELETE) { 248 this.onLanguageDeleted(); 249 } 250 }, 251 252 uninit() { 253 Services.obs.removeObserver(this, "perm-changed"); 254 Services.prefs.removeObserver(kLanguagesPref, this); 255 }, 256 };