"]}, options);
+ found = true;
+ let value = responseHeader.value.toLowerCase();
+ if(
+ value.startsWith('text') ||
+ value.startsWith('application/javascript') ||
+ value.startsWith('application/x-javascript') ||
+ value.startsWith('application/json')
+ ) {
+ if(charsetPattern.test(value)) {
+ value = value.replace(charsetPattern.exec(value)[1], encoding);
+ } else {
+ value += value.substr(-1) === ';' ? ' ' : '; ';
+ value += `charset=${encoding}`;
+ }
+ responseHeader.value = value;
+ }
+ break;
+ }
+ if (!found) {
+ details.responseHeaders.push({
+ name: 'Content-Type',
+ value: `text/plain; charset=${encoding}`,
+ });
+ }
+ return { responseHeaders: details.responseHeaders };
+};
+
+const bodyModifier = (tabId, changeInfo, tab) => {
+ if (!tab.url.toLowerCase().startsWith('file://')) {
+ return;
+ }
+ if (changeInfo.status.toLowerCase() !== 'complete') {
+ return;
+ }
+ const encoding = encodingList.get(tabId) || defaultEncoding;
+ if (!encoding) {
+ return;
+ }
+ let xmlHttp = new XMLHttpRequest();
+ xmlHttp.overrideMimeType(`text/plain; charset=${encoding}`);
+ xmlHttp.onload = () => {
+ const is_html = /\.html?$/.test(tab.url);
+ const data = is_html ? encodeURIComponent(xmlHttp.responseText) : encodeURIComponent(html_special_chars(xmlHttp.responseText));
+ chrome.tabs.executeScript(tabId, {
+ code: `const _t = document.open('text/${is_html ? 'html' : 'plain'}', 'replace');
+ _t.write(${is_html ? `decodeURIComponent('${data}')` : `'' + decodeURIComponent('${data}') + '
'`});
+ _t.close();`,
+ runAt: 'document_start',
+ });
+ };
+ xmlHttp.onerror = () => alert(chrome.i18n.getMessage('cannotLoadLocalFile'));
+ xmlHttp.open('GET', tab.url, true);
+ xmlHttp.send();
+};
+
+const setEncoding = (tabId, encoding) => {
+ encodingList.set(tabId, encoding);
+ recordRecentlySelectedEncoding(encoding);
+ if (defaultEncoding) {
+ return;
+ }
+ if (listeners.size === 0) {
+ chrome.tabs.onUpdated.addListener(bodyModifier);
+ }
+ if (!listeners.has(tabId)) {
+ const headerModifier = getHeaderModifier();
+ listeners.set(tabId, headerModifier);
+ chrome.webRequest.onHeadersReceived.addListener(headerModifier, { urls: [''], tabId }, options);
+ }
+};
-chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
- if(tab.url.startsWith('file://') && changeInfo.status === 'complete' && localStorage.getItem('tab' + tabId)) {
- let xmlHttp = new XMLHttpRequest();
- xmlHttp.overrideMimeType('text/plain; charset=' + localStorage.getItem('tab' + tabId));
- xmlHttp.onload = () => {
- const is_html = /\.html?$/.test(tab.url);
- const data = is_html ? encodeURI(xmlHttp.responseText) : encodeURI(html_special_chars(xmlHttp.responseText));
- chrome.tabs.executeScript(tabId, {
- code: `const _t = document.open('text/${is_html ? 'html' : 'plain'}', 'replace');
- _t.write(${is_html ? `decodeURI('${data}')` : `'' + decodeURI('${data}') + '
'`});
- _t.close();`,
- runAt: 'document_start'
- });
- };
- xmlHttp.onerror = () => {
- alert(chrome.i18n.getMessage('cannotLoadLocalFile'));
- };
- xmlHttp.open('GET', tab.url, true);
- xmlHttp.send();
+const resetEncoding = tabId => {
+ const callback = listeners.get(tabId);
+ if (callback) {
+ chrome.webRequest.onHeadersReceived.removeListener(callback);
+ listeners.delete(tabId);
+ }
+ encodingList.delete(tabId);
+ if (defaultEncoding) {
+ return;
+ }
+ if (listeners.size === 0) {
+ chrome.tabs.onUpdated.removeListener(bodyModifier);
+ }
+};
+
+const getEncoding = tabId => encodingList.get(tabId) || defaultEncoding;
+
+const setupDefaultEncoding = () => {
+ defaultEncoding = localStorage.getItem('config_enable_default');
+ if (!defaultEncoding) {
+ return;
+ }
+ if (listeners.size === 0) {
+ chrome.tabs.onUpdated.addListener(bodyModifier);
+ }
+ listeners.forEach((callback, tabId) => {
+ chrome.webRequest.onHeadersReceived.removeListener(callback);
+ listeners.delete(tabId);
+ });
+ if (!defaultListener) {
+ defaultListener = getHeaderModifier();
+ }
+ chrome.webRequest.onHeadersReceived.addListener(defaultListener, { urls: [''] }, options);
+};
+
+const unsetDefaultEncoding = () => {
+ defaultEncoding = undefined;
+ chrome.webRequest.onHeadersReceived.removeListener(defaultListener);
+ encodingList.forEach((encoding, tabId) => {
+ if (!listeners.has(tabId)) {
+ const headerModifier = getHeaderModifier();
+ listeners.set(tabId, headerModifier);
+ chrome.webRequest.onHeadersReceived.addListener(headerModifier, { urls: [''], tabId }, options);
}
+ });
+ if (listeners.size === 0) {
+ chrome.tabs.onUpdated.removeListener(bodyModifier);
+ }
+};
+
+chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
+ switch(message.type) {
+ case 'setEncoding': sendResponse(setEncoding(message.tabId, message.encoding)); break;
+ case 'resetEncoding': sendResponse(resetEncoding(message.tabId)); break;
+ case 'getEncoding': sendResponse(getEncoding(message.tabId)); break;
+ case 'createMenu': removeMenu(); sendResponse(createMenu()); break;
+ case 'removeMenu': sendResponse(removeMenu()); break;
+ case 'setupDefaultEncoding': unsetDefaultEncoding(); sendResponse(setupDefaultEncoding()); break;
+ case 'unsetDefaultEncoding': sendResponse(unsetDefaultEncoding()); break;
+ }
});
+
+setupDefaultEncoding();
diff --git a/j/content.js b/j/content.js
deleted file mode 100644
index c1594a9..0000000
--- a/j/content.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * Created by Liming on 2017/2/14.
- */
-"use strict";
-chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
- switch(message.action) {
- case 'GetCharset':
- sendResponse(document.charset || 'Unknown');
- break;
- }
-});
diff --git a/j/encoding.js b/j/encoding.js
index 807d7af..f0baac9 100644
--- a/j/encoding.js
+++ b/j/encoding.js
@@ -1,58 +1,73 @@
/**
* Created by Liming on 2017/3/22.
*/
-"use strict";
+const recentlySelectedEncodingList = (localStorage.getItem('recent') || '').split(',');
+const LocaleDependentStaticEncodingList = (chrome.i18n.getMessage('staticEncodingList') || '').split(',');
//Encoding List
const ENCODINGS = [
- ['UTF-8', 'Unicode'],
- ['GBK', chrome.i18n.getMessage('Chinese')],
- ['GB18030', chrome.i18n.getMessage('Chinese')],
- ['Big5', chrome.i18n.getMessage('Chinese')],
- ['
'],
- ['UTF-16LE', 'Unicode'],
- ['Windows-1256', chrome.i18n.getMessage('Arabic')],
- ['ISO-8859-6', chrome.i18n.getMessage('Arabic')],
- ['ISO-8859-10', chrome.i18n.getMessage('Nordic')],
- ['ISO-8859-4', chrome.i18n.getMessage('Baltic')],
- ['ISO-8859-13', chrome.i18n.getMessage('Baltic')],
- ['Windows-1257', chrome.i18n.getMessage('Baltic')],
- ['EUC-KR', chrome.i18n.getMessage('Korean')],
- ['ISO-8859-14', chrome.i18n.getMessage('Celtic')],
- ['ISO-8859-16', chrome.i18n.getMessage('Romanian')],
- ['ISO-8859-3', chrome.i18n.getMessage('SouthEuropean')],
- ['Shift_JIS', chrome.i18n.getMessage('Japanese')],
- ['EUC-JP', chrome.i18n.getMessage('Japanese')],
- ['ISO-2022-JP', chrome.i18n.getMessage('Japanese')],
- ['Windows-874', chrome.i18n.getMessage('Thai')],
- ['Windows-1254', chrome.i18n.getMessage('Turkish')],
- ['Windows-1255', chrome.i18n.getMessage('Hebrew')],
- ['ISO-8859-8-I', chrome.i18n.getMessage('Hebrew')],
- ['ISO-8859-8', chrome.i18n.getMessage('Hebrew')],
- ['ISO-8859-7', chrome.i18n.getMessage('Greek')],
- ['Windows-1253', chrome.i18n.getMessage('Greek')],
- ['ISO-8859-5', chrome.i18n.getMessage('Cyrillic')],
- ['Windows-1251', chrome.i18n.getMessage('Cyrillic')],
- ['KOI8-R', chrome.i18n.getMessage('Cyrillic')],
- ['KOI8-U', chrome.i18n.getMessage('Cyrillic')],
- ['IBM866', chrome.i18n.getMessage('Cyrillic')],
- ['Windows-1252', chrome.i18n.getMessage('Western')],
- ['ISO-8859-15', chrome.i18n.getMessage('Western')],
- ['Macintosh', chrome.i18n.getMessage('Western')],
- ['Windows-1258', chrome.i18n.getMessage('Vietnamese')],
- ['ISO-8859-2', chrome.i18n.getMessage('CentralEuropean')],
- ['Windows-1250', chrome.i18n.getMessage('CentralEuropean')]
-];
-
-let setEncoding = (tabId, charset, callback) => {
- localStorage.setItem('tab' + tabId, charset);
- chrome.tabs.reload(tabId, {bypassCache: true}, callback);
-};
-
-let resetEncoding = (tabId, callback) => {
- localStorage.removeItem('tab' + tabId);
- chrome.tabs.reload(tabId, {bypassCache: true}, callback);
-};
-
-let getEncoding = (tabId) => {
- return localStorage.getItem('tab' + tabId);
-};
+ ['
'],
+ ['Big5', chrome.i18n.getMessage('encodingChineseTraditional')],
+ ['GBK', chrome.i18n.getMessage('encodingChineseSimplified')],
+ ['GB18030', chrome.i18n.getMessage('encodingChineseSimplified')],
+ ['EUC-JP', chrome.i18n.getMessage('encodingJapanese')],
+ ['EUC-KR', chrome.i18n.getMessage('encodingKorean')],
+ ['IBM866', chrome.i18n.getMessage('encodingCyrillic')],
+ ['ISO-2022-JP', chrome.i18n.getMessage('encodingJapanese')],
+ ['ISO-8859-2', chrome.i18n.getMessage('encodingCentralEuropean')],
+ ['ISO-8859-3', chrome.i18n.getMessage('encodingSouthEuropean')],
+ ['ISO-8859-4', chrome.i18n.getMessage('encodingBaltic')],
+ ['ISO-8859-5', chrome.i18n.getMessage('encodingCyrillic')],
+ ['ISO-8859-6', chrome.i18n.getMessage('encodingArabic')],
+ ['ISO-8859-7', chrome.i18n.getMessage('encodingGreek')],
+ ['ISO-8859-8', chrome.i18n.getMessage('encodingHebrew')],
+ ['ISO-8859-8-I', chrome.i18n.getMessage('encodingHebrew')],
+ ['ISO-8859-10', chrome.i18n.getMessage('encodingNordic')],
+ ['ISO-8859-13', chrome.i18n.getMessage('encodingBaltic')],
+ ['ISO-8859-14', chrome.i18n.getMessage('encodingCeltic')],
+ ['ISO-8859-15', chrome.i18n.getMessage('encodingWestern')],
+ ['ISO-8859-16', chrome.i18n.getMessage('encodingRomanian')],
+ ['KOI8-R', chrome.i18n.getMessage('encodingCyrillic')],
+ ['KOI8-U', chrome.i18n.getMessage('encodingCyrillic')],
+ ['Macintosh', chrome.i18n.getMessage('encodingWestern')],
+ ['Shift_JIS', chrome.i18n.getMessage('encodingJapanese')],
+ ['UTF-8', chrome.i18n.getMessage('encodingUnicode')],
+ ['UTF-16LE', chrome.i18n.getMessage('encodingUnicode')],
+ ['Windows-874', chrome.i18n.getMessage('encodingThai')],
+ ['Windows-1250', chrome.i18n.getMessage('encodingCentralEuropean')],
+ ['Windows-1251', chrome.i18n.getMessage('encodingCyrillic')],
+ ['Windows-1252', chrome.i18n.getMessage('encodingWestern')],
+ ['Windows-1253', chrome.i18n.getMessage('encodingGreek')],
+ ['Windows-1254', chrome.i18n.getMessage('encodingTurkish')],
+ ['Windows-1255', chrome.i18n.getMessage('encodingHebrew')],
+ ['Windows-1256', chrome.i18n.getMessage('encodingArabic')],
+ ['Windows-1257', chrome.i18n.getMessage('encodingBaltic')],
+ ['Windows-1258', chrome.i18n.getMessage('encodingVietnamese')],
+].sort(([a, nameA], [b, nameB]) => {
+ // we always put UTF-8 as top position
+ if (a === 'UTF-8') return -1;
+ if (b === 'UTF-8') return 1;
+ // then put local dependent encoding items
+ {
+ const hasA = LocaleDependentStaticEncodingList.indexOf(a);
+ const hasB = LocaleDependentStaticEncodingList.indexOf(b);
+ if (hasA >= 0 && hasB >= 0) return hasA > hasB ? 1 : -1;
+ if (hasA >= 0) return -1;
+ if (hasB >= 0) return 1;
+ }
+ // then put user recently selected encodings
+ {
+ const hasA = recentlySelectedEncodingList.indexOf(a);
+ const hasB = recentlySelectedEncodingList.indexOf(b);
+ if (hasA >= 0 && hasB >= 0) return hasA > hasB ? 1 : -1;
+ if (hasA >= 0) return -1;
+ if (hasB >= 0) return 1;
+ }
+ // then put a delimiter
+ if (a === '
') return -1;
+ if (b === '
') return 1;
+ // then put UTF-16LE
+ if (a === 'UTF-16LE') return -1;
+ if (b === 'UTF-16LE') return 1;
+ // sort all left encodings by their name
+ return nameA.localeCompare(nameB, chrome.i18n.getUILanguage());
+});
diff --git a/j/menu.js b/j/menu.js
index 951f388..aba8bc8 100644
--- a/j/menu.js
+++ b/j/menu.js
@@ -1,90 +1,77 @@
/**
* Created by Liming on 2017/3/22.
*/
-"use strict";
-(() => {
- let _menu = false;
- const menuList = {};
- //CreateMenu
- const createMenu = () => {
- menuList['default'] = chrome.contextMenus.create({
- type: "radio",
- title: chrome.i18n.getMessage('default'),
- checked: true,
- onclick: (info, tab) => {
- if(!info.wasChecked) {
- resetEncoding(tab.id);
- }
- }
- });
- for(let encoding of ENCODINGS) {
- if(encoding.length === 1) {
- continue;
- }
- menuList[encoding[0].toUpperCase()] = chrome.contextMenus.create({
- type: "radio",
- title: `${encoding[1]}(${encoding[0]})`,
- checked: false,
- onclick: (info, tab) => {
- if(!info.wasChecked) {
- setEncoding(tab.id, encoding[0]);
- }
- }
- });
- }
- _menu = true;
- };
- //UpdateMenu
- const updateMenu = tabId => {
- let charset = getEncoding(tabId);
- charset = charset ? menuList[charset.toUpperCase()] : menuList['default'];
- for(let menu in menuList) {
- chrome.contextMenus.update(menuList[menu], {
- checked: false
- });
- }
- chrome.contextMenus.update(charset, {
- checked: true
- });
- };
- chrome.tabs.onActivated.addListener((activeInfo) => {
- if (!_menu) {
- return;
- }
- updateMenu(activeInfo.tabId);
- });
- chrome.tabs.onUpdated.addListener((tabId) => {
- if (!_menu) {
- return;
- }
- updateMenu(tabId);
- });
- chrome.windows.onFocusChanged.addListener(() => {
- if (!_menu) {
- return;
- }
- chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
- if(tabs.length === 0) {
- return;
- }
- updateMenu(tabs[0].id);
- });
- });
+const rtl = chrome.i18n.getMessage('@@bidi_dir') === 'rtl' ? '\u{200f}' : '';
+const printEncodingInfo = info => `${info[1]} ${rtl}(${info[0]})`;
- chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
- switch(message.action) {
- case 'ShowMenu':
- createMenu();
- break;
- case 'HideMenu':
- _menu = false;
- chrome.contextMenus.removeAll();
- break;
- }
- });
- const config = localStorage.getItem('config_menu');
- if(config === 'false') {
- return;
+let selectedMenu;
+
+const menuClicked = (info, tab) => {
+ if (info.wasChecked) {
+ return;
+ }
+ if (info.menuItemId === 'default') {
+ resetEncoding(tab.id);
+ } else {
+ setEncoding(tab.id, info.menuItemId);
+ }
+ chrome.tabs.reload(tab.id, { bypassCache: true });
+};
+
+const updateMenu = tabId => {
+ const encoding = getEncoding(tabId) || 'default';
+ if (selectedMenu === encoding) {
+ return;
+ }
+ chrome.contextMenus.update(selectedMenu, { checked: false });
+ chrome.contextMenus.update(encoding, { checked: true });
+ selectedMenu = encoding;
+};
+
+const tabUpdatedEvent = tabId => updateMenu(tabId);
+const tabActivatedEvent = activeInfo => updateMenu(activeInfo.tabId);
+const windowsFocusedEvent = () => {
+ chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
+ if (tabs.length === 0) {
+ return;
+ }
+ updateMenu(tabs[0].id);
+ });
+};
+
+const createMenu = () => {
+ chrome.contextMenus.create({
+ type: 'radio',
+ id: 'default',
+ title: chrome.i18n.getMessage('default'),
+ checked: true,
+ onclick: menuClicked,
+ });
+ selectedMenu = 'default';
+ for (const encoding of ENCODINGS) {
+ if (encoding.length === 1) {
+ continue;
}
- createMenu();
-})();
+ chrome.contextMenus.create({
+ type: 'radio',
+ id: encoding[0],
+ title: printEncodingInfo(encoding),
+ checked: false,
+ onclick: menuClicked,
+ });
+ }
+ chrome.tabs.onUpdated.addListener(tabUpdatedEvent);
+ chrome.tabs.onActivated.addListener(tabActivatedEvent);
+ chrome.windows.onFocusChanged.addListener(windowsFocusedEvent);
+};
+
+const removeMenu = () => {
+ chrome.contextMenus.removeAll();
+ chrome.tabs.onUpdated.removeListener(tabUpdatedEvent);
+ chrome.tabs.onActivated.removeListener(tabActivatedEvent);
+ chrome.windows.onFocusChanged.removeListener(windowsFocusedEvent);
+};
+
+if (localStorage.getItem('config_menu') === 'true') {
+ createMenu();
+}
diff --git a/j/option.js b/j/option.js
new file mode 100644
index 0000000..1ddfce6
--- /dev/null
+++ b/j/option.js
@@ -0,0 +1,72 @@
+/**
+ * Created by Liming on 2019/3/2.
+ */
+const rtl = chrome.i18n.getMessage('@@bidi_dir') === 'rtl' ? '' : '';
+const printEncodingInfo = info => `${info[1]} ${rtl}(${info[0]})`;
+
+// I18n
+document.getElementById('menu').innerHTML = chrome.i18n.getMessage('optionMenu');
+document.getElementById('default-encoding').innerHTML = chrome.i18n.getMessage('optionDefaultEncoding');
+// Initialize encoding list
+const list = document.getElementById('default-encoding-list');
+let option = document.createElement('option');
+option.value = '';
+option.innerHTML = chrome.i18n.getMessage('default');
+list.appendChild(option);
+const optgroup = [
+ document.createElement('optgroup'),
+ document.createElement('optgroup'),
+];
+optgroup[0].label = chrome.i18n.getMessage('optionRecommendEncoding');
+optgroup[1].label = chrome.i18n.getMessage('optionOtherEncoding');
+let index = 0;
+for (const encodingInfo of ENCODINGS) {
+ if (encodingInfo.length === 1) {
+ ++index;
+ continue;
+ }
+ option = document.createElement('option');
+ option.value = encodingInfo[0];
+ option.innerHTML = printEncodingInfo(encodingInfo);
+ optgroup[index].appendChild(option);
+}
+optgroup.forEach(o => list.appendChild(o));
+// Current Setting
+const contextMenuButton = document.getElementById('context-menu');
+if (contextMenuButton instanceof HTMLInputElement) {
+ contextMenuButton.checked = (localStorage.getItem('config_menu') === 'true');
+}
+if (list instanceof HTMLSelectElement) {
+ list.value = localStorage.getItem('config_enable_default') || '';
+}
+// Fix RTL mode display
+if (rtl) {
+ list.style.backgroundPosition = '8px';
+}
+// Change Events
+document.body.addEventListener('change', e => {
+ if (e.target instanceof HTMLInputElement) {
+ if (e.target.id === 'context-menu') {
+ if (e.target.checked) {
+ localStorage.setItem('config_menu', 'true');
+ chrome.runtime.sendMessage({ type: 'createMenu' });
+ } else {
+ localStorage.removeItem('config_menu');
+ chrome.runtime.sendMessage({ type: 'removeMenu' });
+ }
+ return;
+ }
+ }
+ if (e.target instanceof HTMLSelectElement) {
+ if (e.target.id === 'default-encoding-list') {
+ if (e.target.value) {
+ localStorage.setItem('config_enable_default', e.target.value);
+ chrome.runtime.sendMessage({ type: 'setupDefaultEncoding' });
+ } else {
+ localStorage.removeItem('config_enable_default');
+ chrome.runtime.sendMessage({ type: 'unsetDefaultEncoding' });
+ }
+ return;
+ }
+ }
+});
diff --git a/j/popup.js b/j/popup.js
index 6cf986b..fe00643 100644
--- a/j/popup.js
+++ b/j/popup.js
@@ -1,72 +1,121 @@
/**
* Created by Liming on 2017/2/14.
*/
-"use strict";
-(() => {
- chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
- if(tabs.length === 0) {
- return;
- }
- //Current Charset
- if(tabs[0].url.startsWith('file://') && localStorage.getItem('tab' + tabs[0].id)) {
- let charset = localStorage.getItem('tab' + tabs[0].id);
- for(let encoding of ENCODINGS) {
- if(encoding[0].toUpperCase() === charset.toUpperCase()) {
- charset += `(${encoding[1]})`;
- break;
- }
- }
- document.getElementById('current').innerHTML = charset;
- } else {
- chrome.tabs.sendMessage(tabs[0].id, {action: 'GetCharset'}, (response) => {
- response = response || 'Unknown';
- if(response !== 'Unknown') {
- for(let encoding of ENCODINGS) {
- if(encoding[0].toUpperCase() === response.toUpperCase()) {
- response += `(${encoding[1]})`;
- break;
- }
- }
- }
- document.getElementById('current').innerHTML = response;
- });
- }
- //I18N
- document.getElementById('reset').innerHTML = chrome.i18n.getMessage('btnReset');
- document.getElementById('tip_current').innerHTML = chrome.i18n.getMessage('tipCurrent');
- document.getElementById('context_menu').innerHTML = chrome.i18n.getMessage('settingMenu');
- //Reset
- document.getElementById('reset').addEventListener('click', () => {
- resetEncoding(tabs[0].id, () => {
- window.close();
- });
- });
- //Make List
- let list = document.getElementById('list');
- for(let encoding of ENCODINGS) {
- if(encoding.length === 1) {
- list.appendChild(document.createElement('hr'));
- continue;
- }
- let button = document.createElement('button');
- button.type = 'button';
- button.dataset.charset = encoding[0];
- button.innerHTML = `${encoding[1]}(${encoding[0]})`;
- button.addEventListener('click', (e) => {
- setEncoding(tabs[0].id, e.target.dataset.charset, () => {
- window.close();
- });
- });
- list.appendChild(button);
- }
- //Settings
- const setting_Menu = document.getElementById('menu');
- setting_Menu.checked = localStorage.getItem('config_menu') !== 'false';
- setting_Menu.addEventListener('change', _ => {
- localStorage.setItem('config_menu', setting_Menu.checked);
- chrome.runtime.sendMessage({
- action: setting_Menu.checked ? 'ShowMenu' : 'HideMenu'
- });
- });
+const rtl = chrome.i18n.getMessage('@@bidi_dir') === 'rtl' ? '' : '';
+const printEncodingInfo = info => `${info[1]} ${rtl}(${info[0]})`;
+
+const distance = (x1, y1, x2, y2) => {
+ var xDelta = x1 - x2;
+ var yDelta = y1 - y2;
+ return Math.sqrt(xDelta * xDelta + yDelta * yDelta);
+};
+
+chrome.tabs.query({ active: true, currentWindow: true }, async tabs => {
+ if (tabs.length === 0) {
+ return;
+ }
+ // Detect current encoding
+ const currentDOM = document.getElementById('current');
+ currentDOM.innerHTML = '......';
+ const fileEncoding = tabs[0].url.startsWith('file://') &&
+ await new Promise(resolve => chrome.runtime.sendMessage({ type: 'getEncoding', tabId: tabs[0].id }, resolve));
+ if (fileEncoding) {
+ const encodingInfo = ENCODINGS.find(e => e[0].toUpperCase() === fileEncoding.toUpperCase());
+ currentDOM.innerHTML = encodingInfo ? printEncodingInfo(encodingInfo) : chrome.i18n.getMessage('unknown');
+ } else {
+ chrome.tabs.executeScript(tabs[0].id, { code: 'document.charset' }, results => {
+ if (!results || !results[0]) {
+ currentDOM.innerHTML = chrome.i18n.getMessage('unknown');
+ return chrome.runtime.lastError;
+ }
+ const encodingInfo = ENCODINGS.find(e => e[0].toUpperCase() === String(results[0]).toUpperCase());
+ currentDOM.innerHTML = printEncodingInfo(encodingInfo || [results[0], chrome.i18n.getMessage('unknown')]);
});
-})();
+ }
+ // I18n
+ document.getElementById('reset').innerHTML = chrome.i18n.getMessage('btnReset');
+ document.getElementById('tip-current').innerHTML = chrome.i18n.getMessage('tipCurrent');
+ // Setted default encoding
+ const defaultEncoding = localStorage.getItem('config_enable_default');
+ if (defaultEncoding) {
+ const encodingInfo = ENCODINGS.find(e => e[0].toUpperCase() === defaultEncoding.toUpperCase());
+ const defaultTip = document.getElementById('default-tip');
+ defaultTip.innerHTML = chrome.i18n.getMessage('defaultEncodingEnabled', [printEncodingInfo(encodingInfo)]);
+ defaultTip.title = chrome.i18n.getMessage('tipDisableDefaultEncoding');
+ defaultTip.addEventListener('click', () => chrome.runtime.openOptionsPage());
+ }
+ // Reset button
+ document.getElementById('reset').addEventListener('click', () => {
+ chrome.runtime.sendMessage({ type: 'resetEncoding', tabId: tabs[0].id }, () => {
+ chrome.tabs.reload(tabs[0].id, { bypassCache: true }, () => window.close());
+ });
+ });
+ // Initialize encoding list
+ const list = document.getElementById('list');
+ list.addEventListener('click', e => {
+ if(!(e.target instanceof HTMLButtonElement && e.target.dataset.encoding)) {
+ return;
+ }
+ chrome.runtime.sendMessage({ type: 'setEncoding', tabId: tabs[0].id, encoding: e.target.dataset.encoding }, () => {
+ chrome.tabs.reload(tabs[0].id, { bypassCache: true }, () => window.close());
+ });
+ });
+ for (const encodingInfo of ENCODINGS) {
+ if (encodingInfo.length === 1) {
+ list.appendChild(document.createElement('hr'));
+ continue;
+ }
+ const button = document.createElement('button');
+ button.type = 'button';
+ button.dataset.encoding = encodingInfo[0];
+ button.innerHTML = printEncodingInfo(encodingInfo);
+ list.appendChild(button);
+ }
+ // Ripple animate event
+ let inks = [];
+ const removeInks = () => {
+ for (const ink of inks) {
+ if (ink.parentElement) {
+ ink.parentElement.removeChild(ink);
+ }
+ }
+ inks = [];
+ };
+ document.body.addEventListener('mousedown', e => {
+ removeInks();
+ if (!(e && e.target instanceof HTMLButtonElement)) {
+ return;
+ }
+ const rect = e.target.getBoundingClientRect();
+ const x = Math.round(e.clientX - rect.left);
+ const y = Math.round(e.clientY - rect.top);
+ const cornerDistances = [
+ { x: 0, y: 0 },
+ { x: rect.width, y: 0 },
+ { x: 0, y: rect.height },
+ { x: rect.width, y: rect.height },
+ ].map(corner => Math.round(distance(x, y, corner.x, corner.y)));
+ const radius = Math.max(...cornerDistances);
+ const startTranslate = `${x - radius}px, ${y - radius}px`;
+ const ripple = document.createElement('div');
+ ripple.classList.add('ripple');
+ ripple.style.height = ripple.style.width = `${2 * radius}px`;
+ const ink = document.createElement('div');
+ ink.classList.add('ink');
+ ink.appendChild(ripple);
+ e.target.appendChild(ink);
+ const duration = Math.max(800, Math.log(radius) * radius);
+ ripple.animate({
+ transform: [
+ `translate(${startTranslate}) scale(0)`,
+ `translate(${startTranslate}) scale(1)`,
+ ],
+ }, {
+ duration,
+ easing: 'cubic-bezier(.2, .9, .1, .9)',
+ fill: 'forwards',
+ });
+ inks.push(ink);
+ });
+ document.body.addEventListener('mouseup', removeInks);
+});
diff --git a/manifest.json b/manifest.json
index 9fe46b6..f646da5 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,49 +1,49 @@
{
- "manifest_version": 2,
- "name": "__MSG_appName__",
- "version": "0.4.3",
- "default_locale": "en",
- "description": "__MSG_appDescription__",
- "icons": {
- "128": "i/128.png",
- "64": "i/64.png",
- "38": "i/38.png",
- "32": "i/32.png",
- "19": "i/19.png",
- "16": "i/16.png"
+ "manifest_version": 2,
+ "name": "__MSG_appName__",
+ "version": "0.5.0",
+ "default_locale": "en",
+ "description": "__MSG_appDescription__",
+ "icons": {
+ "128": "i/128.png",
+ "64": "i/64.png",
+ "38": "i/38.png",
+ "32": "i/32.png",
+ "19": "i/19.png",
+ "16": "i/16.png"
+ },
+ "browser_action": {
+ "default_icon": {
+ "38": "i/38.png",
+ "19": "i/19.png"
},
- "browser_action": {
- "default_icon": {
- "38": "i/38.png",
- "19": "i/19.png"
- },
- "default_title": "__MSG_appName__",
- "default_popup": "popup.html"
- },
- "author": "Liming Jin, jinliming2@gmail.com",
- "background": {
- "scripts": [
- "j/background.js",
- "j/encoding.js",
- "j/menu.js"
- ]
- },
- "content_scripts": [
- {
- "matches": [""],
- "js": ["j/content.js"],
- "run_at": "document_start"
- }
- ],
- "homepage_url": "https://github.com/jinliming2/Chrome-Charset",
- "incognito": "split",
- "minimum_chrome_version": "55",
- "permissions": [
- "",
- "webRequest",
- "webRequestBlocking",
- "contextMenus",
- "tabs"
+ "default_title": "__MSG_appName__",
+ "default_popup": "popup.html"
+ },
+ "author": "Liming Jin, jinliming2@gmail.com",
+ "background": {
+ "scripts": [
+ "j/encoding.js",
+ "j/background.js",
+ "j/menu.js"
],
- "short_name": "__MSG_appShortName__"
+ "persistent": true
+ },
+ "homepage_url": "https://github.com/jinliming2/Chrome-Charset",
+ "incognito": "split",
+ "minimum_chrome_version": "55.0.2872.0",
+ "offline_enabled": true,
+ "options_ui": {
+ "chrome_style": false,
+ "page": "option.html",
+ "open_in_tab": false
+ },
+ "permissions": [
+ "",
+ "webRequest",
+ "webRequestBlocking",
+ "contextMenus",
+ "tabs"
+ ],
+ "short_name": "__MSG_appShortName__"
}
diff --git a/option.html b/option.html
new file mode 100644
index 0000000..3924413
--- /dev/null
+++ b/option.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/popup.html b/popup.html
index 44947c4..139e18b 100644
--- a/popup.html
+++ b/popup.html
@@ -1,27 +1,21 @@
-
+
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+