Merge pull request #160 from toasted-nutbread/mobile
Add support for mobile Firefox
This commit is contained in:
commit
61d1168d94
@ -2,6 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="/mixed/lib/dexie.min.js"></script>
|
<script src="/mixed/lib/dexie.min.js"></script>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap.min.css">
|
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css">
|
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap-toggle/bootstrap-toggle.min.css">
|
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap-toggle/bootstrap-toggle.min.css">
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<title>Welcome to Yomichan!</title>
|
<title>Welcome to Yomichan!</title>
|
||||||
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap.min.css">
|
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css">
|
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css">
|
||||||
|
@ -28,7 +28,9 @@ class Backend {
|
|||||||
await this.translator.prepare();
|
await this.translator.prepare();
|
||||||
await apiOptionsSet(await optionsLoad());
|
await apiOptionsSet(await optionsLoad());
|
||||||
|
|
||||||
|
if (chrome.commands !== null && typeof chrome.commands === 'object') {
|
||||||
chrome.commands.onCommand.addListener(this.onCommand.bind(this));
|
chrome.commands.onCommand.addListener(this.onCommand.bind(this));
|
||||||
|
}
|
||||||
chrome.runtime.onMessage.addListener(this.onMessage.bind(this));
|
chrome.runtime.onMessage.addListener(this.onMessage.bind(this));
|
||||||
|
|
||||||
if (this.options.general.showGuide) {
|
if (this.options.general.showGuide) {
|
||||||
@ -40,13 +42,13 @@ class Backend {
|
|||||||
this.options = utilIsolate(options);
|
this.options = utilIsolate(options);
|
||||||
|
|
||||||
if (!options.general.enable) {
|
if (!options.general.enable) {
|
||||||
chrome.browserAction.setBadgeBackgroundColor({color: '#555555'});
|
this.setExtensionBadgeBackgroundColor('#555555');
|
||||||
chrome.browserAction.setBadgeText({text: 'off'});
|
this.setExtensionBadgeText('off');
|
||||||
} else if (!dictConfigured(options)) {
|
} else if (!dictConfigured(options)) {
|
||||||
chrome.browserAction.setBadgeBackgroundColor({color: '#f0ad4e'});
|
this.setExtensionBadgeBackgroundColor('#f0ad4e');
|
||||||
chrome.browserAction.setBadgeText({text: '!'});
|
this.setExtensionBadgeText('!');
|
||||||
} else {
|
} else {
|
||||||
chrome.browserAction.setBadgeText({text: ''});
|
this.setExtensionBadgeText('');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.anki.enable) {
|
if (options.anki.enable) {
|
||||||
@ -125,6 +127,18 @@ class Backend {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setExtensionBadgeBackgroundColor(color) {
|
||||||
|
if (typeof chrome.browserAction.setBadgeBackgroundColor === 'function') {
|
||||||
|
chrome.browserAction.setBadgeBackgroundColor({color});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setExtensionBadgeText(text) {
|
||||||
|
if (typeof chrome.browserAction.setBadgeText === 'function') {
|
||||||
|
chrome.browserAction.setBadgeText({text});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.yomichan_backend = new Backend();
|
window.yomichan_backend = new Backend();
|
||||||
|
@ -228,11 +228,47 @@ class Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async importDictionary(archive, callback) {
|
async importDictionary(archive, progressCallback, exceptions) {
|
||||||
if (!this.db) {
|
if (!this.db) {
|
||||||
throw 'Database not initialized';
|
throw 'Database not initialized';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const maxTransactionLength = 1000;
|
||||||
|
const bulkAdd = async (table, items, total, current) => {
|
||||||
|
if (items.length < maxTransactionLength) {
|
||||||
|
if (progressCallback) {
|
||||||
|
progressCallback(total, current);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await table.bulkAdd(items);
|
||||||
|
} catch (e) {
|
||||||
|
if (exceptions) {
|
||||||
|
exceptions.push(e);
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < items.length; i += maxTransactionLength) {
|
||||||
|
if (progressCallback) {
|
||||||
|
progressCallback(total, current + i / items.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
let count = Math.min(maxTransactionLength, items.length - i);
|
||||||
|
try {
|
||||||
|
await table.bulkAdd(items.slice(i, i + count));
|
||||||
|
} catch (e) {
|
||||||
|
if (exceptions) {
|
||||||
|
exceptions.push(e);
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const indexDataLoaded = async summary => {
|
const indexDataLoaded = async summary => {
|
||||||
if (summary.version > 3) {
|
if (summary.version > 3) {
|
||||||
throw 'Unsupported dictionary version';
|
throw 'Unsupported dictionary version';
|
||||||
@ -247,10 +283,6 @@ class Database {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const termDataLoaded = async (summary, entries, total, current) => {
|
const termDataLoaded = async (summary, entries, total, current) => {
|
||||||
if (callback) {
|
|
||||||
callback(total, current);
|
|
||||||
}
|
|
||||||
|
|
||||||
const rows = [];
|
const rows = [];
|
||||||
if (summary.version === 1) {
|
if (summary.version === 1) {
|
||||||
for (const [expression, reading, definitionTags, rules, score, ...glossary] of entries) {
|
for (const [expression, reading, definitionTags, rules, score, ...glossary] of entries) {
|
||||||
@ -280,14 +312,10 @@ class Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.db.terms.bulkAdd(rows);
|
await bulkAdd(this.db.terms, rows, total, current);
|
||||||
};
|
};
|
||||||
|
|
||||||
const termMetaDataLoaded = async (summary, entries, total, current) => {
|
const termMetaDataLoaded = async (summary, entries, total, current) => {
|
||||||
if (callback) {
|
|
||||||
callback(total, current);
|
|
||||||
}
|
|
||||||
|
|
||||||
const rows = [];
|
const rows = [];
|
||||||
for (const [expression, mode, data] of entries) {
|
for (const [expression, mode, data] of entries) {
|
||||||
rows.push({
|
rows.push({
|
||||||
@ -298,14 +326,10 @@ class Database {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.db.termMeta.bulkAdd(rows);
|
await bulkAdd(this.db.termMeta, rows, total, current);
|
||||||
};
|
};
|
||||||
|
|
||||||
const kanjiDataLoaded = async (summary, entries, total, current) => {
|
const kanjiDataLoaded = async (summary, entries, total, current) => {
|
||||||
if (callback) {
|
|
||||||
callback(total, current);
|
|
||||||
}
|
|
||||||
|
|
||||||
const rows = [];
|
const rows = [];
|
||||||
if (summary.version === 1) {
|
if (summary.version === 1) {
|
||||||
for (const [character, onyomi, kunyomi, tags, ...meanings] of entries) {
|
for (const [character, onyomi, kunyomi, tags, ...meanings] of entries) {
|
||||||
@ -332,14 +356,10 @@ class Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.db.kanji.bulkAdd(rows);
|
await bulkAdd(this.db.kanji, rows, total, current);
|
||||||
};
|
};
|
||||||
|
|
||||||
const kanjiMetaDataLoaded = async (summary, entries, total, current) => {
|
const kanjiMetaDataLoaded = async (summary, entries, total, current) => {
|
||||||
if (callback) {
|
|
||||||
callback(total, current);
|
|
||||||
}
|
|
||||||
|
|
||||||
const rows = [];
|
const rows = [];
|
||||||
for (const [character, mode, data] of entries) {
|
for (const [character, mode, data] of entries) {
|
||||||
rows.push({
|
rows.push({
|
||||||
@ -350,14 +370,10 @@ class Database {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.db.kanjiMeta.bulkAdd(rows);
|
await bulkAdd(this.db.kanjiMeta, rows, total, current);
|
||||||
};
|
};
|
||||||
|
|
||||||
const tagDataLoaded = async (summary, entries, total, current) => {
|
const tagDataLoaded = async (summary, entries, total, current) => {
|
||||||
if (callback) {
|
|
||||||
callback(total, current);
|
|
||||||
}
|
|
||||||
|
|
||||||
const rows = [];
|
const rows = [];
|
||||||
for (const [name, category, order, notes, score] of entries) {
|
for (const [name, category, order, notes, score] of entries) {
|
||||||
const row = dictTagSanitize({
|
const row = dictTagSanitize({
|
||||||
@ -372,7 +388,7 @@ class Database {
|
|||||||
rows.push(row);
|
rows.push(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.db.tagMeta.bulkAdd(rows);
|
await bulkAdd(this.db.tagMeta, rows, total, current);
|
||||||
};
|
};
|
||||||
|
|
||||||
return await Database.importDictionaryZip(
|
return await Database.importDictionaryZip(
|
||||||
|
@ -193,7 +193,7 @@ async function onReady() {
|
|||||||
await dictionaryGroupsPopulate(options);
|
await dictionaryGroupsPopulate(options);
|
||||||
await formMainDictionaryOptionsPopulate(options);
|
await formMainDictionaryOptionsPopulate(options);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dictionaryErrorShow(e);
|
dictionaryErrorsShow([e]);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -203,6 +203,8 @@ async function onReady() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
formUpdateVisibility(options);
|
formUpdateVisibility(options);
|
||||||
|
|
||||||
|
storageInfoInitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(utilAsync(onReady));
|
$(document).ready(utilAsync(onReady));
|
||||||
@ -212,10 +214,23 @@ $(document).ready(utilAsync(onReady));
|
|||||||
* Dictionary
|
* Dictionary
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function dictionaryErrorShow(error) {
|
function dictionaryErrorToString(error) {
|
||||||
const dialog = $('#dict-error');
|
if (error.toString) {
|
||||||
if (error) {
|
error = error.toString();
|
||||||
const overrides = [
|
} else {
|
||||||
|
error = `${error}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [match, subst] of dictionaryErrorToString.overrides) {
|
||||||
|
if (error.includes(match)) {
|
||||||
|
error = subst;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
dictionaryErrorToString.overrides = [
|
||||||
[
|
[
|
||||||
'A mutation operation was attempted on a database that did not allow mutations.',
|
'A mutation operation was attempted on a database that did not allow mutations.',
|
||||||
'Access to IndexedDB appears to be restricted. Firefox seems to require that the history preference is set to "Remember history" before IndexedDB use of any kind is allowed.'
|
'Access to IndexedDB appears to be restricted. Firefox seems to require that the history preference is set to "Remember history" before IndexedDB use of any kind is allowed.'
|
||||||
@ -230,18 +245,32 @@ function dictionaryErrorShow(error) {
|
|||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
if (error.toString) {
|
function dictionaryErrorsShow(errors) {
|
||||||
error = error.toString();
|
const dialog = $('#dict-error');
|
||||||
|
dialog.show().text('');
|
||||||
|
|
||||||
|
if (errors !== null && errors.length > 0) {
|
||||||
|
const uniqueErrors = {};
|
||||||
|
for (let e of errors) {
|
||||||
|
e = dictionaryErrorToString(e);
|
||||||
|
uniqueErrors[e] = uniqueErrors.hasOwnProperty(e) ? uniqueErrors[e] + 1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [match, subst] of overrides) {
|
for (const e in uniqueErrors) {
|
||||||
if (error.includes(match)) {
|
const count = uniqueErrors[e];
|
||||||
error = subst;
|
const div = document.createElement('p');
|
||||||
break;
|
if (count > 1) {
|
||||||
|
div.textContent = `${e} `;
|
||||||
|
const em = document.createElement('em');
|
||||||
|
em.textContent = `(${count})`;
|
||||||
|
div.appendChild(em);
|
||||||
|
} else {
|
||||||
|
div.textContent = `${e}`;
|
||||||
}
|
}
|
||||||
|
dialog.append($(div));
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.show().text(error);
|
dialog.show();
|
||||||
} else {
|
} else {
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
}
|
}
|
||||||
@ -317,7 +346,7 @@ async function onDictionaryPurge(e) {
|
|||||||
const dictProgress = $('#dict-purge').show();
|
const dictProgress = $('#dict-purge').show();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dictionaryErrorShow();
|
dictionaryErrorsShow(null);
|
||||||
dictionarySpinnerShow(true);
|
dictionarySpinnerShow(true);
|
||||||
|
|
||||||
await utilDatabasePurge();
|
await utilDatabasePurge();
|
||||||
@ -329,12 +358,16 @@ async function onDictionaryPurge(e) {
|
|||||||
await dictionaryGroupsPopulate(options);
|
await dictionaryGroupsPopulate(options);
|
||||||
await formMainDictionaryOptionsPopulate(options);
|
await formMainDictionaryOptionsPopulate(options);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dictionaryErrorShow(e);
|
dictionaryErrorsShow([e]);
|
||||||
} finally {
|
} finally {
|
||||||
dictionarySpinnerShow(false);
|
dictionarySpinnerShow(false);
|
||||||
|
|
||||||
dictControls.show();
|
dictControls.show();
|
||||||
dictProgress.hide();
|
dictProgress.hide();
|
||||||
|
|
||||||
|
if (storageEstimate.mostRecent !== null) {
|
||||||
|
storageUpdateStats();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,25 +377,37 @@ async function onDictionaryImport(e) {
|
|||||||
const dictProgress = $('#dict-import-progress').show();
|
const dictProgress = $('#dict-import-progress').show();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dictionaryErrorShow();
|
dictionaryErrorsShow(null);
|
||||||
dictionarySpinnerShow(true);
|
dictionarySpinnerShow(true);
|
||||||
|
|
||||||
const setProgress = percent => dictProgress.find('.progress-bar').css('width', `${percent}%`);
|
const setProgress = percent => dictProgress.find('.progress-bar').css('width', `${percent}%`);
|
||||||
const updateProgress = (total, current) => setProgress(current / total * 100.0);
|
const updateProgress = (total, current) => {
|
||||||
|
setProgress(current / total * 100.0);
|
||||||
|
if (storageEstimate.mostRecent !== null && !storageUpdateStats.isUpdating) {
|
||||||
|
storageUpdateStats();
|
||||||
|
}
|
||||||
|
};
|
||||||
setProgress(0.0);
|
setProgress(0.0);
|
||||||
|
|
||||||
|
const exceptions = [];
|
||||||
const options = await optionsLoad();
|
const options = await optionsLoad();
|
||||||
const summary = await utilDatabaseImport(e.target.files[0], updateProgress);
|
const summary = await utilDatabaseImport(e.target.files[0], updateProgress, exceptions);
|
||||||
options.dictionaries[summary.title] = {enabled: true, priority: 0, allowSecondarySearches: false};
|
options.dictionaries[summary.title] = {enabled: true, priority: 0, allowSecondarySearches: false};
|
||||||
if (summary.sequenced && options.general.mainDictionary === '') {
|
if (summary.sequenced && options.general.mainDictionary === '') {
|
||||||
options.general.mainDictionary = summary.title;
|
options.general.mainDictionary = summary.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (exceptions.length > 0) {
|
||||||
|
exceptions.push(`Dictionary may not have been imported properly: ${exceptions.length} error${exceptions.length === 1 ? '' : 's'} reported.`);
|
||||||
|
dictionaryErrorsShow(exceptions);
|
||||||
|
}
|
||||||
|
|
||||||
await optionsSave(options);
|
await optionsSave(options);
|
||||||
|
|
||||||
await dictionaryGroupsPopulate(options);
|
await dictionaryGroupsPopulate(options);
|
||||||
await formMainDictionaryOptionsPopulate(options);
|
await formMainDictionaryOptionsPopulate(options);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dictionaryErrorShow(e);
|
dictionaryErrorsShow([e]);
|
||||||
} finally {
|
} finally {
|
||||||
dictionarySpinnerShow(false);
|
dictionarySpinnerShow(false);
|
||||||
|
|
||||||
@ -520,3 +565,93 @@ async function onAnkiFieldTemplatesReset(e) {
|
|||||||
ankiErrorShow(e);
|
ankiErrorShow(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Storage
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function getBrowser() {
|
||||||
|
if (typeof chrome !== "undefined") {
|
||||||
|
if (typeof browser !== "undefined") {
|
||||||
|
try {
|
||||||
|
const info = await browser.runtime.getBrowserInfo();
|
||||||
|
if (info.name === "Fennec") {
|
||||||
|
return "firefox-mobile";
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
return "firefox";
|
||||||
|
} else {
|
||||||
|
return "chrome";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "edge";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function storageBytesToLabeledString(size) {
|
||||||
|
const base = 1000;
|
||||||
|
const labels = ["bytes", "KB", "MB", "GB"];
|
||||||
|
let labelIndex = 0;
|
||||||
|
while (size >= base) {
|
||||||
|
size /= base;
|
||||||
|
++labelIndex;
|
||||||
|
}
|
||||||
|
const label = size.toFixed(1);
|
||||||
|
return `${label}${labels[labelIndex]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function storageEstimate() {
|
||||||
|
try {
|
||||||
|
return (storageEstimate.mostRecent = await navigator.storage.estimate());
|
||||||
|
} catch (e) { }
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
storageEstimate.mostRecent = null;
|
||||||
|
|
||||||
|
async function storageInfoInitialize() {
|
||||||
|
const browser = await getBrowser();
|
||||||
|
const container = document.querySelector("#storage-info");
|
||||||
|
container.setAttribute("data-browser", browser);
|
||||||
|
|
||||||
|
await storageShowInfo();
|
||||||
|
|
||||||
|
container.classList.remove("storage-hidden");
|
||||||
|
|
||||||
|
document.querySelector("#storage-refresh").addEventListener('click', () => storageShowInfo(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function storageUpdateStats() {
|
||||||
|
storageUpdateStats.isUpdating = true;
|
||||||
|
|
||||||
|
const estimate = await storageEstimate();
|
||||||
|
const valid = (estimate !== null);
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
document.querySelector("#storage-usage").textContent = storageBytesToLabeledString(estimate.usage);
|
||||||
|
document.querySelector("#storage-quota").textContent = storageBytesToLabeledString(estimate.quota);
|
||||||
|
}
|
||||||
|
|
||||||
|
storageUpdateStats.isUpdating = false;
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
storageUpdateStats.isUpdating = false;
|
||||||
|
|
||||||
|
async function storageShowInfo() {
|
||||||
|
storageSpinnerShow(true);
|
||||||
|
|
||||||
|
const valid = await storageUpdateStats();
|
||||||
|
document.querySelector("#storage-use").classList.toggle("storage-hidden", !valid);
|
||||||
|
document.querySelector("#storage-error").classList.toggle("storage-hidden", valid);
|
||||||
|
|
||||||
|
storageSpinnerShow(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function storageSpinnerShow(show) {
|
||||||
|
const spinner = $('#storage-spinner');
|
||||||
|
if (show) {
|
||||||
|
spinner.show();
|
||||||
|
} else {
|
||||||
|
spinner.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -87,6 +87,6 @@ function utilDatabasePurge() {
|
|||||||
return utilBackend().translator.database.purge();
|
return utilBackend().translator.database.purge();
|
||||||
}
|
}
|
||||||
|
|
||||||
function utilDatabaseImport(data, progress) {
|
function utilDatabaseImport(data, progress, exceptions) {
|
||||||
return utilBackend().translator.database.importDictionary(data, progress);
|
return utilBackend().translator.database.importDictionary(data, progress, exceptions);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<title>Yomichan Legal</title>
|
<title>Yomichan Legal</title>
|
||||||
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap.min.css">
|
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css">
|
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css">
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<title>Yomichan Search</title>
|
<title>Yomichan Search</title>
|
||||||
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap.min.css">
|
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css">
|
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css">
|
||||||
|
@ -2,13 +2,14 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<title>Yomichan Options</title>
|
<title>Yomichan Options</title>
|
||||||
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap.min.css">
|
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css">
|
<link rel="stylesheet" type="text/css" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css">
|
||||||
<style>
|
<style>
|
||||||
#anki-spinner, #anki-general, #anki-error,
|
#anki-spinner, #anki-general, #anki-error,
|
||||||
#dict-spinner, #dict-error, #dict-warning, #dict-purge, #dict-import-progress,
|
#dict-spinner, #dict-error, #dict-warning, #dict-purge, #dict-import-progress,
|
||||||
#debug, .options-advanced {
|
#debug, .options-advanced, .storage-hidden, #storage-spinner {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,6 +25,21 @@
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bottom-links {
|
||||||
|
padding-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-show-for-browser] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-browser=edge] [data-show-for-browser~=edge],
|
||||||
|
[data-browser=chrome] [data-show-for-browser~=chrome],
|
||||||
|
[data-browser=firefox] [data-show-for-browser~=firefox],
|
||||||
|
[data-browser=firefox-mobile] [data-show-for-browser~=firefox-mobile] {
|
||||||
|
display: initial;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -192,6 +208,40 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="storage-info" class="storage-hidden">
|
||||||
|
<div>
|
||||||
|
<img src="/mixed/img/spinner.gif" class="pull-right" id="storage-spinner" />
|
||||||
|
<h3>Storage</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="storage-use" class="storage-hidden">
|
||||||
|
<p class="help-block">
|
||||||
|
Yomichan is using approximately <strong id="storage-usage"></strong> of <strong id="storage-quota"></strong>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="storage-error" class="storage-hidden">
|
||||||
|
<p class="help-block">
|
||||||
|
Could not detect how much storage Yomichan is using.
|
||||||
|
</p>
|
||||||
|
<div data-show-for-browser="firefox firefox-mobile"><div class="alert alert-danger options-advanced">
|
||||||
|
On Firefox and Firefox for Android, the storage information feature may be hidden behind a browser flag.
|
||||||
|
|
||||||
|
If you would like to enable this flag, open <a href="about:config" target="_blank">about:config</a> and search for the
|
||||||
|
<strong>dom.storageManager.enabled</strong> option. If this option has a value of <strong>false</strong>, toggling it to
|
||||||
|
<strong>true</strong> may allow storage information to be calculated.
|
||||||
|
</div></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-show-for-browser="firefox-mobile"><div class="alert alert-warning">
|
||||||
|
If you are using Firefox for Android, you will have to make sure you have enough free space on your device to install dictionaries.
|
||||||
|
</div></div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input type="button" value="Refresh" id="storage-refresh" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<img src="/mixed/img/spinner.gif" class="pull-right" id="anki-spinner" alt>
|
<img src="/mixed/img/spinner.gif" class="pull-right" id="anki-spinner" alt>
|
||||||
@ -310,8 +360,8 @@
|
|||||||
|
|
||||||
<pre id="debug"></pre>
|
<pre id="debug"></pre>
|
||||||
|
|
||||||
<div class="pull-right">
|
<div class="pull-right bottom-links">
|
||||||
<small><a href="https://foosoft.net/projects/yomichan/" target="_blank">Homepage</a> • <a href="legal.html">Legal</a></small>
|
<small><a href="search.html">Search</a> • <a href="https://foosoft.net/projects/yomichan/" target="_blank">Homepage</a> • <a href="legal.html">Legal</a></small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<title></title>
|
<title></title>
|
||||||
<link rel="stylesheet" href="/mixed/lib/bootstrap/css/bootstrap.min.css">
|
<link rel="stylesheet" href="/mixed/lib/bootstrap/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css">
|
<link rel="stylesheet" href="/mixed/lib/bootstrap/css/bootstrap-theme.min.css">
|
||||||
|
@ -256,7 +256,7 @@ class Frontend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onError(error) {
|
onError(error) {
|
||||||
window.alert(`Error: ${error.toString ? error.toString() : error}`);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
popupTimerSet(callback) {
|
popupTimerSet(callback) {
|
||||||
|
@ -26,11 +26,15 @@ function utilAsync(func) {
|
|||||||
function utilInvoke(action, params={}) {
|
function utilInvoke(action, params={}) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
chrome.runtime.sendMessage({action, params}, ({result, error}) => {
|
chrome.runtime.sendMessage({action, params}, (response) => {
|
||||||
if (error) {
|
if (response !== null && typeof response === 'object') {
|
||||||
reject(error);
|
if (response.error) {
|
||||||
|
reject(response.error);
|
||||||
} else {
|
} else {
|
||||||
resolve(result);
|
resolve(response.result);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reject(`Unexpected response of type ${typeof response}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
Loading…
Reference in New Issue
Block a user