'use strict';
var css = "._panel_nvbn4_1 {\n position: fixed;\n max-width: 300px;\n z-index: 10000;\n}\n ._panel_nvbn4_1 * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n._body_nvbn4_11 {\n position: relative;\n padding: 8px;\n border-radius: 4px;\n border: 1px solid #eaeaea;\n line-height: 24px;\n color: #555;\n background-color: #fff;\n font-family: monospace, consolas;\n font-size: 14px;\n text-align: left;\n word-break: break-all;\n}\n._header_nvbn4_24 {\n padding: 0 0 8px;\n border-bottom: 1px dashed #aaa;\n color: #333;\n}\n._header_nvbn4_24 > a {\n margin-left: 8px;\n color: #7cbef0;\n cursor: pointer;\n font-size: 13px;\n }\n._detail_nvbn4_35 {\n margin: 8px 0 0;\n line-height: 22px;\n list-style: none;\n font-size: 13px;\n}\n._detail_nvbn4_35 > li {\n font-size: 13px;\n line-height: 26px;\n }\n";
var classMap = {
"panel": "_panel_nvbn4_1",
"body": "_body_nvbn4_11",
"header": "_header_nvbn4_24",
"detail": "_detail_nvbn4_35"
};
// ==UserScript==
// @name translator
// @namespace https://lufei.so
// @supportURL https://github.com/intellilab/translator.user.js
// @description 划词翻译
// @version 1.5.11
// @run-at document-start
// @grant GM_addStyle
// @grant GM_xmlhttpRequest
// @include *
// ==/UserScript==
GM_addStyle(css);
var translator = initialize();
function createElement(tagName, props, attrs) {
var el = document.createElement(tagName);
if (props) {
Object.keys(props).forEach(function (key) {
el[key] = props[key];
});
}
if (attrs) {
Object.keys(attrs).forEach(function (key) {
el.setAttribute(key, attrs[key]);
});
}
return el;
}
function render(data) {
var body = translator.body,
audio = translator.audio;
body.innerHTML = '';
var basic = data.basic,
query = data.query,
translation = data.translation;
if (basic) {
var explains = basic.explains,
us = basic['us-phonetic'],
uk = basic['uk-phonetic'];
var noPhonetic = '♥';
var header = createElement('div', {
className: classMap.header
});
header.appendChild(createElement('span', {
textContent: query
}));
header.appendChild(createElement('a', {
innerHTML: `uk: [${uk || noPhonetic}]`
}, {
'data-type': 1
}));
header.appendChild(createElement('a', {
innerHTML: `us: [${us || noPhonetic}]`
}, {
'data-type': 2
}));
header.appendChild(createElement('a', {
textContent: '详情'
}, {
target: '_blank',
href: `http://dict.youdao.com/search?q=${encodeURIComponent(query)}`
}));
body.appendChild(header);
header.addEventListener('click', function (e) {
var type = e.target.dataset.type;
if (type) {
audio.src = `http://dict.youdao.com/dictvoice?audio=${encodeURIComponent(query)}&type=${type}`;
}
});
if (explains) {
var ul = createElement('ul', {
className: classMap.detail
});
for (var i = 0; i < explains.length; i += 1) {
var li = createElement('li', {
innerHTML: explains[i]
});
ul.appendChild(li);
}
body.appendChild(ul);
}
} else if (translation) {
var div = createElement('div', {
innerHTML: translation[0]
});
body.appendChild(div);
}
}
function translate(e) {
var sel = window.getSelection();
var text = sel.toString();
if (/^\s*$/.test(text)) return;
var _document = document,
activeElement = _document.activeElement;
if (['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) < 0 && !activeElement.contains(sel.getRangeAt(0).startContainer)) return;
var query = {
type: 'data',
doctype: 'json',
version: '1.1',
relatedUrl: 'http://fanyi.youdao.com/',
keyfrom: 'fanyiweb',
key: null,
translate: 'on',
q: text,
ts: Date.now()
};
var qs = Object.keys(query).map(function (key) {
return `${encodeURIComponent(key)}=${encodeURIComponent(query[key])}`;
}).join('&');
GM_xmlhttpRequest({
method: 'GET',
url: `https://fanyi.youdao.com/openapi.do?${qs}`,
onload(res) {
var data = JSON.parse(res.responseText);
if (!data.errorCode) {
render(data);
var panel = translator.panel;
var _window = window,
innerWidth = _window.innerWidth,
innerHeight = _window.innerHeight;
if (e.clientY > innerHeight * 0.5) {
panel.style.top = 'auto';
panel.style.bottom = `${innerHeight - e.clientY + 10}px`;
} else {
panel.style.top = `${e.clientY + 10}px`;
panel.style.bottom = 'auto';
}
if (e.clientX > innerWidth * 0.5) {
panel.style.left = 'auto';
panel.style.right = `${innerWidth - e.clientX}px`;
} else {
panel.style.left = `${e.clientX}px`;
panel.style.right = 'auto';
}
document.body.appendChild(panel);
}
}
});
}
function debounce(func, delay) {
var timer;
function exec() {
timer = null;
func.apply(void 0, arguments);
}
return function () {
if (timer) clearTimeout(timer);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
timer = setTimeout.apply(void 0, [exec, delay].concat(args));
};
}
function initialize() {
var audio = createElement('audio', {
autoplay: true
});
var panel = createElement('div', {
className: classMap.panel
});
var panelBody = createElement('div', {
className: classMap.body
});
panel.appendChild(panelBody);
var debouncedTranslate = debounce(translate);
var isSelecting;
document.addEventListener('mousedown', function (e) {
isSelecting = false;
if (panel.contains(e.target)) return;
if (panel.parentNode) panel.parentNode.removeChild(panel);
panelBody.innerHTML = '';
}, true);
document.addEventListener('mousemove', function () {
isSelecting = true;
}, true);
document.addEventListener('mouseup', function (e) {
if (panel.contains(e.target) || !isSelecting) return;
debouncedTranslate(e);
}, true);
document.addEventListener('dblclick', function (e) {
if (panel.contains(e.target)) return;
debouncedTranslate(e);
}, true);
return {
audio,
panel,
body: panelBody
};
}