translator

划词翻译

当前为 2016-08-30 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name translator
  3. // @namespace https://lufei.so
  4. // @supportURL https://github.com/intellilab/translator.user.js
  5. // @description 划词翻译
  6. // @version 1.5.5
  7. // @run-at document-start
  8. // @grant GM_addStyle
  9. // @grant GM_xmlhttpRequest
  10. // ==/UserScript==
  11.  
  12. function play(query, type) {
  13. audio.src = 'http://dict.youdao.com/dictvoice?audio=' + window.encodeURIComponent(query) + '&type=' + type
  14. }
  15. function htmlEntities(s) {
  16. var o = {
  17. '<': '&lt;',
  18. '&': '&amp;',
  19. }
  20. return s.replace(/[<&]/g, function (c) {
  21. return o[c]
  22. })
  23. }
  24. function render(o) {
  25. // variable
  26. var us, uk, x, i
  27. // element
  28. var header, explains, web, translation
  29. if (o.errorCode) return
  30. panelBody.innerHTML = ''
  31. if (o.basic) {
  32. us = htmlEntities(o.basic['us-phonetic'] || '')
  33. uk = htmlEntities(o.basic['uk-phonetic'] || '')
  34. query = o.query || ''
  35. header = document.createElement('div')
  36. header.className = randKey + ' ' + randKey + '-header'
  37. header.innerHTML =
  38. '<span style="color: #333">' + htmlEntities(query) + '</span>' +
  39. '<span data-type="1">uk:[' + uk + ']</span>' +
  40. '<span data-type="2">us:[' + us + ']</span>'
  41. panelBody.appendChild(header)
  42. header.addEventListener('click', function(e) {
  43. e.target.dataset.type && play(query, e.target.dataset.type)
  44. })
  45. if (o.basic.explains) {
  46. explains = document.createElement('ul')
  47. explains.className = randKey + ' ' + randKey + '-detail'
  48. for (i = 0; i < o.basic.explains.length; i++) {
  49. x = document.createElement('li')
  50. x.className = randKey
  51. x.innerHTML = o.basic.explains[i]
  52. explains.appendChild(x)
  53. }
  54. panelBody.appendChild(explains)
  55. }
  56. } else if (o.translation) {
  57. translation = document.createElement('div')
  58. translation.className = randKey
  59. translation.innerHTML = o.translation[0]
  60. panelBody.appendChild(translation)
  61. }
  62. }
  63. function translate(e) {
  64. var sel = window.getSelection()
  65. var text = sel.toString()
  66. if (/^\s*$/.test(text)) return
  67. if (['input', 'textarea'].indexOf(document.activeElement.tagName.toLowerCase()) < 0 && !document.activeElement.contains(window.getSelection().getRangeAt(0).startContainer)) return
  68. GM_xmlhttpRequest({
  69. method: 'GET',
  70. url: 'https://fanyi.youdao.com/openapi.do?relatedUrl=http%3A%2F%2Ffanyi.youdao.com%2Fopenapi%3Fpath%3Dweb-mode&keyfrom=test&key=null&type=data&doctype=json&version=1.1&q=' + window.encodeURIComponent(text),
  71. onload: function (res) {
  72. var data = JSON.parse(res.responseText)
  73. var w = window.innerWidth, h = window.innerHeight
  74. if (!data.errorCode) {
  75. render(data)
  76. if (e.clientY > h * .5) {
  77. panel.style.top = 'auto'
  78. panel.style.bottom = h - e.clientY + 10 + 'px'
  79. } else {
  80. panel.style.top = e.clientY + 10 + 'px'
  81. panel.style.bottom = 'auto'
  82. }
  83. if (e.clientX > w * .5) {
  84. panel.style.left = 'auto'
  85. panel.style.right = w - e.clientX + 'px'
  86. } else {
  87. panel.style.left = e.clientX + 'px'
  88. panel.style.right = 'auto'
  89. }
  90. document.body.appendChild(panel)
  91. }
  92. }
  93. })
  94. }
  95.  
  96. var panel, panelBody, panelPos, audio
  97.  
  98. audio = document.createElement('audio')
  99. audio.autoplay = true
  100.  
  101. var randKey = 'it-' + Math.random().toString(16).slice(2, 8)
  102. GM_addStyle(
  103. '.' + randKey + '{' + [
  104. 'margin: 0',
  105. 'padding: 0',
  106. 'box-sizing: border-box',
  107. ].join(';') + '}' +
  108. '.' + randKey + '-panel{' + [
  109. 'position: fixed',
  110. 'max-width: 300px',
  111. 'z-index: 10000',
  112. ].join(';') + '}' +
  113. '.' + randKey + '-body{' + [
  114. 'position: relative',
  115. 'padding: 8px',
  116. 'border-radius: 4px',
  117. 'border: 1px solid #eaeaea',
  118. 'line-height: 24px',
  119. 'color: #555',
  120. 'background-color: #fff',
  121. 'font-family: monospace, consolas',
  122. 'font-size: 14px',
  123. 'text-align: left',
  124. 'word-break: break-all',
  125. ].join(';') + '}' +
  126. '.' + randKey + '-header{' + [
  127. 'padding: 0 0 8px',
  128. 'border-bottom: 1px dashed #aaa',
  129. ].join(';') + '}' +
  130. '.' + randKey + '-header>[data-type]{' + [
  131. 'margin-left: 8px',
  132. 'color: #7cbef0',
  133. 'cursor: pointer',
  134. 'font-size: 13px'
  135. ].join(';') + '}' +
  136. '.' + randKey + '-detail{' + [
  137. 'margin: 8px 0 0',
  138. 'line-height: 22px',
  139. 'list-style: none',
  140. 'font-size: 13px'
  141. ].join(';') + '}'
  142. )
  143. panel = document.createElement('div')
  144. panel.className = randKey + ' ' + randKey + '-panel'
  145. panelBody = document.createElement('div')
  146. panelBody.className = randKey + ' ' + randKey + '-body'
  147. panel.appendChild(panelBody)
  148.  
  149. document.addEventListener('mousedown', function (e) {
  150. if (panel.contains(e.target)) return
  151. panel.parentNode && panel.parentNode.removeChild(panel)
  152. panelBody.innerHTML = ''
  153. }, true)
  154. document.addEventListener('mouseup', function (e) {
  155. if (panel.contains(e.target)) return
  156. setTimeout(translate, 0, e)
  157. }, true)