2019-01-04 11:07:50 +00:00
|
|
|
|
// ==UserScript==
|
2019-01-16 12:45:52 +00:00
|
|
|
|
// @name 划词翻译:多词典查询
|
2019-01-04 11:07:50 +00:00
|
|
|
|
// @namespace http://tampermonkey.net/
|
2019-09-25 10:11:56 +00:00
|
|
|
|
// @version 6.5
|
2019-02-14 11:04:56 +00:00
|
|
|
|
// @description 划词翻译调用“有道词典(有道翻译)、金山词霸、Bing 词典(必应词典)、剑桥高阶、沪江小D、谷歌翻译”
|
2019-01-04 11:07:50 +00:00
|
|
|
|
// @author https://github.com/barrer
|
|
|
|
|
// @match http://*/*
|
|
|
|
|
// @include https://*/*
|
|
|
|
|
// @include file:///*
|
2019-03-22 11:43:10 +00:00
|
|
|
|
// @run-at document-start
|
2019-01-16 12:45:52 +00:00
|
|
|
|
// @connect hjenglish.com
|
2019-01-04 11:07:50 +00:00
|
|
|
|
// @grant GM_xmlhttpRequest
|
|
|
|
|
// ==/UserScript==
|
|
|
|
|
|
|
|
|
|
(function () {
|
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
// Your code here...
|
2019-09-25 10:11:56 +00:00
|
|
|
|
/**联网权限*/
|
|
|
|
|
// @connect hjenglish.com 沪江小D
|
2019-01-07 10:59:21 +00:00
|
|
|
|
/**样式*/
|
|
|
|
|
var style = document.createElement('style');
|
2019-08-01 10:05:38 +00:00
|
|
|
|
// >>>>> 可以自定义的变量
|
2019-07-03 08:14:10 +00:00
|
|
|
|
var fontSize = 14; // 字体大小
|
|
|
|
|
var iconWidth = 300; // 整个面板宽度
|
|
|
|
|
var iconHeight = 400; // 整个面板高度
|
2019-08-01 10:05:38 +00:00
|
|
|
|
// 可以自定义的变量 <<<<< (自定义变量修改后把 “@version” 版本号改为 “10000” 防止更新后消失)
|
2019-07-03 08:14:10 +00:00
|
|
|
|
var trContentWidth = iconWidth - 16; // 整个面板宽度 - 边距间隔 = 翻译正文宽度
|
2019-08-01 10:05:38 +00:00
|
|
|
|
var trContentHeight = iconHeight - 35; // 整个面板高度 - 边距间隔 = 翻译正文高度
|
|
|
|
|
var zIndex = '2147483647'; // 渲染图层
|
2019-01-07 10:59:21 +00:00
|
|
|
|
style.textContent = `
|
2019-02-21 04:21:09 +00:00
|
|
|
|
/*组件样式*/
|
2019-03-28 10:09:57 +00:00
|
|
|
|
:host{all:unset!important}
|
2019-03-22 11:43:10 +00:00
|
|
|
|
:host{all:initial!important}
|
2019-02-23 01:28:48 +00:00
|
|
|
|
*{word-wrap:break-word!important;word-break:break-word!important}
|
2019-06-03 11:17:24 +00:00
|
|
|
|
a{color:#00c;text-decoration:none;cursor:pointer}
|
|
|
|
|
a:hover{text-decoration:none}
|
|
|
|
|
a:active{text-decoration:underline}
|
2019-08-01 10:05:38 +00:00
|
|
|
|
img{cursor:pointer;display:inline-block;width:20px;height:20px;border:1px solid #dfe1e5;border-radius:4px;background-color:rgba(255,255,255,1);padding:2px;margin:0;margin-right:5px;box-sizing:content-box;vertical-align:middle}
|
2019-02-21 04:21:09 +00:00
|
|
|
|
img:last-of-type{margin-right:auto}
|
2019-06-03 11:17:24 +00:00
|
|
|
|
img:hover{border:1px solid #f90}
|
2019-02-27 11:00:28 +00:00
|
|
|
|
img[activate]{border:1px solid #f90}
|
2019-03-21 04:21:03 +00:00
|
|
|
|
img[activate]:hover{border:1px solid #f90}
|
2019-04-16 07:27:51 +00:00
|
|
|
|
table{font-size:inherit;color:inherit}
|
2019-08-01 10:05:38 +00:00
|
|
|
|
tr-icon{display:none;position:absolute;padding:0;margin:0;cursor:move;box-sizing:content-box;font-size:${fontSize}px;text-align:left;border:0;border-radius:4px;color:black;z-index:${zIndex};background:transparent}
|
2019-02-27 11:00:28 +00:00
|
|
|
|
tr-icon[activate]{background:#fff;-webkit-box-shadow:0 3px 8px 0 rgba(0,0,0,0.2),0 0 0 0 rgba(0,0,0,0.08);box-shadow:0 3px 8px 0 rgba(0,0,0,0.2),0 0 0 0 rgba(0,0,0,0.08)}
|
2019-02-21 04:21:09 +00:00
|
|
|
|
tr-audio{display:block;margin-bottom:5px}
|
2019-02-23 01:28:48 +00:00
|
|
|
|
tr-audio a{margin-right:1em;font-size:80%}
|
2019-02-21 04:21:09 +00:00
|
|
|
|
tr-audio a:last-of-type{margin-right:auto}
|
2020-01-08 04:31:58 +00:00
|
|
|
|
tr-content{display:none;width:${trContentWidth}px;height:auto;overflow-x:hidden;overflow-y:scroll;background:white;padding:2px 8px;margin-top:5px;box-sizing:content-box;font-family:"Helvetica Neue","Helvetica","Arial","sans-serif";font-size:${fontSize}px;font-weight:normal;line-height:normal;-webkit-font-smoothing:auto;font-smoothing:auto;text-rendering:auto}
|
2019-04-16 04:50:01 +00:00
|
|
|
|
tr-engine~tr-engine{margin-top:1em}
|
2019-06-03 11:17:24 +00:00
|
|
|
|
tr-engine .title{color:#00c;display:inline-block;font-weight:bold}
|
2019-04-16 04:50:01 +00:00
|
|
|
|
tr-engine .title:hover{text-decoration:none}
|
2019-02-21 04:21:09 +00:00
|
|
|
|
/*各引擎样式*/
|
|
|
|
|
.hjenglish dl,.hjenglish dt,.hjenglish dd,.hjenglish p,.hjenglish ul,.hjenglish li,.hjenglish h3{margin:0;padding:0;margin-block-start:0;margin-block-end:0;margin-inline-start:0;margin-inline-end:0}
|
|
|
|
|
.hjenglish h3{font-size:1em;font-weight:normal}
|
|
|
|
|
.hjenglish .detail-pron,.hjenglish .pronounces{color:#777}
|
|
|
|
|
.hjenglish ul{margin-left:2em}
|
|
|
|
|
.hjenglish .def-sentence-from,.hjenglish .def-sentence-to{display:none}
|
|
|
|
|
.hjenglish .detail-groups dd h3:before{counter-increment:eq;content:counter(eq) ".";display:block;width:22px;float:left}
|
|
|
|
|
.hjenglish .detail-groups dl{counter-reset:eq;margin-bottom:.5em;clear:both}
|
|
|
|
|
.hjenglish ol,.hjenglish ul{list-style:none}
|
|
|
|
|
.hjenglish dd{margin-left:1em}
|
|
|
|
|
.hjenglish dd>p{margin-left:2.5em}
|
2020-01-08 04:31:58 +00:00
|
|
|
|
.hjenglish .pronounces .word-audio {margin-left:2.5em}
|
2019-01-07 10:59:21 +00:00
|
|
|
|
`;
|
2019-01-23 10:40:19 +00:00
|
|
|
|
// iframe 工具库
|
|
|
|
|
var iframe = document.createElement('iframe');
|
|
|
|
|
var iframeWin = null;
|
|
|
|
|
var iframeDoc = null;
|
|
|
|
|
iframe.style.display = 'none';
|
2019-02-17 01:52:33 +00:00
|
|
|
|
var icon = document.createElement('tr-icon'), //翻译图标
|
|
|
|
|
content = document.createElement('tr-content'), // 内容面板
|
|
|
|
|
contentList = document.createElement('div'), //翻译内容结果集(HTML内容)列表
|
|
|
|
|
selected, // 当前选中文本
|
|
|
|
|
engineId, // 当前翻译引擎
|
|
|
|
|
engineTriggerTime, // 引擎触发时间(milliseconds)
|
2019-08-01 10:05:38 +00:00
|
|
|
|
idsType, // 当前翻译面板内容列表数组
|
|
|
|
|
pageX, // 图标显示的 X 坐标
|
|
|
|
|
pageY; // 图标显示的 Y 坐标
|
2019-01-23 01:45:54 +00:00
|
|
|
|
// 初始化内容面板
|
|
|
|
|
content.appendChild(contentList);
|
2019-03-29 04:20:30 +00:00
|
|
|
|
// 发音缓存
|
2019-04-16 04:50:01 +00:00
|
|
|
|
var audioCache = {}; // {'mp3 download url': data}
|
2019-01-16 12:45:52 +00:00
|
|
|
|
// 翻译引擎结果集
|
|
|
|
|
var engineResult = {}; // id: DOM
|
2019-04-02 10:04:59 +00:00
|
|
|
|
// 唯一 ID
|
2019-01-16 12:45:52 +00:00
|
|
|
|
var ids = {
|
|
|
|
|
HJENGLISH: 'hjenglish',
|
|
|
|
|
};
|
2019-04-02 10:04:59 +00:00
|
|
|
|
// 唯一 ID 扩展
|
2019-01-16 12:45:52 +00:00
|
|
|
|
var idsExtension = {
|
2019-04-02 10:04:59 +00:00
|
|
|
|
// ID 组
|
2020-01-08 04:31:58 +00:00
|
|
|
|
LIST_DICT: [ids.HJENGLISH,],
|
|
|
|
|
LIST_DICT_LOWER_CASE: [ids.HJENGLISH,],
|
2019-04-02 10:04:59 +00:00
|
|
|
|
// 去重比对(大小写翻译可能一样)
|
2019-01-16 12:45:52 +00:00
|
|
|
|
lowerCaseMap: (function () {
|
|
|
|
|
var obj = {};
|
|
|
|
|
return obj;
|
|
|
|
|
})(),
|
2019-04-02 10:04:59 +00:00
|
|
|
|
// 标题
|
2019-01-16 12:45:52 +00:00
|
|
|
|
names: (function () {
|
|
|
|
|
var obj = {};
|
2019-06-03 11:17:24 +00:00
|
|
|
|
obj[ids.HJENGLISH] = '沪江小D';
|
2019-01-16 12:45:52 +00:00
|
|
|
|
return obj;
|
2019-02-14 11:04:56 +00:00
|
|
|
|
})(),
|
2019-04-02 10:04:59 +00:00
|
|
|
|
// 跳转到网站(“%q%”占位符或者 function text -> return URL)
|
2019-02-14 11:04:56 +00:00
|
|
|
|
links: (function () {
|
|
|
|
|
var obj = {};
|
2020-01-08 04:31:58 +00:00
|
|
|
|
obj[ids.HJENGLISH] = 'https://dict.hjenglish.com/jp/jc/%q%';
|
2019-02-14 11:04:56 +00:00
|
|
|
|
return obj;
|
|
|
|
|
})(),
|
2019-04-02 10:04:59 +00:00
|
|
|
|
// 翻译引擎
|
2019-02-14 11:04:56 +00:00
|
|
|
|
engines: (function () {
|
|
|
|
|
var obj = {};
|
2020-01-08 04:31:58 +00:00
|
|
|
|
|
2019-02-17 01:52:33 +00:00
|
|
|
|
obj[ids.HJENGLISH] = function (text, time) {
|
2020-01-08 04:31:58 +00:00
|
|
|
|
ajax('https://dict.hjenglish.com/jp/jc/' + encodeURIComponent(text), function (rst) {
|
2019-02-17 01:52:33 +00:00
|
|
|
|
putEngineResult(ids.HJENGLISH, parseHjenglish(rst), time);
|
2019-02-14 11:04:56 +00:00
|
|
|
|
showContent();
|
|
|
|
|
}, function (rst) {
|
2019-02-17 01:52:33 +00:00
|
|
|
|
putEngineResult(ids.HJENGLISH, htmlToDom('error: 无法连接翻译服务'), time);
|
2019-02-14 11:04:56 +00:00
|
|
|
|
showContent();
|
|
|
|
|
}, {
|
|
|
|
|
headers: {
|
2019-08-01 10:05:38 +00:00
|
|
|
|
'Cookie': 'HJ_SID=' + uuid() + '; HJ_SSID_3=' + uuid() + '; HJ_CST=1; HJ_CSST_3=1; HJ_UID=' + uuid(),
|
|
|
|
|
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
|
2019-02-14 11:04:56 +00:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
2020-01-08 04:31:58 +00:00
|
|
|
|
|
2019-02-14 11:04:56 +00:00
|
|
|
|
return obj;
|
|
|
|
|
})()
|
2020-01-08 04:31:58 +00:00
|
|
|
|
};
|
2019-02-14 11:04:56 +00:00
|
|
|
|
// 绑定图标拖动事件
|
|
|
|
|
var iconDrag = new Drag(icon);
|
|
|
|
|
// 图标数组
|
|
|
|
|
var iconArray = [{
|
|
|
|
|
name: '多词典查询',
|
|
|
|
|
id: 'icon-dict',
|
2020-01-08 04:31:58 +00:00
|
|
|
|
image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAAAXNSR0IArs4c6QAAFtFJREFUeAHNXWuMXddV3ufOnbE9xtTP2DUo2I6dUNwWKWooVmniCFVUbcCFqpXyi0iIlqoBIX7wbrBUlX+AKhKqWkiJQFA1VWgjUEVLpDZpiqEuSaGE0jgPJzFOHMevjO2ZsWfO4fvW2t85++5z78y5dh13W+estdde7732Pvvce20XYcz2kW9XkxeeD7dA7N1FEXZVIWwrQtgKuKaqwppeCCuAT+DqYbwHGoA30AJxQjbh9TgGyAwZbxlD1gUflRcGTUDC0aLxY7hXgaUIJfqLEJmD4RngMzBzDPAIaIch/43p7eHQgXcUl6L1ToA2OrVffai6dbEMH4PRfcjAKgrBL/gCD/FneKN6jsmM8OH8SgYhWytBRk1v4+kfMmVQJh3UW8yi+3Dohc/8/QeLx1JLo3BFNmo83Plgtaeowr1I0s0tJtmWliw/eUKaZHoCWWkqGtOd6dPkELLlCc31tyY088eUJDfZjvMF/Y0/sPkEqvbuz324OJiItFCF3hq462vVyrkT4dNg+HU4PpKvJbgkIY+IakUbJqgxQrbl+J1L95w71yY+wRZ/UVRI7l+v2Bh+64HbiznxpZAyrXbnw9XmarZ6GGl7Zz0t5EqnyKQyk1m3zZ+bygSybp3bUflr+ZPrz/vLGcj4Y4kWvd6/FyvCvs/tK45nHHFtJFQmb3G2Oojgt7cnPHMgD2C5YTikZegmB2tiGXXtAhwUT9YfHWHLGLJuvX8MW8MUT+MpiucnVhZ78iTKEtnDR/6xmj5zvvo6guRT9gfeWv7DgmidjKUBUUDChG9Aw557aO3qYu+BXywuyBxOHU07M1PeW5blLawSXmUCDQerIH3OL40Rprj4oNRkCFNc46lMitfjpcuXgLzMxwjNZ/oUbUgmhalOw+UnZYZcKQ9xXLecQo6ajHmRWv9DD1a3lQvl15tpJZnmNe3sD7Z8VJxNWQ9S6KSenNQUtxiDrnmQfzn7g960ufOneJsj19DNfq8/sfcLHy4epbRVIAIrkLz7PONeZZ5x4YRuXpDJYxMkzjFB47NZA49mF9yGE9ofyvOPdDseZ9uqOMXJZz7W/JKLtsFgPkSFpg2429CqcGh6jB+j5Enwxqbbo06Lx+wDXyzvY87Q9QR+6PPhPRDaDb46GOJsgsSpWNCNDBrwMWNxvihdAvJiNQsabupAA3QHGVwTMHk8pfSVDyCqdWhBczTh57Any/22ZQ5aveQj7nzOsxQOdvOakE3xL5bl7l/+/MJ7SOvzdmlh8eNkZckzQEI24R40XRfNhs1Z0jzIxhidUtOY9cFsSXD1wMEZn8zib7SkelONDSexVL9wQRs3gy6DFwLww2RU5/F5TOQYJ/5ioUDOwlcL7H2r5ucXT0P1CipZquV7ljkDgeiPJVg06hGu8TZh0Fquf3AU+qBIPDbms8fIvWUGxUvIlg0PITjfqHuqD3v5xcnJibX9ubmFPXBg2eSZA7F8rHKMAB8UBPrCfXdwN+rkWRfMUQe7Eo3x2fIlzmXsLQ+Zy1c0cAg36BXE8XoFRVxLjxmUj6afGaExZThaHQVk22BVTS3OVXv6kH1XKQk6ojSLlkKLmDwpcSncBMAQBTL90GRNkGxkEbuXDAiRQa4p3kwdkuO8BqmZXa1bs+Q0oS2YK8wZLBwojeH0kLs+9oGd5rSY0w4dNyENApKmJlyQ9AEcHRmtZRIG6Y4O1dWgEmSmkgqpDIeJejzikpfqGhLBoGIaNgPmswTof4q7+GBMFPDG3PVR8Nu8NCGLPyx/bcKGQ6GWRF0etRE5FyOQbUGSicdhk1cQ9EHradSalx5Bk+HNm5ar/Jfvtb80bLJygHIJLt+i/vHj723rV1W5ZTAf0BZtRL3ug/ks42IgL/Co4G1birBhFSfAm4ZWTUaCFNeQdOkkzmMppfWCJNw10swsPu48O1+FmfkQXsd14jwmuHYHDOaO81Njq6VDwgUlK31RWMONr5EhlFv6WA1raiPijNBnhCGJAKisQMjeKsrSIHWsR/J+91Y7GdUqrzZy7mIVvvdqFR5/oQzfOFKG2YXGYl5RecUzDZwUpUNhCi4bf69YU7z3/vnXsYKaJDb2vRjMSkps8JaDGPrLOybDjRtVQQ3vG4FduFSFB7+7GL74VBnmF2FRvitDli104oqpi0ElnDvJupGOfMz7M/i6IEzppG5vFyhJf8tgehx3rME1Th31EcEUFuHAoaQE3Mgbdp+eLMJdN/fDX+2bDNvXuW/ylZD5EDQcsQpaDsBTQ+NvYk5zIZ1QN9XDEaZvWdbERMhJyi/ykSZ+exiCRsiLm/l/vlKFgy9y+q9d+7EfLcKn3z8Z3nU9VgL8syxFH4nLX44phjS2PG71Ux6TRe5Ygb1aIWyZwhg7M82mjNezAybiHBU0HPyEn/3WQlhMFVHJG9ym+kX44719S6L8pwuKyXF3iq7KXcGUV/J5/Ci+Xg+f/xWsHF5kFHTcDYJslcfkGE5IC6RHmOIvvV6Ff/r+ta1CujWBk+4f3tYPN230k4HFBLoSolgvO/6yKvi9rSXBEgHlgnRAxzNCu8hLnBBXWeEoGaHh5hxf0UN44MmFcB5PyGvdJieKsP/np8KbVka/4ZD8p3eGE0ZHBdntEj8SyKpzRWnVGY56FuTp3wwKmkGd+bjRALf6d3jmQhUeeuraVyHd3LS6CL/5s5OIU7H6SvO4RWtWW12hHeLnHuiJIWQiBVNcPHTAxt0BT7gn2XAkUZDvL3T4h6XdvmMi3LRJ/iUxKzaLa/z4LYG2OcbKGvZQqGcERjxBbogFxxQRGo6ECTJ529Zdm/MgXBrafuWn/JBPn81vOCuouAWNHgtmqfjxKkdbdrMKtJ53gaqKuETBZXTSrJvQvC+y4I51Ltdwj8b+/PGL+OHK6HGOUNsK5GAt3njeel0v/PSbe/YDnKWlmtGf2zYRJh67FBaaj58QC7W6YcUl2CV+vMo175Kmp9HnHlN3zAOrKv1SqHHNMYkSTk3gF0c4j3Vpx8+V4Yvfw35Jz5NXRZn28JohvTjsXF+Ee25fEbav71bpPGjvvq4IT77sGXRTVxa/P4XhIX235RmhyjaFTAb7o5pGCK9fW9gxYhRvSn/uVHxYgWg+AFJH6wLBaIS4nj5Zhd/+8nzgBHRtN23qmSzl88tsg57GnOK0wX7afA8E0Qd8k/WSa5avP72SBwg0UA1lBFNDxLePsf89d9oT4D40AdBXswGY4rLFQE6cL8MDT3R/fbz+TYhrhP+M233gyukW/0DttwKAGgugq0HwmWHct2N5dW3PnuR5kk92JkqQkxRxx6Juhu8BcsMn/i/PXAoXl9tAozMbVw+EHKkOLid+2wNTLQxCTZ+G61ss0QV5ZGYofnR2KoNm2zFGBT57qsREeVoEqYO+UL98km5B56nCuYshvHquCj+O6lqurcJDSIly3iRgEGSLY13ix1OYXkbDwqMWqRZ0g8kdcoPytIoLAjd03NgZzPOnFs1xnw6mx/2hW5bQ2j1u+FpadNtxQn4u2KXx4WY+k5kGFDP7wseIHx/pR0FCOm7C0WOrJuIjnIuGXMYUGOs0PoHewh/7dmhHz+I3t/ULi+w4xJuiu6RnBN1LSlSJICS5SzuPT7Rr1pb/48c/cA50B2r10Z+0TzxNqHDCZmhHx+qjCJev4qhVR3UcX7Il7vB1rUubwdcBtb2hBZLGS41pPzFoxoqw5BJulXhcWp5E6oZCLYOokLRx97+mkuL0RJ9temjCdPMGzKJ3CuX4BdIENqsN0w1XzT4EOYV3dNmrfWcMbHk8ik3jtScNP7+Vi05Rg/CGoaFxfEizgCI94l33P0odPon9r1aLPa2uCrgVcYdgEqMgScDfgrcS/pWALu2507Q3Kr7x48dTOG40sN647x7ScZpSAK2vDX3QckznNYE3bOi2/1HmmdeaZ7hVlMXg9r0A4APtoOEbROB8cPim6P6U4eatnX5YYTp4ZPKY2aXiK4vfHiLRvyETzJTKEBPpuEP0s
|
2019-02-17 01:52:33 +00:00
|
|
|
|
trigger: function (text, time) {
|
2019-02-14 11:04:56 +00:00
|
|
|
|
idsType = idsExtension.LIST_DICT;
|
|
|
|
|
if (text != text.toLowerCase()) {
|
2019-04-02 10:04:59 +00:00
|
|
|
|
idsType = idsExtension.LIST_DICT_LOWER_CASE; // 改为大小写 ID 组(大小写各请求一次)
|
2019-01-16 12:45:52 +00:00
|
|
|
|
}
|
2019-02-14 11:04:56 +00:00
|
|
|
|
idsType.forEach(function (id) {
|
2019-02-17 01:52:33 +00:00
|
|
|
|
idsExtension.engines[id](text, time);
|
2019-02-14 11:04:56 +00:00
|
|
|
|
});
|
2019-04-16 04:50:01 +00:00
|
|
|
|
initContent(); // 初始化翻译面板
|
|
|
|
|
displayContent(); // 立马显示翻译面板
|
2019-01-04 11:07:50 +00:00
|
|
|
|
}
|
|
|
|
|
}];
|
2019-01-09 12:50:31 +00:00
|
|
|
|
// 添加翻译引擎图标
|
2019-01-04 11:07:50 +00:00
|
|
|
|
iconArray.forEach(function (obj) {
|
|
|
|
|
var img = document.createElement('img');
|
|
|
|
|
img.setAttribute('src', obj.image);
|
|
|
|
|
img.setAttribute('alt', obj.name);
|
|
|
|
|
img.setAttribute('title', obj.name);
|
2019-01-09 10:48:36 +00:00
|
|
|
|
img.setAttribute('icon-id', obj.id);
|
2019-01-04 11:07:50 +00:00
|
|
|
|
img.addEventListener('mouseup', function () {
|
2019-02-23 01:28:48 +00:00
|
|
|
|
if (engineId == obj.id) {
|
2019-04-02 10:04:59 +00:00
|
|
|
|
// 已经是当前翻译引擎,不做任何处理
|
|
|
|
|
} else {
|
|
|
|
|
icon.setAttribute('activate', 'activate'); // 标注面板展开
|
|
|
|
|
engineId = obj.id; // 翻译引擎 ID
|
|
|
|
|
engineTriggerTime = new Date().getTime(); // 引擎触发时间
|
|
|
|
|
engineActivateShow(); // 显示翻译引擎指示器
|
|
|
|
|
audioCache = {}; // 清空发音缓存
|
|
|
|
|
engineResult = {}; // 清空翻译引擎结果集
|
|
|
|
|
obj.trigger(selected, engineTriggerTime); // 启动翻译引擎
|
2019-01-06 06:35:25 +00:00
|
|
|
|
}
|
2019-01-04 11:07:50 +00:00
|
|
|
|
});
|
|
|
|
|
icon.appendChild(img);
|
|
|
|
|
});
|
2019-01-09 12:50:31 +00:00
|
|
|
|
// 添加内容面板(放图标后面)
|
|
|
|
|
icon.appendChild(content);
|
|
|
|
|
// 添加样式、翻译图标到 DOM
|
2019-01-07 03:44:12 +00:00
|
|
|
|
var root = document.createElement('div');
|
|
|
|
|
document.documentElement.appendChild(root);
|
|
|
|
|
var shadow = root.attachShadow({
|
2019-03-14 10:44:25 +00:00
|
|
|
|
mode: 'closed'
|
2019-01-07 03:44:12 +00:00
|
|
|
|
});
|
2019-01-23 10:40:19 +00:00
|
|
|
|
// iframe 工具库加入 Shadow
|
|
|
|
|
shadow.appendChild(iframe);
|
|
|
|
|
iframeWin = iframe.contentWindow;
|
|
|
|
|
iframeDoc = iframe.contentDocument;
|
|
|
|
|
// 外部样式表
|
|
|
|
|
var link = document.createElement('link');
|
|
|
|
|
link.rel = 'stylesheet';
|
|
|
|
|
link.type = 'text/css';
|
|
|
|
|
link.href = createObjectURLWithTry(new Blob(['\ufeff', style.textContent], {
|
|
|
|
|
type: 'text/css;charset=UTF-8'
|
|
|
|
|
}));
|
2019-01-07 10:59:21 +00:00
|
|
|
|
// 多种方式最大化兼容:Content Security Policy
|
|
|
|
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
|
|
|
|
shadow.appendChild(style); // 内部样式表
|
|
|
|
|
shadow.appendChild(link); // 外部样式表
|
|
|
|
|
// 翻译图标加入 Shadow
|
2019-01-07 03:44:12 +00:00
|
|
|
|
shadow.appendChild(icon);
|
2019-01-04 11:07:50 +00:00
|
|
|
|
// 鼠标事件:防止选中的文本消失
|
|
|
|
|
document.addEventListener('mousedown', function (e) {
|
2019-01-07 10:59:21 +00:00
|
|
|
|
log('mousedown event:', e);
|
2020-01-08 04:31:58 +00:00
|
|
|
|
if (e.target === icon || (e.target.parentNode && e.target.parentNode === icon)) { // 点击了翻译图标
|
2019-01-04 11:07:50 +00:00
|
|
|
|
e.preventDefault();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
// 鼠标事件:防止选中的文本消失;显示、隐藏翻译图标
|
2019-08-01 10:05:38 +00:00
|
|
|
|
document.addEventListener('mouseup', showIcon);
|
|
|
|
|
// 选中变化事件
|
|
|
|
|
document.addEventListener('selectionchange', showIcon);
|
|
|
|
|
document.addEventListener('touchend', showIcon);
|
2019-01-16 12:45:52 +00:00
|
|
|
|
// 内容面板滚动事件
|
|
|
|
|
content.addEventListener('scroll', function (e) {
|
|
|
|
|
if (content.scrollHeight - content.scrollTop === content.clientHeight) {
|
|
|
|
|
log('scroll bottom', e);
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
} else if (content.scrollTop === 0) {
|
|
|
|
|
log('scroll top', e);
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
2019-01-07 10:59:21 +00:00
|
|
|
|
}
|
|
|
|
|
});
|
2019-01-04 11:07:50 +00:00
|
|
|
|
/**日志输出*/
|
|
|
|
|
function log() {
|
2019-01-16 13:01:02 +00:00
|
|
|
|
var debug = false;
|
2019-02-14 11:04:56 +00:00
|
|
|
|
if (!debug) {
|
2019-01-04 11:07:50 +00:00
|
|
|
|
return;
|
2019-02-14 11:04:56 +00:00
|
|
|
|
}
|
2019-01-04 11:07:50 +00:00
|
|
|
|
if (arguments) {
|
|
|
|
|
for (var i = 0; i < arguments.length; i++) {
|
|
|
|
|
console.log(arguments[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/**鼠标拖动*/
|
|
|
|
|
function Drag(element) {
|
|
|
|
|
this.dragging = false;
|
2019-01-09 10:48:36 +00:00
|
|
|
|
this.startDragTime = 0;
|
|
|
|
|
this.stopDragTime = 0;
|
2019-01-04 11:07:50 +00:00
|
|
|
|
this.mouseDownPositionX = 0;
|
|
|
|
|
this.mouseDownPositionY = 0;
|
2019-01-09 10:48:36 +00:00
|
|
|
|
this.elementOriginalLeft = parseInt(element.style.left);
|
|
|
|
|
this.elementOriginalTop = parseInt(element.style.top);
|
2019-01-04 11:07:50 +00:00
|
|
|
|
var ref = this;
|
|
|
|
|
this.startDrag = function (e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
ref.dragging = true;
|
2019-01-09 10:48:36 +00:00
|
|
|
|
ref.startDragTime = new Date().getTime();
|
2019-01-04 11:07:50 +00:00
|
|
|
|
ref.mouseDownPositionX = e.clientX;
|
|
|
|
|
ref.mouseDownPositionY = e.clientY;
|
|
|
|
|
ref.elementOriginalLeft = parseInt(element.style.left);
|
|
|
|
|
ref.elementOriginalTop = parseInt(element.style.top);
|
|
|
|
|
// set mousemove event
|
|
|
|
|
window.addEventListener('mousemove', ref.dragElement);
|
|
|
|
|
log('startDrag');
|
|
|
|
|
};
|
|
|
|
|
this.unsetMouseMove = function () {
|
|
|
|
|
// unset mousemove event
|
|
|
|
|
window.removeEventListener('mousemove', ref.dragElement);
|
|
|
|
|
};
|
|
|
|
|
this.stopDrag = function (e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
ref.dragging = false;
|
2019-01-09 10:48:36 +00:00
|
|
|
|
ref.stopDragTime = new Date().getTime();
|
2019-01-04 11:07:50 +00:00
|
|
|
|
ref.unsetMouseMove();
|
|
|
|
|
log('stopDrag');
|
|
|
|
|
};
|
|
|
|
|
this.dragElement = function (e) {
|
|
|
|
|
log('dragging');
|
2019-02-14 11:04:56 +00:00
|
|
|
|
if (!ref.dragging) {
|
2019-01-04 11:07:50 +00:00
|
|
|
|
return;
|
2019-02-14 11:04:56 +00:00
|
|
|
|
}
|
2019-01-04 11:07:50 +00:00
|
|
|
|
e.preventDefault();
|
|
|
|
|
// move element
|
|
|
|
|
element.style.left = ref.elementOriginalLeft + (e.clientX - ref.mouseDownPositionX) + 'px';
|
|
|
|
|
element.style.top = ref.elementOriginalTop + (e.clientY - ref.mouseDownPositionY) + 'px';
|
|
|
|
|
log('dragElement');
|
|
|
|
|
};
|
|
|
|
|
element.onmousedown = this.startDrag;
|
|
|
|
|
element.onmouseup = this.stopDrag;
|
|
|
|
|
}
|
2019-01-09 10:48:36 +00:00
|
|
|
|
/**是否拖动图标*/
|
|
|
|
|
function isDrag() {
|
2020-01-08 04:31:58 +00:00
|
|
|
|
return iconDrag.elementOriginalLeft !== parseInt(icon.style.left) ||
|
|
|
|
|
iconDrag.elementOriginalTop !== parseInt(icon.style.top);
|
2019-01-09 10:48:36 +00:00
|
|
|
|
}
|
|
|
|
|
/**强制结束拖动*/
|
|
|
|
|
function forceStopDrag() {
|
|
|
|
|
if (iconDrag) {
|
|
|
|
|
// 强制设置鼠标拖动事件结束,防止由于网页本身的其它鼠标事件冲突而导致没有侦测到:mouseup
|
|
|
|
|
iconDrag.dragging = false;
|
|
|
|
|
iconDrag.unsetMouseMove();
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-01-07 13:26:29 +00:00
|
|
|
|
/**是否包含汉字*/
|
2019-01-07 10:59:21 +00:00
|
|
|
|
function hasChineseByRange(str) {
|
2019-02-23 01:28:48 +00:00
|
|
|
|
return /[\u4e00-\u9fa5]/ig.test(str);
|
2019-01-07 10:59:21 +00:00
|
|
|
|
}
|
2019-01-16 12:45:52 +00:00
|
|
|
|
/**uuid*/
|
|
|
|
|
function uuid() {
|
|
|
|
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
|
|
|
var r = Math.random() * 16 | 0,
|
|
|
|
|
v = c == 'x' ? r : (r & 0x3 | 0x8);
|
|
|
|
|
return v.toString(16);
|
|
|
|
|
});
|
|
|
|
|
}
|
2019-01-07 10:59:21 +00:00
|
|
|
|
/**对象转 xml*/
|
|
|
|
|
function objToXml(obj) {
|
|
|
|
|
var xml = '';
|
|
|
|
|
for (var prop in obj) {
|
2019-01-23 10:40:19 +00:00
|
|
|
|
if (obj[prop] instanceof iframeWin.Function) {
|
2019-01-08 04:58:01 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-01-23 10:40:19 +00:00
|
|
|
|
xml += obj[prop] instanceof iframeWin.Array ? '' : '<' + prop + '>';
|
|
|
|
|
if (obj[prop] instanceof iframeWin.Array) {
|
2019-01-07 10:59:21 +00:00
|
|
|
|
for (var array in obj[prop]) {
|
2019-01-23 10:40:19 +00:00
|
|
|
|
if (obj[prop][array] instanceof iframeWin.Function) {
|
2019-01-08 04:58:01 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
xml += '<' + prop + '>';
|
2019-01-23 10:40:19 +00:00
|
|
|
|
xml += objToXml(new iframeWin.Object(obj[prop][array]));
|
2019-01-08 04:58:01 +00:00
|
|
|
|
xml += '</' + prop + '>';
|
2019-01-07 10:59:21 +00:00
|
|
|
|
}
|
2019-01-23 10:40:19 +00:00
|
|
|
|
} else if (obj[prop] instanceof iframeWin.Object) {
|
|
|
|
|
xml += objToXml(new iframeWin.Object(obj[prop]));
|
2019-01-07 10:59:21 +00:00
|
|
|
|
} else {
|
|
|
|
|
xml += obj[prop];
|
|
|
|
|
}
|
2019-01-23 10:40:19 +00:00
|
|
|
|
xml += obj[prop] instanceof iframeWin.Array ? '' : '</' + prop + '>';
|
2019-01-07 10:59:21 +00:00
|
|
|
|
}
|
2020-01-08 04:31:58 +00:00
|
|
|
|
xml = xml.replace(/<\/?[0-9]{1,}>/g, '');
|
2019-01-07 10:59:21 +00:00
|
|
|
|
return xml
|
|
|
|
|
}
|
|
|
|
|
/**xml 转 html*/
|
|
|
|
|
function xmlToHtml(xml, tag) {
|
2019-01-08 04:58:01 +00:00
|
|
|
|
return xml.replace(/<([^/]+?)>/g, '<' + tag + ' class="$1">')
|
2019-01-07 10:59:21 +00:00
|
|
|
|
.replace(/<\/(.+?)>/g, '</' + tag + '>');
|
|
|
|
|
}
|
2019-01-16 12:45:52 +00:00
|
|
|
|
// html 字符串转 DOM
|
2019-02-23 01:28:48 +00:00
|
|
|
|
function htmlToDom(html) {
|
2019-01-16 12:45:52 +00:00
|
|
|
|
var div = document.createElement('div');
|
2019-02-23 01:28:48 +00:00
|
|
|
|
div.innerHTML = html;
|
2019-01-16 12:45:52 +00:00
|
|
|
|
return div;
|
|
|
|
|
}
|
|
|
|
|
/**清理 html*/
|
2019-02-23 01:28:48 +00:00
|
|
|
|
function cleanHtml(html) {
|
|
|
|
|
html = html.replace(/<script[\s\S]*?<\/script>/ig, '')
|
2019-01-16 12:45:52 +00:00
|
|
|
|
.replace(/<link[\s\S]*?>/ig, '')
|
|
|
|
|
.replace(/<style[\s\S]*?<\/style>/ig, '')
|
2019-02-23 01:28:48 +00:00
|
|
|
|
.replace(/<img[\s\S]*?>/ig, '');
|
|
|
|
|
html = cleanAttr(html, 'on[a-z]*');
|
|
|
|
|
return html;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 清理指定属性(忽略大小写)
|
|
|
|
|
* @param attr 支持正则表示(如“on[a-z]*”,表示清理“on”开头的属性:onclick、onmove等)
|
|
|
|
|
*/
|
|
|
|
|
function cleanAttr(html, attr) {
|
|
|
|
|
var regex = ' ' + attr + '="([^"<>]*)"';
|
|
|
|
|
return html.replace(new RegExp(regex, 'ig'), '');
|
2019-01-16 12:45:52 +00:00
|
|
|
|
}
|
2019-01-23 10:40:19 +00:00
|
|
|
|
/**带异常处理的 createObjectURL*/
|
|
|
|
|
function createObjectURLWithTry(blob) {
|
|
|
|
|
try {
|
|
|
|
|
return iframeWin.URL.createObjectURL(blob);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
log(error);
|
|
|
|
|
}
|
|
|
|
|
return '';
|
|
|
|
|
}
|
2019-01-04 11:07:50 +00:00
|
|
|
|
/**ajax 跨域访问公共方法*/
|
2019-01-06 06:35:25 +00:00
|
|
|
|
function ajax(url, success, error, obj) {
|
2019-02-14 11:04:56 +00:00
|
|
|
|
if (!!!obj) {
|
2019-01-06 06:35:25 +00:00
|
|
|
|
obj = {};
|
2019-02-14 11:04:56 +00:00
|
|
|
|
}
|
|
|
|
|
if (!!!obj.method) {
|
2019-01-06 06:35:25 +00:00
|
|
|
|
obj.method = 'GET';
|
2019-02-14 11:04:56 +00:00
|
|
|
|
}
|
2019-01-04 11:07:50 +00:00
|
|
|
|
// >>>因为Tampermonkey跨域访问(a.com)时会自动携带对应域名(a.com)的对应cookie
|
|
|
|
|
// 不会携带当前域名的cookie
|
|
|
|
|
// 所以,GM_xmlhttpRequest【不存在】cookie跨域访问安全性问题
|
2019-01-16 12:45:52 +00:00
|
|
|
|
// 以下设置的cookie会添加到已有cookie的后面<<<
|
2019-02-14 11:04:56 +00:00
|
|
|
|
if (!!!obj.headers) {
|
2019-01-06 06:35:25 +00:00
|
|
|
|
obj.headers = {
|
2019-01-04 11:07:50 +00:00
|
|
|
|
'cookie': ''
|
|
|
|
|
};
|
2019-02-14 11:04:56 +00:00
|
|
|
|
}
|
2019-01-04 11:07:50 +00:00
|
|
|
|
GM_xmlhttpRequest({
|
2019-01-06 06:35:25 +00:00
|
|
|
|
method: obj.method,
|
2019-01-04 11:07:50 +00:00
|
|
|
|
url: url,
|
2019-01-06 06:35:25 +00:00
|
|
|
|
headers: obj.headers,
|
|
|
|
|
responseType: obj.responseType,
|
|
|
|
|
data: obj.data,
|
2019-01-04 11:07:50 +00:00
|
|
|
|
onload: function (res) {
|
2019-01-06 06:35:25 +00:00
|
|
|
|
success(res.responseText, res, obj);
|
2019-01-04 11:07:50 +00:00
|
|
|
|
},
|
|
|
|
|
onerror: function (res) {
|
2019-01-06 06:35:25 +00:00
|
|
|
|
error(res.responseText, res, obj);
|
2019-01-16 12:45:52 +00:00
|
|
|
|
},
|
|
|
|
|
onabort: function (res) {
|
|
|
|
|
error('the request was aborted', res, obj);
|
|
|
|
|
},
|
|
|
|
|
ontimeout: function (res) {
|
|
|
|
|
error('the request failed due to a timeout', res, obj);
|
|
|
|
|
},
|
|
|
|
|
onreadystatechange: function () {
|
|
|
|
|
log('ajax:', arguments);
|
2019-01-04 11:07:50 +00:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2019-02-17 01:52:33 +00:00
|
|
|
|
/**放入翻译引擎结果集*/
|
|
|
|
|
function putEngineResult(id, value, time) {
|
|
|
|
|
if (time == engineTriggerTime) { // 是本次触发的异步ajax请求
|
|
|
|
|
engineResult[id] = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-14 10:12:11 +00:00
|
|
|
|
/**初始化面板*/
|
|
|
|
|
function initContent() {
|
|
|
|
|
contentList.innerHTML = ''; // 清空翻译内容列表
|
2020-01-08 04:31:58 +00:00
|
|
|
|
|
2019-06-14 10:12:11 +00:00
|
|
|
|
// 初始化翻译引擎结构(此时内容暂未填充)
|
|
|
|
|
idsType.forEach(function (id) {
|
|
|
|
|
if (id in idsExtension.names) {
|
|
|
|
|
var engine = document.createElement('tr-engine');
|
|
|
|
|
engine.setAttribute('data-id', id);
|
|
|
|
|
engine.style.display = 'none'; // 暂无内容默认隐藏
|
|
|
|
|
// 标题
|
|
|
|
|
if (idsExtension.names[id]) {
|
|
|
|
|
var title = document.createElement('a');
|
|
|
|
|
title.innerHTML = idsExtension.names[id];
|
|
|
|
|
title.setAttribute('class', 'title');
|
|
|
|
|
var href = 'javascript:void(0)';
|
|
|
|
|
if (idsExtension.links[id]) {
|
|
|
|
|
var link = idsExtension.links[id];
|
|
|
|
|
if (typeof link == 'string') {
|
|
|
|
|
if (link.length > 0) {
|
|
|
|
|
href = link.replace(/%q%/ig, encodeURIComponent(selected));
|
|
|
|
|
}
|
|
|
|
|
} else if (typeof link == 'function') {
|
|
|
|
|
var fnHref = link(selected);
|
|
|
|
|
if (fnHref.length > 0) {
|
|
|
|
|
href = fnHref;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
title.setAttribute('rel', 'noreferrer noopener');
|
|
|
|
|
title.setAttribute('target', '_blank');
|
|
|
|
|
title.setAttribute('href', href);
|
|
|
|
|
title.setAttribute('title', '打开源网站');
|
|
|
|
|
engine.appendChild(title);
|
|
|
|
|
}
|
|
|
|
|
contentList.appendChild(engine);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2019-01-04 11:07:50 +00:00
|
|
|
|
/**显示内容面板*/
|
2019-02-23 01:28:48 +00:00
|
|
|
|
function displayContent() {
|
2019-07-03 04:10:18 +00:00
|
|
|
|
var panelWidth = iconWidth + 8; // icon 展开后总宽度(8:冗余距离)
|
|
|
|
|
var panelHeight = iconHeight + 8; // icon 展开后总高度(8:冗余距离)
|
2019-02-23 01:28:48 +00:00
|
|
|
|
// 计算位置
|
|
|
|
|
log('content position:',
|
|
|
|
|
'window.scrollY', window.scrollY,
|
|
|
|
|
'document.documentElement.scrollTop', document.documentElement.scrollTop,
|
|
|
|
|
'document.body.scrollTop', document.body.scrollTop,
|
|
|
|
|
'window.innerHeight', window.innerHeight,
|
|
|
|
|
'document.documentElement.clientHeight', document.documentElement.clientHeight,
|
|
|
|
|
'document.body.clientHeight', document.body.clientHeight,
|
|
|
|
|
'icon.style.top', icon.style.top,
|
|
|
|
|
'window.scrollX', window.scrollX,
|
|
|
|
|
'document.documentElement.scrollLeft', document.documentElement.scrollLeft,
|
|
|
|
|
'document.body.scrollLeft', document.body.scrollLeft,
|
|
|
|
|
'window.innerWidth', window.innerWidth,
|
|
|
|
|
'document.documentElement.clientWidth', document.documentElement.clientWidth,
|
|
|
|
|
'document.body.clientWidth', document.body.clientWidth,
|
|
|
|
|
'icon.style.left', icon.style.left
|
|
|
|
|
);
|
2019-03-14 10:44:25 +00:00
|
|
|
|
var scrollTop = Math.max(parseInt(document.documentElement.scrollTop), parseInt(document.body.scrollTop));
|
|
|
|
|
var scrollLeft = Math.max(parseInt(document.documentElement.scrollLeft), parseInt(document.body.scrollLeft));
|
2019-03-28 10:09:57 +00:00
|
|
|
|
var clientHeight = [parseInt(document.documentElement.clientHeight), parseInt(document.body.clientHeight)].filter(function (x) {
|
|
|
|
|
return x <= parseInt(window.innerHeight);
|
|
|
|
|
}).sort(function (a, b) {
|
|
|
|
|
return a > b ? -1 : (a == b ? 0 : 1);
|
|
|
|
|
})[0]; // 找出最大值且小于等于 window 的高度
|
2019-04-09 13:02:42 +00:00
|
|
|
|
if (!clientHeight) { // 网页缩放导致可能数组为空([0] 为 undefined)
|
|
|
|
|
clientHeight = parseInt(window.innerHeight);
|
|
|
|
|
}
|
2019-03-28 10:09:57 +00:00
|
|
|
|
var clientWidth = [parseInt(document.documentElement.clientWidth), parseInt(document.body.clientWidth)].filter(function (x) {
|
|
|
|
|
return x <= parseInt(window.innerWidth);
|
|
|
|
|
}).sort(function (a, b) {
|
|
|
|
|
return a > b ? -1 : (a == b ? 0 : 1);
|
|
|
|
|
})[0]; // 找出最大值且小于等于 window 的宽度
|
2019-04-09 13:02:42 +00:00
|
|
|
|
if (!clientWidth) { // 网页缩放导致可能数组为空([0] 为 undefined)
|
|
|
|
|
clientWidth = parseInt(window.innerWidth);
|
|
|
|
|
}
|
2019-06-11 04:27:31 +00:00
|
|
|
|
// 设置新的位置
|
2019-03-28 10:09:57 +00:00
|
|
|
|
var iconNewTop = -1;
|
2019-08-09 10:11:45 +00:00
|
|
|
|
if (parseInt(icon.style.top) < scrollTop) { // 面板在滚动条顶部可见部分之上(隐藏了部分或全部)
|
2019-02-23 01:28:48 +00:00
|
|
|
|
log('Y adjust top');
|
2019-08-09 10:11:45 +00:00
|
|
|
|
iconNewTop = scrollTop; // 设置为滚动条顶部可见部分位置
|
|
|
|
|
} else if (parseInt(icon.style.top) + panelHeight > scrollTop + clientHeight) { // 面板在滚动条滚到最底部时之下(隐藏了部分或全部)
|
2019-02-23 01:28:48 +00:00
|
|
|
|
log('Y adjust bottom');
|
2019-08-09 10:11:45 +00:00
|
|
|
|
iconNewTop = parseInt(scrollTop + clientHeight - panelHeight); // 设置面板底部不超过滚动条滚到最底部时可见部分位置
|
|
|
|
|
if (iconNewTop < scrollTop) { // 如果此时又出现:面板在滚动条顶部可见部分之上(隐藏了部分或全部)
|
|
|
|
|
log('Y adjust bottom top');
|
|
|
|
|
iconNewTop = scrollTop; // 设置为滚动条顶部可见部分位置
|
|
|
|
|
}
|
2019-02-23 01:28:48 +00:00
|
|
|
|
}
|
2019-03-28 10:09:57 +00:00
|
|
|
|
if (iconNewTop != -1 && Math.abs(iconNewTop - parseInt(icon.style.top)) <= panelHeight) {
|
|
|
|
|
log('Y set iconNewTop', iconNewTop);
|
|
|
|
|
icon.style.top = iconNewTop + 'px';
|
|
|
|
|
}
|
|
|
|
|
var iconNewLeft = -1;
|
2019-03-14 10:44:25 +00:00
|
|
|
|
if (parseInt(icon.style.left) < scrollLeft) {
|
2019-02-23 01:28:48 +00:00
|
|
|
|
log('X adjust left');
|
2019-03-28 10:09:57 +00:00
|
|
|
|
iconNewLeft = scrollLeft;
|
|
|
|
|
} else if (parseInt(icon.style.left) + panelWidth > scrollLeft + clientWidth) {
|
2019-02-23 01:28:48 +00:00
|
|
|
|
log('X adjust right');
|
2019-03-28 10:09:57 +00:00
|
|
|
|
iconNewLeft = parseInt(scrollLeft + clientWidth - panelWidth);
|
2019-08-09 10:11:45 +00:00
|
|
|
|
if (iconNewLeft < scrollLeft) {
|
|
|
|
|
log('X adjust right left');
|
|
|
|
|
iconNewLeft = scrollLeft;
|
|
|
|
|
}
|
2019-03-28 10:09:57 +00:00
|
|
|
|
}
|
|
|
|
|
if (iconNewLeft != -1 && Math.abs(iconNewLeft - parseInt(icon.style.left)) <= panelWidth) {
|
|
|
|
|
log('X set iconNewLeft', iconNewLeft);
|
|
|
|
|
icon.style.left = iconNewLeft + 'px';
|
2019-02-23 01:28:48 +00:00
|
|
|
|
}
|
2019-04-16 04:50:01 +00:00
|
|
|
|
content.scrollTop = 0; // 翻译面板滚动到顶端
|
|
|
|
|
content.scrollLeft = 0; // 翻译面板滚动到左端
|
2019-02-23 01:28:48 +00:00
|
|
|
|
content.style.display = 'block';
|
|
|
|
|
}
|
2019-04-16 04:50:01 +00:00
|
|
|
|
/**内容面板填充数据*/
|
|
|
|
|
function showContent() {
|
2019-04-16 06:16:26 +00:00
|
|
|
|
// 填充已有结果集引擎内容
|
2019-04-16 04:50:01 +00:00
|
|
|
|
idsType.forEach(function (id) {
|
2019-04-16 11:25:36 +00:00
|
|
|
|
if (engineResult[id] && !(id in idsExtension.lowerCaseMap)) { // 跳过小写的内容填充
|
2019-04-16 04:50:01 +00:00
|
|
|
|
var engine = contentList.querySelector('tr-engine[data-id="' + id + '"]');
|
|
|
|
|
if (engine) {
|
|
|
|
|
engine.appendChild(engineResult[id]);
|
2019-04-16 11:25:36 +00:00
|
|
|
|
engine.removeAttribute('data-id');
|
2019-04-16 04:50:01 +00:00
|
|
|
|
engine.style.display = 'block';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
2019-04-16 06:16:26 +00:00
|
|
|
|
// 比较大小写内容
|
|
|
|
|
for (var id in idsExtension.lowerCaseMap) {
|
|
|
|
|
if (engineResult[id] &&
|
|
|
|
|
engineResult[idsExtension.lowerCaseMap[id]] &&
|
2019-04-16 11:25:36 +00:00
|
|
|
|
engineResult[id].innerHTML != engineResult[idsExtension.lowerCaseMap[id]].innerHTML &&
|
|
|
|
|
engineResult[id].innerHTML.toLowerCase() != engineResult[idsExtension.lowerCaseMap[id]].innerHTML.toLowerCase()) {
|
2019-04-16 06:16:26 +00:00
|
|
|
|
var engine = contentList.querySelector('tr-engine[data-id="' + id + '"]');
|
|
|
|
|
if (engine) {
|
2019-04-16 11:25:36 +00:00
|
|
|
|
engine.appendChild(engineResult[id]);
|
|
|
|
|
engine.removeAttribute('data-id');
|
|
|
|
|
engine.style.display = 'block';
|
2019-04-16 06:16:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-01-04 11:07:50 +00:00
|
|
|
|
}
|
2019-01-08 10:15:14 +00:00
|
|
|
|
/**隐藏翻译引擎指示器*/
|
|
|
|
|
function engineActivateHide() {
|
|
|
|
|
icon.querySelectorAll('img[activate]').forEach(function (ele) {
|
|
|
|
|
ele.removeAttribute('activate');
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
/**显示翻译引擎指示器*/
|
|
|
|
|
function engineActivateShow() {
|
|
|
|
|
engineActivateHide();
|
2019-03-28 10:09:57 +00:00
|
|
|
|
icon.querySelector('img[icon-id="' + engineId + '"]').setAttribute('activate', 'activate');
|
2019-01-08 10:15:14 +00:00
|
|
|
|
}
|
2019-08-01 10:05:38 +00:00
|
|
|
|
/**显示 icon*/
|
|
|
|
|
function showIcon(e) {
|
|
|
|
|
log('showIcon event:', e);
|
|
|
|
|
var offsetX = 4; // 横坐标翻译图标偏移
|
|
|
|
|
var offsetY = 8; // 纵坐标翻译图标偏移
|
|
|
|
|
// 更新翻译图标 X、Y 坐标
|
|
|
|
|
if (e.pageX && e.pageY) { // 鼠标
|
|
|
|
|
log('mouse pageX/Y');
|
|
|
|
|
pageX = e.pageX;
|
|
|
|
|
pageY = e.pageY;
|
|
|
|
|
}
|
|
|
|
|
if (e.changedTouches) { // 触屏
|
|
|
|
|
if (e.changedTouches.length > 0) { // 多点触控选取第 1 个
|
|
|
|
|
log('touch pageX/Y');
|
|
|
|
|
pageX = e.changedTouches[0].pageX;
|
|
|
|
|
pageY = e.changedTouches[0].pageY;
|
|
|
|
|
// 触屏修改翻译图标偏移(Android、iOS 选中后的动作菜单一般在当前文字顶部,翻译图标则放到底部)
|
|
|
|
|
offsetX = -26; // 单个翻译图标块宽度
|
|
|
|
|
offsetY = 16 * 3; // 一般字体高度的 3 倍,距离系统自带动作菜单、选择光标太近会导致无法点按
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log('selected:' + selected + ', pageX:' + pageX + ', pageY:' + pageY)
|
|
|
|
|
if (e.target == icon || (e.target.parentNode && e.target.parentNode == icon)) { // 点击了翻译图标
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
selected = window.getSelection().toString().trim(); // 当前选中文本
|
|
|
|
|
log('selected:' + selected + ', icon display:' + icon.style.display);
|
2020-01-08 04:31:58 +00:00
|
|
|
|
if (selected && icon.style.display !== 'block' && /[\u30a1-\u30f6\u3041-\u3093\uFF00-\uFFFF\u4e00-\u9fa5]/.test(selected) && pageX && pageY) { // 显示翻译图标
|
2019-08-01 10:05:38 +00:00
|
|
|
|
log('show icon');
|
|
|
|
|
icon.style.top = pageY + offsetY + 'px';
|
|
|
|
|
icon.style.left = pageX + offsetX + 'px';
|
|
|
|
|
icon.style.display = 'block';
|
|
|
|
|
// 兼容部分 Content Security Policy
|
|
|
|
|
icon.style.position = 'absolute';
|
|
|
|
|
icon.style.zIndex = zIndex;
|
|
|
|
|
} else if (!selected) { // 隐藏翻译图标
|
|
|
|
|
log('hide icon');
|
|
|
|
|
hideIcon();
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-01-16 12:45:52 +00:00
|
|
|
|
/**隐藏 icon*/
|
|
|
|
|
function hideIcon() {
|
|
|
|
|
icon.style.display = 'none';
|
2019-02-27 11:00:28 +00:00
|
|
|
|
icon.removeAttribute('activate'); // 标注面板关闭
|
2019-01-16 12:45:52 +00:00
|
|
|
|
content.style.display = 'none';
|
|
|
|
|
engineId = '';
|
2019-02-17 01:52:33 +00:00
|
|
|
|
engineTriggerTime = 0;
|
2019-08-01 10:05:38 +00:00
|
|
|
|
pageX = 0;
|
|
|
|
|
pageY = 0;
|
2019-04-16 04:50:01 +00:00
|
|
|
|
engineActivateHide();
|
2019-03-29 04:20:30 +00:00
|
|
|
|
audioCache = {};
|
2019-01-16 12:45:52 +00:00
|
|
|
|
engineResult = {};
|
|
|
|
|
forceStopDrag();
|
|
|
|
|
}
|
|
|
|
|
/**发音*/
|
|
|
|
|
function play(obj) {
|
2019-03-29 04:20:30 +00:00
|
|
|
|
if (obj.url in audioCache) { // 查找缓存
|
|
|
|
|
log('audio in cache', obj, audioCache);
|
2019-04-14 06:27:20 +00:00
|
|
|
|
playArrayBuffer(audioCache[obj.url]); // 播放
|
2019-03-30 00:39:24 +00:00
|
|
|
|
} else {
|
|
|
|
|
ajax(obj.url, function (rst, res) {
|
|
|
|
|
audioCache[obj.url] = res.response; // 放入缓存
|
2019-04-14 06:27:20 +00:00
|
|
|
|
playArrayBuffer(audioCache[obj.url]); // 播放
|
2019-03-30 00:39:24 +00:00
|
|
|
|
}, function (rst) {
|
|
|
|
|
log(rst);
|
|
|
|
|
}, {
|
2019-04-14 06:27:20 +00:00
|
|
|
|
responseType: 'arraybuffer'
|
2019-03-30 00:39:24 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
2019-01-06 06:35:25 +00:00
|
|
|
|
}
|
2019-04-14 06:27:20 +00:00
|
|
|
|
/**播放 ArrayBuffer 音频*/
|
|
|
|
|
function playArrayBuffer(arrayBuffer) {
|
|
|
|
|
var context = new iframeWin.AudioContext() || new iframeWin.webkitAudioContext();
|
|
|
|
|
context.decodeAudioData(arrayBuffer.slice(0), function (audioBuffer) { // `slice(0)`克隆一份(`decodeAudioData`后原数组清空)
|
|
|
|
|
var bufferSource = context.createBufferSource();
|
|
|
|
|
bufferSource.buffer = audioBuffer;
|
|
|
|
|
bufferSource.connect(context.destination);
|
|
|
|
|
bufferSource.start();
|
|
|
|
|
});
|
|
|
|
|
}
|
2019-01-16 12:45:52 +00:00
|
|
|
|
/**得到发音按钮*/
|
|
|
|
|
function getPlayButton(obj) {
|
|
|
|
|
var type = document.createElement('a');
|
|
|
|
|
type.innerHTML = obj.name;
|
|
|
|
|
type.setAttribute('href', 'javascript:void(0)');
|
|
|
|
|
type.setAttribute('class', 'audio-button');
|
2019-02-27 11:00:28 +00:00
|
|
|
|
type.setAttribute('title', '点击发音');
|
2019-01-16 12:45:52 +00:00
|
|
|
|
type.addEventListener('mouseup', function () {
|
|
|
|
|
play(obj);
|
2019-01-06 06:35:25 +00:00
|
|
|
|
});
|
2019-01-16 12:45:52 +00:00
|
|
|
|
return type;
|
2019-01-06 06:35:25 +00:00
|
|
|
|
}
|
2019-01-16 12:45:52 +00:00
|
|
|
|
/**沪江小D排版*/
|
|
|
|
|
function parseHjenglish(rst) {
|
|
|
|
|
var dom = document.createElement('div');
|
|
|
|
|
dom.setAttribute('class', ids.HJENGLISH);
|
2020-01-08 04:31:58 +00:00
|
|
|
|
var parser = new DOMParser(), doc = parser.parseFromString(rst, 'text/html'),
|
|
|
|
|
content = doc.getElementsByClassName('word-details')[0];
|
|
|
|
|
dom.appendChild(content);
|
|
|
|
|
/*try {
|
2019-01-16 12:45:52 +00:00
|
|
|
|
var doc = htmlToDom(cleanHtml(rst));
|
2019-02-15 05:38:48 +00:00
|
|
|
|
var label = doc.querySelector('.word-details-item-content header');
|
2019-01-16 12:45:52 +00:00
|
|
|
|
var entry = doc.querySelector('.word-text h2');
|
|
|
|
|
var collins = doc.querySelector('div[data-id="detail"] .word-details-item-content .detail-groups');
|
|
|
|
|
if (entry) {
|
|
|
|
|
var entryDom = document.createElement('div');
|
|
|
|
|
entryDom.setAttribute('class', 'entry');
|
|
|
|
|
entryDom.innerHTML = entry.innerHTML;
|
|
|
|
|
dom.appendChild(entryDom);
|
|
|
|
|
if (collins) {
|
2019-02-15 05:38:48 +00:00
|
|
|
|
if (label) {
|
|
|
|
|
var regex = /(《.*?》)/ig;
|
|
|
|
|
var match = regex.exec(label.innerHTML);
|
|
|
|
|
if (match && match[1]) {
|
|
|
|
|
dom.appendChild(htmlToDom('<div>' + match[1] + '</div>'));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-01-16 12:45:52 +00:00
|
|
|
|
dom.appendChild(collins);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
log(error);
|
|
|
|
|
dom.appendChild(htmlToDom(error));
|
2020-01-08 04:31:58 +00:00
|
|
|
|
}*/
|
2019-01-16 12:45:52 +00:00
|
|
|
|
return dom;
|
2019-01-04 11:07:50 +00:00
|
|
|
|
}
|
2019-01-09 10:48:36 +00:00
|
|
|
|
/**
|
|
|
|
|
* 谷歌翻译 token 计算
|
|
|
|
|
* https://github.com/hujingshuang/MTrans
|
|
|
|
|
* */
|
|
|
|
|
function token(a) {
|
|
|
|
|
var k = "";
|
|
|
|
|
var b = 406644;
|
|
|
|
|
var b1 = 3293161072;
|
|
|
|
|
|
|
|
|
|
var jd = ".";
|
|
|
|
|
var sb = "+-a^+6";
|
|
|
|
|
var Zb = "+-3^+b+-f";
|
|
|
|
|
|
|
|
|
|
for (var e = [], f = 0, g = 0; g < a.length; g++) {
|
|
|
|
|
var m = a.charCodeAt(g);
|
|
|
|
|
128 > m ? e[f++] = m : (2048 > m ? e[f++] = m >> 6 | 192 : (55296 == (m & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (m = 65536 + ((m & 1023) << 10) + (a.charCodeAt(++g) & 1023), e[f++] = m >> 18 | 240, e[f++] = m >> 12 & 63 | 128) : e[f++] = m >> 12 | 224, e[f++] = m >> 6 & 63 | 128), e[f++] = m & 63 | 128)
|
|
|
|
|
}
|
|
|
|
|
a = b;
|
|
|
|
|
for (f = 0; f < e.length; f++) a += e[f],
|
|
|
|
|
a = RL(a, sb);
|
|
|
|
|
a = RL(a, Zb);
|
|
|
|
|
a ^= b1 || 0;
|
|
|
|
|
0 > a && (a = (a & 2147483647) + 2147483648);
|
|
|
|
|
a %= 1E6;
|
|
|
|
|
return a.toString() + jd + (a ^ b)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function RL(a, b) {
|
|
|
|
|
var t = "a";
|
|
|
|
|
var Yb = "+";
|
|
|
|
|
for (var c = 0; c < b.length - 2; c += 3) {
|
|
|
|
|
var d = b.charAt(c + 2),
|
|
|
|
|
d = d >= t ? d.charCodeAt(0) - 87 : Number(d),
|
|
|
|
|
d = b.charAt(c + 1) == Yb ? a >>> d : a << d;
|
|
|
|
|
a = b.charAt(c) == Yb ? a + d & 4294967295 : a ^ d
|
|
|
|
|
}
|
|
|
|
|
return a
|
|
|
|
|
}
|
2019-01-04 11:07:50 +00:00
|
|
|
|
})();
|