toolkit/modules/CharsetMenu.jsm

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 this.EXPORTED_SYMBOLS = [ "CharsetMenu" ];
michael@0 6
michael@0 7 const { classes: Cc, interfaces: Ci, utils: Cu} = Components;
michael@0 8
michael@0 9 Cu.import("resource://gre/modules/Services.jsm");
michael@0 10 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 11 XPCOMUtils.defineLazyGetter(this, "gBundle", function() {
michael@0 12 const kUrl = "chrome://global/locale/charsetMenu.properties";
michael@0 13 return Services.strings.createBundle(kUrl);
michael@0 14 });
michael@0 15
michael@0 16 const kAutoDetectors = [
michael@0 17 ["off", ""],
michael@0 18 ["ja", "ja_parallel_state_machine"],
michael@0 19 ["ru", "ruprob"],
michael@0 20 ["uk", "ukprob"]
michael@0 21 ];
michael@0 22
michael@0 23 /**
michael@0 24 * This set contains encodings that are in the Encoding Standard, except:
michael@0 25 * - XSS-dangerous encodings (except ISO-2022-JP which is assumed to be
michael@0 26 * too common not to be included).
michael@0 27 * - x-user-defined, which practically never makes sense as an end-user-chosen
michael@0 28 * override.
michael@0 29 * - Encodings that IE11 doesn't have in its correspoding menu.
michael@0 30 */
michael@0 31 const kEncodings = new Set([
michael@0 32 // Globally relevant
michael@0 33 "UTF-8",
michael@0 34 "windows-1252",
michael@0 35 // Arabic
michael@0 36 "windows-1256",
michael@0 37 "ISO-8859-6",
michael@0 38 // Baltic
michael@0 39 "windows-1257",
michael@0 40 "ISO-8859-4",
michael@0 41 // "ISO-8859-13", // Hidden since not in menu in IE11
michael@0 42 // Central European
michael@0 43 "windows-1250",
michael@0 44 "ISO-8859-2",
michael@0 45 // Chinese, Simplified
michael@0 46 "gbk",
michael@0 47 // Chinese, Traditional
michael@0 48 "Big5",
michael@0 49 // Cyrillic
michael@0 50 "windows-1251",
michael@0 51 "ISO-8859-5",
michael@0 52 "KOI8-R",
michael@0 53 "KOI8-U",
michael@0 54 "IBM866", // Not in menu in Chromium. Maybe drop this?
michael@0 55 // "x-mac-cyrillic", // Not in menu in IE11 or Chromium.
michael@0 56 // Greek
michael@0 57 "windows-1253",
michael@0 58 "ISO-8859-7",
michael@0 59 // Hebrew
michael@0 60 "windows-1255",
michael@0 61 "ISO-8859-8",
michael@0 62 // Japanese
michael@0 63 "Shift_JIS",
michael@0 64 "EUC-JP",
michael@0 65 "ISO-2022-JP",
michael@0 66 // Korean
michael@0 67 "EUC-KR",
michael@0 68 // Thai
michael@0 69 "windows-874",
michael@0 70 // Turkish
michael@0 71 "windows-1254",
michael@0 72 // Vietnamese
michael@0 73 "windows-1258",
michael@0 74 // Hiding rare European encodings that aren't in the menu in IE11 and would
michael@0 75 // make the menu messy by sorting all over the place
michael@0 76 // "ISO-8859-3",
michael@0 77 // "ISO-8859-10",
michael@0 78 // "ISO-8859-14",
michael@0 79 // "ISO-8859-15",
michael@0 80 // "ISO-8859-16",
michael@0 81 // "macintosh"
michael@0 82 ]);
michael@0 83
michael@0 84 // Always at the start of the menu, in this order, followed by a separator.
michael@0 85 const kPinned = [
michael@0 86 "UTF-8",
michael@0 87 "windows-1252"
michael@0 88 ];
michael@0 89
michael@0 90 kPinned.forEach(x => kEncodings.delete(x));
michael@0 91
michael@0 92 function CharsetComparator(a, b) {
michael@0 93 // Normal sorting sorts the part in parenthesis in an order that
michael@0 94 // happens to make the less frequently-used items first.
michael@0 95 let titleA = a.label.replace(/\(.*/, "") + b.value;
michael@0 96 let titleB = b.label.replace(/\(.*/, "") + a.value;
michael@0 97 // Secondarily reverse sort by encoding name to sort "windows" or
michael@0 98 // "shift_jis" first.
michael@0 99 return titleA.localeCompare(titleB) || b.value.localeCompare(a.value);
michael@0 100 }
michael@0 101
michael@0 102 function SetDetector(event) {
michael@0 103 let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
michael@0 104 str.data = event.target.getAttribute("detector");
michael@0 105 Services.prefs.setComplexValue("intl.charset.detector", Ci.nsISupportsString, str);
michael@0 106 }
michael@0 107
michael@0 108 function UpdateDetectorMenu(event) {
michael@0 109 event.stopPropagation();
michael@0 110 let detector = Services.prefs.getComplexValue("intl.charset.detector", Ci.nsIPrefLocalizedString);
michael@0 111 let menuitem = this.getElementsByAttribute("detector", detector).item(0);
michael@0 112 if (menuitem) {
michael@0 113 menuitem.setAttribute("checked", "true");
michael@0 114 }
michael@0 115 }
michael@0 116
michael@0 117 let gDetectorInfoCache, gCharsetInfoCache, gPinnedInfoCache;
michael@0 118
michael@0 119 let CharsetMenu = {
michael@0 120 build: function(parent, showAccessKeys=true, showDetector=true) {
michael@0 121 function createDOMNode(doc, nodeInfo) {
michael@0 122 let node = doc.createElement("menuitem");
michael@0 123 node.setAttribute("type", "radio");
michael@0 124 node.setAttribute("name", nodeInfo.name + "Group");
michael@0 125 node.setAttribute(nodeInfo.name, nodeInfo.value);
michael@0 126 node.setAttribute("label", nodeInfo.label);
michael@0 127 if (showAccessKeys && nodeInfo.accesskey) {
michael@0 128 node.setAttribute("accesskey", nodeInfo.accesskey);
michael@0 129 }
michael@0 130 return node;
michael@0 131 }
michael@0 132
michael@0 133 if (parent.hasChildNodes()) {
michael@0 134 // Detector menu or charset menu already built
michael@0 135 return;
michael@0 136 }
michael@0 137 this._ensureDataReady();
michael@0 138 let doc = parent.ownerDocument;
michael@0 139
michael@0 140 if (showDetector) {
michael@0 141 let menuNode = doc.createElement("menu");
michael@0 142 menuNode.setAttribute("label", gBundle.GetStringFromName("charsetMenuAutodet"));
michael@0 143 if (showAccessKeys) {
michael@0 144 menuNode.setAttribute("accesskey", gBundle.GetStringFromName("charsetMenuAutodet.key"));
michael@0 145 }
michael@0 146 parent.appendChild(menuNode);
michael@0 147
michael@0 148 let menuPopupNode = doc.createElement("menupopup");
michael@0 149 menuNode.appendChild(menuPopupNode);
michael@0 150 menuPopupNode.addEventListener("command", SetDetector);
michael@0 151 menuPopupNode.addEventListener("popupshown", UpdateDetectorMenu);
michael@0 152
michael@0 153 gDetectorInfoCache.forEach(detectorInfo => menuPopupNode.appendChild(createDOMNode(doc, detectorInfo)));
michael@0 154 parent.appendChild(doc.createElement("menuseparator"));
michael@0 155 }
michael@0 156
michael@0 157 gPinnedInfoCache.forEach(charsetInfo => parent.appendChild(createDOMNode(doc, charsetInfo)));
michael@0 158 parent.appendChild(doc.createElement("menuseparator"));
michael@0 159 gCharsetInfoCache.forEach(charsetInfo => parent.appendChild(createDOMNode(doc, charsetInfo)));
michael@0 160 },
michael@0 161
michael@0 162 getData: function() {
michael@0 163 this._ensureDataReady();
michael@0 164 return {
michael@0 165 detectors: gDetectorInfoCache,
michael@0 166 pinnedCharsets: gPinnedInfoCache,
michael@0 167 otherCharsets: gCharsetInfoCache
michael@0 168 };
michael@0 169 },
michael@0 170
michael@0 171 _ensureDataReady: function() {
michael@0 172 if (!gDetectorInfoCache) {
michael@0 173 gDetectorInfoCache = this.getDetectorInfo();
michael@0 174 gPinnedInfoCache = this.getCharsetInfo(kPinned, false);
michael@0 175 gCharsetInfoCache = this.getCharsetInfo(kEncodings);
michael@0 176 }
michael@0 177 },
michael@0 178
michael@0 179 getDetectorInfo: function() {
michael@0 180 return kAutoDetectors.map(([detectorName, nodeId]) => ({
michael@0 181 label: this._getDetectorLabel(detectorName),
michael@0 182 accesskey: this._getDetectorAccesskey(detectorName),
michael@0 183 name: "detector",
michael@0 184 value: nodeId
michael@0 185 }));
michael@0 186 },
michael@0 187
michael@0 188 getCharsetInfo: function(charsets, sort=true) {
michael@0 189 let list = [{
michael@0 190 label: this._getCharsetLabel(charset),
michael@0 191 accesskey: this._getCharsetAccessKey(charset),
michael@0 192 name: "charset",
michael@0 193 value: charset
michael@0 194 } for (charset of charsets)];
michael@0 195
michael@0 196 if (sort) {
michael@0 197 list.sort(CharsetComparator);
michael@0 198 }
michael@0 199 return list;
michael@0 200 },
michael@0 201
michael@0 202 _getDetectorLabel: function(detector) {
michael@0 203 try {
michael@0 204 return gBundle.GetStringFromName("charsetMenuAutodet." + detector);
michael@0 205 } catch (ex) {}
michael@0 206 return detector;
michael@0 207 },
michael@0 208 _getDetectorAccesskey: function(detector) {
michael@0 209 try {
michael@0 210 return gBundle.GetStringFromName("charsetMenuAutodet." + detector + ".key");
michael@0 211 } catch (ex) {}
michael@0 212 return "";
michael@0 213 },
michael@0 214
michael@0 215 _getCharsetLabel: function(charset) {
michael@0 216 if (charset == "gbk") {
michael@0 217 // Localization key has been revised
michael@0 218 charset = "gbk.bis";
michael@0 219 }
michael@0 220 try {
michael@0 221 return gBundle.GetStringFromName(charset);
michael@0 222 } catch (ex) {}
michael@0 223 return charset;
michael@0 224 },
michael@0 225 _getCharsetAccessKey: function(charset) {
michael@0 226 if (charset == "gbk") {
michael@0 227 // Localization key has been revised
michael@0 228 charset = "gbk.bis";
michael@0 229 }
michael@0 230 try {
michael@0 231 return gBundle.GetStringFromName(charset + ".key");
michael@0 232 } catch (ex) {}
michael@0 233 return "";
michael@0 234 },
michael@0 235
michael@0 236 /**
michael@0 237 * For substantially similar encodings, treat two encodings as the same
michael@0 238 * for the purpose of the check mark.
michael@0 239 */
michael@0 240 foldCharset: function(charset) {
michael@0 241 switch (charset) {
michael@0 242 case "ISO-8859-8-I":
michael@0 243 return "windows-1255";
michael@0 244
michael@0 245 case "gb18030":
michael@0 246 return "gbk";
michael@0 247
michael@0 248 default:
michael@0 249 return charset;
michael@0 250 }
michael@0 251 },
michael@0 252
michael@0 253 update: function(parent, charset) {
michael@0 254 let menuitem = parent.getElementsByAttribute("charset", this.foldCharset(charset)).item(0);
michael@0 255 if (menuitem) {
michael@0 256 menuitem.setAttribute("checked", "true");
michael@0 257 }
michael@0 258 },
michael@0 259 };
michael@0 260
michael@0 261 Object.freeze(CharsetMenu);
michael@0 262

mercurial