扩展新增功能:页面嵌入搜索引擎,实时检索发音 (#375)
* 新增README.md页面无跳转即可收听正确读音 的 chromium 扩展 * add 手动安装扩展 方法 * fix no element error * add comment console log * change load chrome extension describe * use prettier format code * comment console.log * fix http protocol audio media no play * add chromium extension use Reference * 无页面跳转收听正确读音请安装我们的 chromium 扩展 * 无页面跳转收听正确读音请安装我们的 [chromium 扩展] * change chromium extension README.md * add css * add css extension * add css extension * change app.css extension * 限定权限 * 新增搜索引擎读音检索功能 * 新增功能截图 * 页面嵌入搜索引擎,实时检索发音 * 页面嵌入搜索引擎,实时检索发音 * # 新增功能截图 * change README.md describe * change README.md describe * format code * 新增功能截图 * 新增功能截图 * 新增功能截图 * 新增功能截图 * 新增功能截图 * 新增百度汉语搜索和必应辞典搜索 * 默认搜索引擎修改为有道 * add bing search * add common tool * until method name change * fix error and add new search engine * change chromium url * 设置默认为新标签页打开搜索 * 完善工具库yuanchen8911-patch-2
parent
9cfdee68f5
commit
ec339d9ac9
@ -0,0 +1,33 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# Matches multiple files with brace expansion notation
|
||||
# Set default charset
|
||||
[*.{js,py}]
|
||||
charset = utf-8
|
||||
|
||||
# 4 space indentation
|
||||
[*.py]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
# Tab indentation (no size specified)
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
# Indentation override for all JS under lib directory
|
||||
[lib/**.js]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# Matches the exact files either package.json or .travis.yml
|
||||
[{package.json,.travis.yml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
@ -0,0 +1,8 @@
|
||||
#!/bin/env bash
|
||||
|
||||
set -exu
|
||||
|
||||
__DIR__=$(cd "$(dirname "$0")";pwd)
|
||||
cd ${__DIR__}
|
||||
|
||||
npm run format-code
|
@ -0,0 +1,9 @@
|
||||
# 新增功能截图
|
||||
|
||||
## 嵌入搜索引擎 谷歌搜索
|
||||
|
||||
![](https://github.com/jingjingxyk/chinese-programmer-wrong-pronunciation/blob/master/tools/chromium_extension/images/%E6%88%AA%E5%9B%BE2022-06-14-22-11.png?raw=true)
|
||||
|
||||
## 嵌入搜索引擎 有道搜索
|
||||
|
||||
![](https://raw.githubusercontent.com/jingjingxyk/chinese-programmer-wrong-pronunciation/master/tools/chromium_extension/images/截图2022-06-14-22-10.png)
|
After Width: | Height: | Size: 262 KiB |
After Width: | Height: | Size: 193 KiB |
@ -0,0 +1,42 @@
|
||||
import * as utils from "./utils.js";
|
||||
import * as components from "./components.js";
|
||||
import * as searchEngine from "./search-engine.js";
|
||||
|
||||
let goToSearchPronounce = (word) => {
|
||||
let search_engine_name = "gotToGoogleSearch";
|
||||
// search_engine_name='gotToYouDaoSearch'
|
||||
// search_engine_name = "goToBingDictSearch";
|
||||
// search_engine_name = "goToBingSearch";
|
||||
search_engine_name = "gotToYouDaoSearch";
|
||||
// search_engine_name = "goToBaiduFanYiSearch";
|
||||
//let tab = "current_tab";
|
||||
let tab = "new_tab"; //修改默认为新标签页打开
|
||||
|
||||
let opener = components.getSearchEngineOpener();
|
||||
if (opener && opener.expired_date) {
|
||||
if (opener.expired_date > new Date().getTime()) {
|
||||
if (opener.search_engine_name) {
|
||||
search_engine_name = opener.search_engine_name;
|
||||
}
|
||||
if (opener.tab) {
|
||||
tab = opener.tab;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (search_engine_name && searchEngine[search_engine_name]) {
|
||||
console.log(word);
|
||||
let url = searchEngine[search_engine_name](word);
|
||||
console.log(url);
|
||||
if (tab === "new_tab") {
|
||||
window.open(url, "_blank");
|
||||
} else {
|
||||
let iframe = components.getIframe();
|
||||
iframe.setAttribute("src", url);
|
||||
}
|
||||
} else {
|
||||
console.log("search engine no found !");
|
||||
}
|
||||
};
|
||||
|
||||
let box = { ...utils, ...components, ...searchEngine, goToSearchPronounce };
|
||||
export default box;
|
@ -0,0 +1,131 @@
|
||||
import { prettyBox } from "./pretty-box.js";
|
||||
|
||||
let styleConfig = () => {
|
||||
let css = document.createElement("link");
|
||||
css.setAttribute("rel", "stylesheet");
|
||||
css.setAttribute("type", "text/css");
|
||||
css.setAttribute("href", chrome.runtime.getURL("css/app.css"));
|
||||
document.head.appendChild(css);
|
||||
};
|
||||
|
||||
let customElement = () => {
|
||||
let link = document.createElement("link");
|
||||
link.setAttribute(
|
||||
"href",
|
||||
chrome.runtime.getURL("web-components/x-custom-box.html")
|
||||
);
|
||||
document.head.appendChild(link);
|
||||
};
|
||||
|
||||
let getIframe = () => {
|
||||
let box = document.querySelector(
|
||||
"#chinese-programmer-wrong-pronunciation-custom-iframe-box"
|
||||
);
|
||||
let iframe = null;
|
||||
if (!box) {
|
||||
let custom_box = document.createElement(
|
||||
"x-chinese-programmer-wrong-pronunciation-custom-box"
|
||||
);
|
||||
|
||||
let aside = document.createElement("aside");
|
||||
aside.setAttribute(
|
||||
"id",
|
||||
"chinese-programmer-wrong-pronunciation-custom-iframe-box"
|
||||
);
|
||||
aside.setAttribute(
|
||||
"class",
|
||||
"chinese-programmer-wrong-pronunciation-custom-iframe-box"
|
||||
);
|
||||
aside.setAttribute("draggable", "true");
|
||||
|
||||
iframe = document.createElement("iframe");
|
||||
iframe.setAttribute(
|
||||
"id",
|
||||
"chinese-programmer-wrong-pronunciation-custom-iframe"
|
||||
);
|
||||
iframe.setAttribute("security", "restricted");
|
||||
//iframe.setAttribute('sandbox',"")
|
||||
aside.appendChild(iframe);
|
||||
custom_box.appendChild(aside);
|
||||
document.body.appendChild(custom_box);
|
||||
|
||||
//设置 box 可 拖拽
|
||||
prettyBox(aside);
|
||||
//显示重置按键
|
||||
//showResetCurrentSearchEngineTab()
|
||||
} else {
|
||||
iframe = box.querySelector(
|
||||
"#chinese-programmer-wrong-pronunciation-custom-iframe"
|
||||
);
|
||||
}
|
||||
return iframe;
|
||||
};
|
||||
|
||||
let opener_key = "how-to-pronounce-from-search-engine-open-tab-opener";
|
||||
let getSearchEngineOpener = () => {
|
||||
return JSON.parse(sessionStorage.getItem(opener_key));
|
||||
};
|
||||
|
||||
let showResetCurrentSearchEngineTab = () => {
|
||||
let div = document.createElement("div");
|
||||
div.setAttribute(
|
||||
"id",
|
||||
"#chinese-programmer-wrong-pronunciation-custom-tools-bar"
|
||||
);
|
||||
div.innerHTML = `
|
||||
<span>关闭搜索页面</span>🥳🥳🥳🥳🥳🥳<span>更换搜索引擎</span>
|
||||
`;
|
||||
|
||||
document
|
||||
.querySelector("#chinese-programmer-wrong-pronunciation-custom-iframe-box")
|
||||
.appendChild(div);
|
||||
};
|
||||
let setSearchEngineOpener = (search_engine_name, tab) => {
|
||||
let opener = getSearchEngineOpener();
|
||||
if (!opener || opener.expired_date < new Date().getTime()) {
|
||||
search_engine_name = "gotToGoogleSearch";
|
||||
/*
|
||||
if (window.confirm('默认有道词典搜索,选择 “取消” 将设置为谷歌搜索,有效期一天')) { //当前页面展示搜索结果
|
||||
search_engine_name = "gotToYouDaoSearch"
|
||||
} else {
|
||||
//新开标签页展示搜索结果
|
||||
search_engine_name = "gotToGoogleSearch"
|
||||
}
|
||||
*/
|
||||
|
||||
//页面展示方式,默认有效期一天
|
||||
let expired_date = new Date().getTime() + 24 * 60 * 60 * 1000;
|
||||
// expired_date = (new Date()).getTime() + 10000 # test expired
|
||||
|
||||
tab = "current_tab";
|
||||
/*
|
||||
if (window.confirm('允许当前页面展示搜索结果')) { //当前页面展示搜索结果
|
||||
tab = "current_tab"
|
||||
} else {
|
||||
//新开标签页展示搜索结果
|
||||
tab = "new_tab"
|
||||
}
|
||||
*/
|
||||
|
||||
sessionStorage.setItem(
|
||||
opener_key,
|
||||
JSON.stringify({
|
||||
tab: tab,
|
||||
expired_date: expired_date,
|
||||
search_engine_name: search_engine_name,
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let cleanOpener = () => {
|
||||
sessionStorage.removeItem(opener_key);
|
||||
};
|
||||
|
||||
export {
|
||||
styleConfig,
|
||||
customElement,
|
||||
getIframe,
|
||||
getSearchEngineOpener,
|
||||
setSearchEngineOpener,
|
||||
};
|
@ -0,0 +1,66 @@
|
||||
import box from "./box.js";
|
||||
|
||||
let init = () => {
|
||||
let URLObj = new URL(location.href);
|
||||
console.log(URLObj);
|
||||
if (document.querySelector("#readme table tbody")) {
|
||||
box.styleConfig();
|
||||
box.customElement();
|
||||
|
||||
let audio_player = new Audio();
|
||||
audio_player.setAttribute("autoplay", "true");
|
||||
document
|
||||
.querySelector("#readme table tbody")
|
||||
.addEventListener("click", (event) => {
|
||||
//console.log(event.target)
|
||||
// console.log(event.target.nodeType)
|
||||
// console.log(event.target.nodeName);
|
||||
let parentElement = event.target.parentElement;
|
||||
if (parentElement && parentElement.nodeName === "TR") {
|
||||
if (parentElement.firstElementChild === event.target) {
|
||||
//使用搜索引擎查询发音
|
||||
box.goToSearchPronounce(event.target.innerText);
|
||||
}
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
let audio_url = null;
|
||||
if (event.target.nodeName === "TD") {
|
||||
let aTag = event.target.querySelector("a");
|
||||
if (aTag) {
|
||||
audio_url = aTag.getAttribute("href");
|
||||
}
|
||||
}
|
||||
if (event.target.nodeName === "IMG") {
|
||||
let aTag = event.target.parentNode.parentNode;
|
||||
audio_url = aTag.getAttribute("href");
|
||||
}
|
||||
if (audio_url) {
|
||||
let desURL = new URL(audio_url);
|
||||
//console.log(desURL.protocol);
|
||||
if (desURL.protocol === "http:") {
|
||||
//skip http
|
||||
location.href = audio_url;
|
||||
} else {
|
||||
// console.log("audio_url:", audio_url);
|
||||
audio_player.setAttribute("src", audio_url);
|
||||
}
|
||||
}
|
||||
});
|
||||
document
|
||||
.querySelector("#readme table tbody")
|
||||
.addEventListener("mouseover", (event) => {
|
||||
let parentElement = event.target.parentElement;
|
||||
if (parentElement && parentElement.nodeName === "TR") {
|
||||
if (parentElement.firstElementChild === event.target) {
|
||||
event.target.setAttribute("title", "点击我打开搜索引擎检索");
|
||||
event.target.style.cursor = "pointer";
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log("no found README.md table");
|
||||
}
|
||||
};
|
||||
|
||||
export { init };
|
@ -0,0 +1,74 @@
|
||||
import { addClass, removeClass } from "./utils.js";
|
||||
|
||||
let prettyBox = (box) => {
|
||||
// 参考 https://blog.csdn.net/weixin_41910848/article/details/82218243
|
||||
|
||||
let dragging = false;
|
||||
let diffX = null;
|
||||
let diffY = null;
|
||||
box.onmousedown = function (event) {
|
||||
dragging = true;
|
||||
|
||||
let left = box.offsetLeft;
|
||||
let top = box.offsetTop;
|
||||
|
||||
removeClass(
|
||||
box,
|
||||
"chinese-programmer-wrong-pronunciation-custom-iframe-box"
|
||||
);
|
||||
|
||||
box.style.left = left + "px";
|
||||
box.style.top = top + "px";
|
||||
|
||||
diffX = event.clientX - left;
|
||||
diffY = event.clientY - top;
|
||||
};
|
||||
document.onmousemove = function (event) {
|
||||
if (dragging) {
|
||||
// console.log(event.clientX, event.clientY)
|
||||
//console.log(diffX, diffY)
|
||||
|
||||
let moveX = event.clientX - diffX;
|
||||
let moveY = event.clientY - diffY;
|
||||
|
||||
if (moveX < 0) {
|
||||
moveX = 0;
|
||||
} else if (moveX > window.innerWidth - box.offsetWidth) {
|
||||
moveX = window.innerWidth - box.offsetWidth;
|
||||
}
|
||||
if (moveY < 0) {
|
||||
moveY = 0;
|
||||
} else if (moveY > window.innerHeight - box.offsetHeight) {
|
||||
moveY = window.innerHeight - box.offsetHeight;
|
||||
}
|
||||
|
||||
box.style.left = moveX + "px";
|
||||
box.style.top = moveY + "px";
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
document.onmouseup = function (event) {
|
||||
dragging = false;
|
||||
};
|
||||
|
||||
box.onmouseup = (event) => {
|
||||
dragging = false;
|
||||
};
|
||||
|
||||
box.ondragstart = function (event) {
|
||||
console.log(box.offsetLeft, box.offsetTop);
|
||||
console.log("开始拖拽");
|
||||
};
|
||||
box.ondrag = function () {
|
||||
console.log(box.offsetLeft, box.offsetTop);
|
||||
console.log("拖拽中");
|
||||
};
|
||||
box.ondragend = function () {
|
||||
console.log(box.offsetLeft, box.offsetTop);
|
||||
console.log("拖拽结束");
|
||||
};
|
||||
};
|
||||
|
||||
export { prettyBox };
|
@ -0,0 +1,103 @@
|
||||
function hasClass(el, className) {
|
||||
if (el.classList) return el.classList.contains(className);
|
||||
return !!el.className.match(new RegExp("(\\s|^)" + className + "(\\s|$)"));
|
||||
}
|
||||
|
||||
function addClass(el, className) {
|
||||
if (el.classList) el.classList.add(className);
|
||||
else if (!hasClass(el, className)) el.className += " " + className;
|
||||
}
|
||||
|
||||
function removeClass(el, className) {
|
||||
if (el.classList) el.classList.remove(className);
|
||||
else if (hasClass(el, className)) {
|
||||
let reg = new RegExp("(\\s|^)" + className + "(\\s|$)");
|
||||
el.className = el.className.replace(reg, " ");
|
||||
}
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
let arr,
|
||||
reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
|
||||
if ((arr = document.cookie.match(reg))) {
|
||||
return decodeURIComponent(arr[2]);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
//await cookieStore.get({name:name})
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
|
||||
|
||||
function setCookie(name, value, second, domain) {
|
||||
var exp = new Date();
|
||||
exp.setTime(exp.getTime() + second * 1000);
|
||||
document.cookie =
|
||||
name +
|
||||
"=" +
|
||||
encodeURIComponent(value) +
|
||||
";expires=" +
|
||||
exp.toGMTString() +
|
||||
";path=/;domain=" +
|
||||
domain +
|
||||
";SameSite=None;Secure";
|
||||
}
|
||||
async function getCookies(domain) {
|
||||
let cookies = await cookieStore.getAll({ domain: domain });
|
||||
return cookies;
|
||||
}
|
||||
|
||||
function encodeBase64(str) {
|
||||
return btoa(encodeURIComponent(str));
|
||||
}
|
||||
|
||||
function decodeBase64(encoded) {
|
||||
return decodeURIComponent(atob(encoded));
|
||||
}
|
||||
|
||||
function getParameterValue(name) {
|
||||
let reg = new RegExp("[^?&]?" + encodeURI(name) + "=[^&]+");
|
||||
let arr = location.search.match(reg);
|
||||
if (arr != null) {
|
||||
return decodeURI(arr[0].substring(arr[0].search("=") + 1));
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function createJSONFile(content, filename) {
|
||||
let blob = new Blob([JSON.stringify(content)], { type: "application/json" });
|
||||
let url = window.URL.createObjectURL(blob);
|
||||
let a = document.createElement("a");
|
||||
a.style.display = "none";
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
a.click();
|
||||
setTimeout(function () {
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
async function sleep(time) {
|
||||
return new Promise((resolve) => setTimeout(resolve, time));
|
||||
}
|
||||
|
||||
async function getMediaDevices() {
|
||||
return await navigator.mediaDevices.enumerateDevices();
|
||||
}
|
||||
|
||||
// new URLSearchParams
|
||||
// new URL
|
||||
// (new Date()).toISOString()
|
||||
export {
|
||||
addClass,
|
||||
removeClass,
|
||||
hasClass,
|
||||
setCookie,
|
||||
getCookie,
|
||||
encodeBase64,
|
||||
decodeBase64,
|
||||
getParameterValue,
|
||||
sleep,
|
||||
getMediaDevices,
|
||||
createJSONFile,
|
||||
};
|
@ -1,45 +1,4 @@
|
||||
{
|
||||
let URLObj = new URL(location.href);
|
||||
console.log(URLObj);
|
||||
if (document.querySelector("#readme table tbody")) {
|
||||
console.log(chrome.runtime.getURL("css/app.css"));
|
||||
let css = document.createElement("link");
|
||||
css.setAttribute("rel", "stylesheet");
|
||||
css.setAttribute("type", "text/css");
|
||||
css.setAttribute("href", chrome.runtime.getURL("css/app.css"));
|
||||
document.head.appendChild(css);
|
||||
let audio_player = new Audio();
|
||||
audio_player.setAttribute("autoplay", "true");
|
||||
document
|
||||
.querySelector("#readme table tbody")
|
||||
.addEventListener("click", (event) => {
|
||||
// console.log(event)
|
||||
// console.log(event.target.nodeType)
|
||||
// console.log(event.target.nodeName);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
let audio_url = null;
|
||||
if (event.target.nodeName === "TD") {
|
||||
let aTag = event.target.querySelector("a");
|
||||
if (aTag) {
|
||||
audio_url = aTag.getAttribute("href");
|
||||
}
|
||||
}
|
||||
if (event.target.nodeName === "IMG") {
|
||||
let aTag = event.target.parentNode.parentNode;
|
||||
audio_url = aTag.getAttribute("href");
|
||||
}
|
||||
if (audio_url) {
|
||||
let desURL = new URL(audio_url);
|
||||
console.log(desURL.protocol);
|
||||
if (desURL.protocol === "http:") {
|
||||
//skip http
|
||||
location.href = audio_url;
|
||||
} else {
|
||||
console.log("audio_url:", audio_url);
|
||||
audio_player.setAttribute("src", audio_url);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
(async () => {
|
||||
let app = await import(chrome.runtime.getURL("js/app/init.js"));
|
||||
app.init();
|
||||
})();
|
||||
|
@ -0,0 +1,3 @@
|
||||
<x-chinese-programmer-wrong-pronunciation-custom-box>
|
||||
<div>自定义web组件-做代码隔离</div>
|
||||
</x-chinese-programmer-wrong-pronunciation-custom-box>
|
Loading…
Reference in new issue