diff --git a/package-lock.json b/package-lock.json index 9232671..c28ebaf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1137,6 +1137,12 @@ "uri-js": "^4.2.1" } }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, "ajv-keywords": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", @@ -5367,6 +5373,12 @@ "brorand": "^1.0.1" } }, + "mime": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", + "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==", + "dev": true + }, "mime-db": { "version": "1.36.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", @@ -9705,6 +9717,30 @@ } } }, + "url-loader": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", + "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "mime": "^2.0.3", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", diff --git a/package.json b/package.json index 04a1889..b3cf711 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "sass-loader": "^7.0.3", "style-loader": "^0.21.0", "uglifyjs-webpack-plugin": "^1.2.5", + "url-loader": "^1.1.2", "webextension-polyfill": "^0.3.1", "webpack": "^4.10.2", "webpack-cli": "^3.0.1", diff --git a/src/common/translate.js b/src/common/translate.js index 8734e91..6025ee0 100644 --- a/src/common/translate.js +++ b/src/common/translate.js @@ -1,86 +1,75 @@ -/* Copyright (c) 2017-2018 Sienori All rights reserved. - * 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/. */ +let translationHistory = []; -class Translate { - constructor() { - this.history = []; - } +const getHistory = (sourceWord, sourceLang, targetLang) => { + const history = translationHistory.find( + history => + history.sourceWord == sourceWord && + history.sourceLang == sourceLang && + history.targetLang == targetLang && + history.result.statusText == "OK" + ); + return history; +}; - getHistory(sourceWord, sourceLang, targetLang) { - const history = this.history.find( - history => - history.sourceWord == sourceWord && - history.sourceLang == sourceLang && - history.targetLang == targetLang && - history.result.statusText == "OK" - ); - return history; - } +const setHistory = (sourceWord, sourceLang, targetLang, formattedResult) => { + translationHistory.push({ + sourceWord: sourceWord, + sourceLang: sourceLang, + targetLang: targetLang, + result: formattedResult + }); +}; - setHistory(sourceWord, sourceLang, targetLang, formattedResult) { - this.history.push({ - sourceWord: sourceWord, - sourceLang: sourceLang, - targetLang: targetLang, - result: formattedResult - }); - } +const sendRequest = (word, sourceLang, targetLang) => { + const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${sourceLang}&tl=${targetLang}&dt=t&dt=bd&dj=1&q=${encodeURIComponent( + word + )}`; + const xhr = new XMLHttpRequest(); + xhr.responseType = "json"; + xhr.open("GET", url); + xhr.send(); - async translate(sourceWord, sourceLang = "auto", targetLang) { - sourceWord = sourceWord.trim(); - - const history = this.getHistory(sourceWord, sourceLang, targetLang); - if (history) return history.result; - - const result = await this.sendRequest(sourceWord, sourceLang, targetLang); - const formattedResult = this.formatResult(result); - this.setHistory(sourceWord, sourceLang, targetLang, formattedResult); - - return formattedResult; - } - - sendRequest(word, sourceLang, targetLang) { - const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${sourceLang}&tl=${targetLang}&dt=t&dt=bd&dj=1&q=${encodeURIComponent( - word - )}`; - const xhr = new XMLHttpRequest(); - xhr.responseType = "json"; - xhr.open("GET", url); - xhr.send(); - - return new Promise((resolve, reject) => { - xhr.onload = () => { - resolve(xhr); - }; - xhr.onerror = () => { - resolve(xhr); - }; - }); - } - - formatResult(result) { - const resultData = { - resultText: "", - candidateText: "", - sourceLanguage: "", - percentage: 0, - statusText: "" + return new Promise((resolve, reject) => { + xhr.onload = () => { + resolve(xhr); }; + xhr.onerror = () => { + resolve(xhr); + }; + }); +}; - resultData.statusText = result.statusText; - if (resultData.statusText !== "OK") return resultData; +const formatResult = result => { + const resultData = { + resultText: "", + candidateText: "", + sourceLanguage: "", + percentage: 0, + statusText: "" + }; - resultData.sourceLanguage = result.response.src; - resultData.percentage = result.response.confidence; - resultData.resultText = result.response.sentences.map(sentence => sentence.trans).join(""); - if (result.response.dict) { - resultData.candidateText = result.response.dict - .map(dict => `${dict.pos}${dict.pos != "" ? ": " : ""}${dict.terms.join(", ")}\n`) - .join(""); - } + resultData.statusText = result.statusText; + if (resultData.statusText !== "OK") return resultData; - return resultData; + resultData.sourceLanguage = result.response.src; + resultData.percentage = result.response.confidence; + resultData.resultText = result.response.sentences.map(sentence => sentence.trans).join(""); + if (result.response.dict) { + resultData.candidateText = result.response.dict + .map(dict => `${dict.pos}${dict.pos != "" ? ": " : ""}${dict.terms.join(", ")}\n`) + .join(""); } -} + + return resultData; +}; + +export default async (sourceWord, sourceLang = "auto", targetLang) => { + sourceWord = sourceWord.trim(); + const history = getHistory(sourceWord, sourceLang, targetLang); + if (history) return history.result; + + const result = await sendRequest(sourceWord, sourceLang, targetLang); + const formattedResult = formatResult(result); + setHistory(sourceWord, sourceLang, targetLang, formattedResult); + return formattedResult; +}; diff --git a/src/content/components/TranslateButton.js b/src/content/components/TranslateButton.js new file mode 100644 index 0000000..d8081ac --- /dev/null +++ b/src/content/components/TranslateButton.js @@ -0,0 +1,37 @@ +import React from "react"; +import { getSettings } from "src/settings/settings"; +import "../styles/TranslateButton.scss"; + +const calcPosition = () => { + const buttonSize = parseInt(getSettings("buttonSize")); + const offset = 10; + switch (getSettings("buttonPosition")) { + case "rightUp": + return { top: -buttonSize - offset, left: offset }; + case "rightDown": + return { top: offset, left: offset }; + case "leftUp": + return { top: -buttonSize - offset, left: -buttonSize - offset }; + case "leftDown": + return { top: offset, left: -buttonSize - offset }; + } +}; + +export default props => { + const { position, shouldShow } = props; + const buttonSize = parseInt(getSettings("buttonSize")); + const { top, left } = calcPosition(); + const buttonStyle = { + height: buttonSize, + width: buttonSize, + top: top + position.y, + left: left + position.x + }; + return ( +