2013-11-26 11:31:52 +04:00
|
|
|
/* 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"];
|
|
|
|
|
2019-01-17 21:18:31 +03:00
|
|
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
|
|
const { XPCOMUtils } = ChromeUtils.import(
|
|
|
|
"resource://gre/modules/XPCOMUtils.jsm"
|
|
|
|
);
|
2013-11-26 11:31:52 +04:00
|
|
|
XPCOMUtils.defineLazyGetter(this, "gBundle", function() {
|
2014-01-06 12:44:19 +04:00
|
|
|
const kUrl = "chrome://global/locale/charsetMenu.properties";
|
2013-11-26 11:31:52 +04:00
|
|
|
return Services.strings.createBundle(kUrl);
|
|
|
|
});
|
2014-01-27 15:56:04 +04:00
|
|
|
|
2018-01-30 08:17:48 +03:00
|
|
|
ChromeUtils.defineModuleGetter(
|
|
|
|
this,
|
|
|
|
"Deprecated",
|
2016-02-24 18:23:35 +03:00
|
|
|
"resource://gre/modules/Deprecated.jsm"
|
|
|
|
);
|
|
|
|
|
2013-11-26 11:31:52 +04:00
|
|
|
/**
|
|
|
|
* This set contains encodings that are in the Encoding Standard, except:
|
2019-04-17 14:36:52 +03:00
|
|
|
* - Japanese encodings are represented by one autodetection item
|
2013-11-26 11:31:52 +04:00
|
|
|
* - x-user-defined, which practically never makes sense as an end-user-chosen
|
|
|
|
* override.
|
2019-04-17 14:36:52 +03:00
|
|
|
* - Encodings that IE11 doesn't have in its corresponding menu.
|
2013-11-26 11:31:52 +04:00
|
|
|
*/
|
|
|
|
const kEncodings = new Set([
|
|
|
|
// Globally relevant
|
2021-01-14 10:06:53 +03:00
|
|
|
"_autodetect_all", // (NOT AN ENCODING NAME; using IE-consistent magic name)
|
2013-11-26 11:31:52 +04:00
|
|
|
"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
|
2017-04-27 13:27:03 +03:00
|
|
|
"GBK",
|
2013-11-26 11:31:52 +04:00
|
|
|
// 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",
|
2019-04-17 14:36:52 +03:00
|
|
|
// Japanese (NOT AN ENCODING NAME)
|
|
|
|
"Japanese",
|
2013-11-26 11:31:52 +04:00
|
|
|
// 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.
|
2021-01-14 10:06:53 +03:00
|
|
|
const kPinned = ["_autodetect_all", "UTF-8", "windows-1252"];
|
2013-11-26 11:31:52 +04:00
|
|
|
|
2014-01-27 15:56:04 +04:00
|
|
|
kPinned.forEach(x => kEncodings.delete(x));
|
|
|
|
|
2014-02-23 22:28:04 +04:00
|
|
|
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;
|
2019-04-17 14:36:52 +03:00
|
|
|
// Secondarily reverse sort by encoding name to sort "windows"
|
2014-02-23 22:28:04 +04:00
|
|
|
return titleA.localeCompare(titleB) || b.value.localeCompare(a.value);
|
|
|
|
}
|
|
|
|
|
2020-06-15 18:32:21 +03:00
|
|
|
var gCharsetInfoCache, gPinnedInfoCache;
|
2014-01-27 15:56:04 +04:00
|
|
|
|
2015-09-15 21:19:45 +03:00
|
|
|
var CharsetMenu = {
|
2020-06-15 18:32:21 +03:00
|
|
|
build(parent, deprecatedShowAccessKeys = true) {
|
2016-02-24 18:23:35 +03:00
|
|
|
if (!deprecatedShowAccessKeys) {
|
|
|
|
Deprecated.warning(
|
|
|
|
"CharsetMenu no longer supports building a menu with no access keys.",
|
|
|
|
"https://bugzilla.mozilla.org/show_bug.cgi?id=1088710"
|
|
|
|
);
|
|
|
|
}
|
2014-01-27 15:56:04 +04:00
|
|
|
function createDOMNode(doc, nodeInfo) {
|
2019-05-20 19:50:28 +03:00
|
|
|
let node = doc.createXULElement("menuitem");
|
2014-01-27 15:56:04 +04:00
|
|
|
node.setAttribute("type", "radio");
|
2014-02-23 22:28:04 +04:00
|
|
|
node.setAttribute("name", nodeInfo.name + "Group");
|
|
|
|
node.setAttribute(nodeInfo.name, nodeInfo.value);
|
2014-01-27 15:56:04 +04:00
|
|
|
node.setAttribute("label", nodeInfo.label);
|
2016-02-24 18:23:35 +03:00
|
|
|
if (nodeInfo.accesskey) {
|
2014-01-27 15:56:04 +04:00
|
|
|
node.setAttribute("accesskey", nodeInfo.accesskey);
|
|
|
|
}
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
2014-02-23 22:28:04 +04:00
|
|
|
if (parent.hasChildNodes()) {
|
2020-06-15 18:32:21 +03:00
|
|
|
// Charset menu already built
|
2013-11-26 11:31:52 +04:00
|
|
|
return;
|
|
|
|
}
|
2014-02-23 22:28:04 +04:00
|
|
|
this._ensureDataReady();
|
2013-11-26 11:31:52 +04:00
|
|
|
let doc = parent.ownerDocument;
|
|
|
|
|
2014-01-27 15:56:04 +04:00
|
|
|
gPinnedInfoCache.forEach(charsetInfo =>
|
|
|
|
parent.appendChild(createDOMNode(doc, charsetInfo))
|
|
|
|
);
|
2019-05-20 19:50:28 +03:00
|
|
|
parent.appendChild(doc.createXULElement("menuseparator"));
|
2014-01-27 15:56:04 +04:00
|
|
|
gCharsetInfoCache.forEach(charsetInfo =>
|
|
|
|
parent.appendChild(createDOMNode(doc, charsetInfo))
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
2016-12-30 02:34:54 +03:00
|
|
|
getData() {
|
2014-01-27 15:56:04 +04:00
|
|
|
this._ensureDataReady();
|
|
|
|
return {
|
|
|
|
pinnedCharsets: gPinnedInfoCache,
|
|
|
|
otherCharsets: gCharsetInfoCache,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2016-12-30 02:34:54 +03:00
|
|
|
_ensureDataReady() {
|
2020-06-15 18:32:21 +03:00
|
|
|
if (!gCharsetInfoCache) {
|
2014-01-27 15:56:04 +04:00
|
|
|
gPinnedInfoCache = this.getCharsetInfo(kPinned, false);
|
2014-02-23 22:28:04 +04:00
|
|
|
gCharsetInfoCache = this.getCharsetInfo(kEncodings);
|
2014-01-27 15:56:04 +04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-12-30 02:34:54 +03:00
|
|
|
getCharsetInfo(charsets, sort = true) {
|
2015-12-03 20:58:56 +03:00
|
|
|
let list = Array.from(charsets, charset => ({
|
2014-01-27 15:56:04 +04:00
|
|
|
label: this._getCharsetLabel(charset),
|
|
|
|
accesskey: this._getCharsetAccessKey(charset),
|
2014-02-23 22:28:04 +04:00
|
|
|
name: "charset",
|
|
|
|
value: charset,
|
2015-12-03 20:58:56 +03:00
|
|
|
}));
|
2014-01-27 15:56:04 +04:00
|
|
|
|
2014-02-23 22:28:04 +04:00
|
|
|
if (sort) {
|
|
|
|
list.sort(CharsetComparator);
|
2013-11-26 11:31:52 +04:00
|
|
|
}
|
2014-01-27 15:56:04 +04:00
|
|
|
return list;
|
|
|
|
},
|
2013-11-26 11:31:52 +04:00
|
|
|
|
2016-12-30 02:34:54 +03:00
|
|
|
_getCharsetLabel(charset) {
|
2017-04-27 13:27:03 +03:00
|
|
|
if (charset == "GBK") {
|
2014-01-30 16:39:25 +04:00
|
|
|
// Localization key has been revised
|
|
|
|
charset = "gbk.bis";
|
|
|
|
}
|
2014-01-27 15:56:04 +04:00
|
|
|
try {
|
|
|
|
return gBundle.GetStringFromName(charset);
|
|
|
|
} catch (ex) {}
|
|
|
|
return charset;
|
|
|
|
},
|
2016-12-30 02:34:54 +03:00
|
|
|
_getCharsetAccessKey(charset) {
|
2017-04-27 13:27:03 +03:00
|
|
|
if (charset == "GBK") {
|
2014-01-30 16:39:25 +04:00
|
|
|
// Localization key has been revised
|
|
|
|
charset = "gbk.bis";
|
|
|
|
}
|
2014-01-27 15:56:04 +04:00
|
|
|
try {
|
2014-01-30 16:34:48 +04:00
|
|
|
return gBundle.GetStringFromName(charset + ".key");
|
2014-01-27 15:56:04 +04:00
|
|
|
} catch (ex) {}
|
|
|
|
return "";
|
|
|
|
},
|
2014-02-23 22:28:04 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* For substantially similar encodings, treat two encodings as the same
|
|
|
|
* for the purpose of the check mark.
|
|
|
|
*/
|
2019-04-17 14:36:52 +03:00
|
|
|
foldCharset(charset, isAutodetected) {
|
|
|
|
if (isAutodetected) {
|
|
|
|
switch (charset) {
|
|
|
|
case "Shift_JIS":
|
|
|
|
case "EUC-JP":
|
|
|
|
case "ISO-2022-JP":
|
|
|
|
return "Japanese";
|
|
|
|
default:
|
|
|
|
// fall through
|
|
|
|
}
|
|
|
|
}
|
2014-02-23 22:28:04 +04:00
|
|
|
switch (charset) {
|
|
|
|
case "ISO-8859-8-I":
|
|
|
|
return "windows-1255";
|
|
|
|
|
|
|
|
case "gb18030":
|
2017-04-27 13:27:03 +03:00
|
|
|
return "GBK";
|
2014-02-23 22:28:04 +04:00
|
|
|
|
|
|
|
default:
|
|
|
|
return charset;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2019-04-17 14:36:52 +03:00
|
|
|
/**
|
|
|
|
* This method is for comm-central callers only.
|
|
|
|
*/
|
2016-12-30 02:34:54 +03:00
|
|
|
update(parent, charset) {
|
2019-04-17 14:36:52 +03:00
|
|
|
let menuitem = parent
|
|
|
|
.getElementsByAttribute("charset", this.foldCharset(charset, false))
|
|
|
|
.item(0);
|
2014-02-23 22:28:04 +04:00
|
|
|
if (menuitem) {
|
|
|
|
menuitem.setAttribute("checked", "true");
|
|
|
|
}
|
|
|
|
},
|
2014-01-27 15:56:04 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
Object.freeze(CharsetMenu);
|