summaryrefslogtreecommitdiffstats
path: root/webbrowser/modules/CharsetMenu.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'webbrowser/modules/CharsetMenu.jsm')
-rw-r--r--webbrowser/modules/CharsetMenu.jsm160
1 files changed, 160 insertions, 0 deletions
diff --git a/webbrowser/modules/CharsetMenu.jsm b/webbrowser/modules/CharsetMenu.jsm
new file mode 100644
index 0000000..f973088
--- /dev/null
+++ b/webbrowser/modules/CharsetMenu.jsm
@@ -0,0 +1,160 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+this.EXPORTED_SYMBOLS = [ "CharsetMenu" ];
+
+const { classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyGetter(this, "gBundle", function() {
+ const kUrl = "chrome://browser/locale/charsetMenu.properties";
+ return Services.strings.createBundle(kUrl);
+});
+/**
+ * This set contains encodings that are in the Encoding Standard, except:
+ * - XSS-dangerous encodings (except ISO-2022-JP which is assumed to be
+ * too common not to be included).
+ * - x-user-defined, which practically never makes sense as an end-user-chosen
+ * override.
+ * - Encodings that IE11 doesn't have in its correspoding menu.
+ */
+const kEncodings = new Set([
+ // Globally relevant
+ "UTF-8",
+ "windows-1252",
+ // Arabic
+ "windows-1256",
+ "ISO-8859-6",
+ // Baltic
+ "windows-1257",
+ "ISO-8859-4",
+ // "ISO-8859-13", // Hidden since not in menu in IE11
+ // Central European
+ "windows-1250",
+ "ISO-8859-2",
+ // Chinese, Simplified
+ "gbk",
+ "gb18030",
+ // Chinese, Traditional
+ "Big5",
+ // Cyrillic
+ "windows-1251",
+ "ISO-8859-5",
+ "KOI8-R",
+ "KOI8-U",
+ "IBM866", // Not in menu in Chromium. Maybe drop this?
+ // "x-mac-cyrillic", // Not in menu in IE11 or Chromium.
+ // Greek
+ "windows-1253",
+ "ISO-8859-7",
+ // Hebrew
+ "windows-1255",
+ "ISO-8859-8-I",
+ "ISO-8859-8",
+ // Japanese
+ "Shift_JIS",
+ "EUC-JP",
+ "ISO-2022-JP",
+ // Korean
+ "EUC-KR",
+ // Thai
+ "windows-874",
+ // Turkish
+ "windows-1254",
+ // Vietnamese
+ "windows-1258",
+ // Hiding rare European encodings that aren't in the menu in IE11 and would
+ // make the menu messy by sorting all over the place
+ // "ISO-8859-3",
+ // "ISO-8859-10",
+ // "ISO-8859-14",
+ // "ISO-8859-15",
+ // "ISO-8859-16",
+ // "macintosh"
+]);
+
+// Always at the start of the menu, in this order, followed by a separator.
+const kPinned = [
+ "UTF-8",
+ "windows-1252"
+];
+
+this.CharsetMenu = Object.freeze({
+ build: function BuildCharsetMenu(event) {
+ let parent = event.target;
+ if (parent.lastChild.localName != "menuseparator") {
+ // Detector menu or charset menu already built
+ return;
+ }
+ let doc = parent.ownerDocument;
+
+ function createItem(encoding) {
+ let menuItem = doc.createElement("menuitem");
+ menuItem.setAttribute("type", "radio");
+ menuItem.setAttribute("name", "charsetGroup");
+ try {
+ menuItem.setAttribute("label", gBundle.GetStringFromName(encoding));
+ } catch (e) {
+ // Localization error but put *something* in the menu to recover.
+ menuItem.setAttribute("label", encoding);
+ }
+ try {
+ menuItem.setAttribute("accesskey",
+ gBundle.GetStringFromName(encoding + ".key"));
+ } catch (e) {
+ // Some items intentionally don't have an accesskey
+ }
+ menuItem.setAttribute("id", "charset." + encoding);
+ return menuItem;
+ }
+
+ // Clone the set in order to be able to remove the pinned encodings from
+ // the cloned set.
+ let encodings = new Set(kEncodings);
+ for (let encoding of kPinned) {
+ encodings.delete(encoding);
+ parent.appendChild(createItem(encoding));
+ }
+ parent.appendChild(doc.createElement("menuseparator"));
+ let list = [];
+ for (let encoding of encodings) {
+ list.push(createItem(encoding));
+ }
+
+ list.sort(function (a, b) {
+ let titleA = a.getAttribute("label");
+ let titleB = b.getAttribute("label");
+ // Normal sorting sorts the part in parenthesis in an order that
+ // happens to make the less frequently-used items first.
+ let index;
+ if ((index = titleA.indexOf("(")) > -1) {
+ titleA = titleA.substring(0, index);
+ }
+ if ((index = titleB.indexOf("(")) > -1) {
+ titleA = titleB.substring(0, index);
+ }
+ let comp = titleA.localeCompare(titleB);
+ if (comp) {
+ return comp;
+ }
+ // secondarily reverse sort by encoding name to sort "windows" or
+ // "shift_jis" first. This works regardless of localization, because
+ // the ids aren't localized.
+ let idA = a.getAttribute("id");
+ let idB = b.getAttribute("id");
+ if (idA < idB) {
+ return 1;
+ }
+ if (idB < idA) {
+ return -1;
+ }
+ return 0;
+ });
+
+ for (let item of list) {
+ parent.appendChild(item);
+ }
+ },
+}); \ No newline at end of file