From 4492b5f8e774bf3b4f21e4e468fc052cbcbb468a Mon Sep 17 00:00:00 2001 From: Thomas Groman Date: Mon, 16 Dec 2019 19:48:42 -0800 Subject: initial commit --- modules/CharsetMenu.jsm | 160 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 modules/CharsetMenu.jsm (limited to 'modules/CharsetMenu.jsm') diff --git a/modules/CharsetMenu.jsm b/modules/CharsetMenu.jsm new file mode 100644 index 0000000..f973088 --- /dev/null +++ b/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 -- cgit v1.2.3