diff options
Diffstat (limited to 'toolkit/modules/CharsetMenu.jsm')
-rw-r--r-- | toolkit/modules/CharsetMenu.jsm | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/toolkit/modules/CharsetMenu.jsm b/toolkit/modules/CharsetMenu.jsm new file mode 100644 index 0000000000..2a3335dabd --- /dev/null +++ b/toolkit/modules/CharsetMenu.jsm @@ -0,0 +1,223 @@ +/* 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/. */ + +var EXPORTED_SYMBOLS = ["CharsetMenu"]; + +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); +XPCOMUtils.defineLazyGetter(this, "gBundle", function() { + const kUrl = "chrome://global/locale/charsetMenu.properties"; + return Services.strings.createBundle(kUrl); +}); + +ChromeUtils.defineModuleGetter( + this, + "Deprecated", + "resource://gre/modules/Deprecated.jsm" +); + +/** + * This set contains encodings that are in the Encoding Standard, except: + * - Japanese encodings are represented by one autodetection item + * - x-user-defined, which practically never makes sense as an end-user-chosen + * override. + * - Encodings that IE11 doesn't have in its corresponding menu. + */ +const kEncodings = new Set([ + // Globally relevant + "_autodetect_all", // (NOT AN ENCODING NAME; using IE-consistent magic name) + "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", + // 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", + // Japanese (NOT AN ENCODING NAME) + "Japanese", + // 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 = ["_autodetect_all", "UTF-8", "windows-1252"]; + +kPinned.forEach(x => kEncodings.delete(x)); + +function CharsetComparator(a, b) { + // Normal sorting sorts the part in parenthesis in an order that + // happens to make the less frequently-used items first. + let titleA = a.label.replace(/\(.*/, "") + b.value; + let titleB = b.label.replace(/\(.*/, "") + a.value; + // Secondarily reverse sort by encoding name to sort "windows" + return titleA.localeCompare(titleB) || b.value.localeCompare(a.value); +} + +var gCharsetInfoCache, gPinnedInfoCache; + +var CharsetMenu = { + build(parent, deprecatedShowAccessKeys = true) { + if (!deprecatedShowAccessKeys) { + Deprecated.warning( + "CharsetMenu no longer supports building a menu with no access keys.", + "https://bugzilla.mozilla.org/show_bug.cgi?id=1088710" + ); + } + function createDOMNode(doc, nodeInfo) { + let node = doc.createXULElement("menuitem"); + node.setAttribute("type", "radio"); + node.setAttribute("name", nodeInfo.name + "Group"); + node.setAttribute(nodeInfo.name, nodeInfo.value); + node.setAttribute("label", nodeInfo.label); + if (nodeInfo.accesskey) { + node.setAttribute("accesskey", nodeInfo.accesskey); + } + return node; + } + + if (parent.hasChildNodes()) { + // Charset menu already built + return; + } + this._ensureDataReady(); + let doc = parent.ownerDocument; + + gPinnedInfoCache.forEach(charsetInfo => + parent.appendChild(createDOMNode(doc, charsetInfo)) + ); + parent.appendChild(doc.createXULElement("menuseparator")); + gCharsetInfoCache.forEach(charsetInfo => + parent.appendChild(createDOMNode(doc, charsetInfo)) + ); + }, + + getData() { + this._ensureDataReady(); + return { + pinnedCharsets: gPinnedInfoCache, + otherCharsets: gCharsetInfoCache, + }; + }, + + _ensureDataReady() { + if (!gCharsetInfoCache) { + gPinnedInfoCache = this.getCharsetInfo(kPinned, false); + gCharsetInfoCache = this.getCharsetInfo(kEncodings); + } + }, + + getCharsetInfo(charsets, sort = true) { + let list = Array.from(charsets, charset => ({ + label: this._getCharsetLabel(charset), + accesskey: this._getCharsetAccessKey(charset), + name: "charset", + value: charset, + })); + + if (sort) { + list.sort(CharsetComparator); + } + return list; + }, + + _getCharsetLabel(charset) { + if (charset == "GBK") { + // Localization key has been revised + charset = "gbk.bis"; + } + try { + return gBundle.GetStringFromName(charset); + } catch (ex) {} + return charset; + }, + _getCharsetAccessKey(charset) { + if (charset == "GBK") { + // Localization key has been revised + charset = "gbk.bis"; + } + try { + return gBundle.GetStringFromName(charset + ".key"); + } catch (ex) {} + return ""; + }, + + /** + * For substantially similar encodings, treat two encodings as the same + * for the purpose of the check mark. + */ + foldCharset(charset, isAutodetected) { + if (isAutodetected) { + switch (charset) { + case "Shift_JIS": + case "EUC-JP": + case "ISO-2022-JP": + return "Japanese"; + default: + // fall through + } + } + switch (charset) { + case "ISO-8859-8-I": + return "windows-1255"; + + case "gb18030": + return "GBK"; + + default: + return charset; + } + }, + + /** + * This method is for comm-central callers only. + */ + update(parent, charset) { + let menuitem = parent + .getElementsByAttribute("charset", this.foldCharset(charset, false)) + .item(0); + if (menuitem) { + menuitem.setAttribute("checked", "true"); + } + }, +}; + +Object.freeze(CharsetMenu); |