日语划词词典

调用沪江小D进行日语划词查询

  1. // ==UserScript==
  2. // @name 日语划词词典
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.60
  5. // @description 调用沪江小D进行日语划词查询
  6. // @author https://github.com/fthvgb1
  7. // @match http://*/*
  8. // @include https://*/*
  9. // @include file:///*
  10. // @run-at document-start
  11. // @connect hjenglish.com
  12. // @grant GM_xmlhttpRequest
  13. // ==/UserScript==
  14.  
  15. (function () {
  16. 'use strict';
  17.  
  18. // Your code here...
  19. /**联网权限*/
  20. // @connect hjenglish.com 沪江小D
  21. /**样式*/
  22. var style = document.createElement('style');
  23. // >>>>> 可以自定义的变量
  24. var fontSize = 14; // 字体大小
  25. var iconWidth = 300; // 整个面板宽度
  26. var iconHeight = 400; // 整个面板高度
  27. // 可以自定义的变量 <<<<< (自定义变量修改后把 “@version” 版本号改为 “10000” 防止更新后消失)
  28. var trContentWidth = iconWidth - 16; // 整个面板宽度 - 边距间隔 = 翻译正文宽度
  29. var trContentHeight = iconHeight - 35; // 整个面板高度 - 边距间隔 = 翻译正文高度
  30. var zIndex = '2147483647'; // 渲染图层
  31. style.textContent = `
  32. /*组件样式*/
  33. :host{all:unset!important}
  34. :host{all:initial!important}
  35. *{word-wrap:break-word!important;word-break:break-word!important}
  36. a{color:#00c;text-decoration:none;cursor:pointer}
  37. a:hover{text-decoration:none}
  38. a:active{text-decoration:underline}
  39. 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}
  40. img:last-of-type{margin-right:auto}
  41. img:hover{border:1px solid #f90}
  42. img[activate]{border:1px solid #f90}
  43. img[activate]:hover{border:1px solid #f90}
  44. table{font-size:inherit;color:inherit}
  45. 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}
  46. 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)}
  47. tr-audio{display:block;margin-bottom:5px}
  48. tr-audio a{margin-right:1em;font-size:80%}
  49. tr-audio a:last-of-type{margin-right:auto}
  50. tr-content{display:none;width:${trContentWidth}px;max-height:${trContentHeight}px;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}
  51. tr-engine~tr-engine{margin-top:1em}
  52. tr-engine .title{color:#00c;display:inline-block;font-weight:bold}
  53. tr-engine .title:hover{text-decoration:none}
  54. /*各引擎样式*/
  55. .word-details {
  56. position: relative
  57. }
  58.  
  59.  
  60.  
  61. .word-details-header>p {
  62. line-height: 20px;
  63. margin: 0 0 20px
  64. }
  65.  
  66. .word-details-header>p>span {
  67. color: #bac
  68. }
  69.  
  70. .word-details .redirection {
  71. color: #fff;
  72. line-height: 20px;
  73. margin: 0 0 20px;
  74. opacity: .8
  75. }
  76.  
  77. .word-details-tab {
  78. cursor: pointer;
  79. display: inline-block;
  80. margin: 0 15px 15px 0;
  81. height: 50px;
  82. border-radius: 5px;
  83. padding: 0 20px;
  84. background: #f5f8ff
  85. }
  86.  
  87. .word-details-tab h2 {
  88. font-size: 18px;
  89. line-height: 30px;
  90. height: 35px;
  91. margin: 0;
  92. font-weight: 400;
  93. display: inline-block
  94. }
  95.  
  96. .word-details-tab-active {
  97. color: #fff;
  98. background-color: #abc
  99. }
  100.  
  101. .word-details-tab .pronounces {
  102. display: inline-block;
  103. line-height: 60px;
  104. height: 60px;
  105. vertical-align: top;
  106. margin-left: 20px
  107. }
  108.  
  109. .word-details-pane {
  110. display: none
  111. }
  112.  
  113. .word-details-pane:first-child {
  114. display: block
  115. }
  116.  
  117. .word-details-pane-header {
  118. padding: 6px 10px;
  119. background-image: -webkit-linear-gradient(276deg,#544646,#7ed285);
  120. background-image: -o-linear-gradient(276deg,#544646,#7ed285);
  121. background-image: linear-gradient(276deg,#544646,#7ed285);
  122. border-top-left-radius: 5px;
  123. border-top-right-radius: 5px;
  124. color: #fff
  125. }
  126.  
  127. .word-details-pane-header-multi {
  128. border-top-left-radius: 0;
  129. border-top-right-radius: 0
  130. }
  131.  
  132. .word-details-pane-header .word-text {
  133. margin-bottom: 10px
  134. }
  135.  
  136. .word-details-pane-header .word-text .add-to-scb-loading {
  137. background: url(img/loading-289f3.png) no-repeat 0 0/cover;
  138. -webkit-animation: xd-loading .6s steps(8) infinite both;
  139. animation: xd-loading .6s steps(8) infinite both
  140. }
  141.  
  142. .word-details-pane-header .word-text .add-to-scb-success {
  143. background: url(data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTQ1N0M1MTRDMDRCMTFFNzlGNEY5NDYwNkM0QUE2NjciIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTQ1N0M1MTVDMDRCMTFFNzlGNEY5NDYwNkM0QUE2NjciPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoxNDU3QzUxMkMwNEIxMUU3OUY0Rjk0NjA2QzRBQTY2NyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoxNDU3QzUxM0MwNEIxMUU3OUY0Rjk0NjA2QzRBQTY2NyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pvx0vOAAAAJLSURBVHja7JkxSMNAFIbT1LGDYnEIRRBdrIOjk0uELkJFHDo5OEpQWlAcXHXTVSld3NwEB7t1ciw4VaRDxUGLIB1sESy0xv/ghvS8xGuauyDmwUfJJe/d3+Tl3V1O02C2bcfBPqiCri3furQv0mdcG8ao2IodnlWGEa2DAjC18MykGoQF57TwLTdMSnwyj2hStjr0kWT6/BT1jZGrBxpgKm6p33517Y9ZJDgSHAlWbGN+y9CwFlS5jFIiEuw3hyUM2fe+3oWw5hJRDv+bOuyVUgiRws8aWAWzwKCnmqABbsA1Qjx7CnGa6HVu5uJrgBLoCYTo0WuNUASjKQvaPhanxCerVDAOd0F/hBU18d3xJdjHEijrIrYG8iANEpQ0bau5iM5KFUxzts35eGIB3cNPp9d0OelhyBRc4og1SXhBTI7okhTBpHRxqoElKHQclMES9WGrR0qGYIuTs7qA2ClwR31aYJGT05YMwWUmZJ4KOgRHLmJJzj8wfq/ggGkryxBcZ0KSClBwHJ+AmEPsDHjkPP5N6uu0ugzBHSbkBvhi2s6o6HnwwnlB1+mfSTDnOioET4BLTn29Am9M2wfIOO6+EsG8lCDfoC9+GdXewTKT2z9SQsb0ssEcZ0AfbIFzF58WWAG3HN/B2IrLGsnbU+Z8EyxwKoeuqqyJDBzHtP0JzLmUOteBg/2gnVQ0NG+DaT9DczWgzZWi6OTHY7QTmvzsBS1Y9vQyqG2vIic1gp/AO0SPurFY9JjIB7dEUrQBE9giNKZY+MjL/G8BBgDu7CBuz18G6wAAAABJRU5ErkJggg==) 0 0/contain
  144. }
  145.  
  146. .word-details-pane-header .word-text .word-info {
  147. margin-bottom: 20px
  148. }
  149.  
  150. .word-details-pane-header .word-text h2 {
  151. font-size: 18px;
  152. line-height: 0;
  153. margin: 0;
  154. font-weight: 400;
  155. display: inline-block
  156. }
  157.  
  158. .word-details-pane-header .word-text a,.word-details-pane-header .word-text button {
  159. display: inline-block;
  160. width: 20px;
  161. height: 20px;
  162. line-height: 50px;
  163. margin-left: 30px;
  164. background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAABGdBTUEAALGPC/xhBQAAAp9JREFUWAntWbFOAkEQBbHESipCbOj8DAobEyz9ATqi0UQ/xsBPWNCY+AW2WtIZPkApMFHxvePOm5u7PQbclZAwyYSZ2zcz7/aG2727SgUyn89r0FvoE/QDGlpYg7VYs0YOZmEA9BG6KWFtM+k9nNk1tGM+Q/9A1iYHk5DwuQkZFmTngMsxU71wGJZb9J9pqJoza80qAyW4CpF+KHvdumyJrZId4dCXazfDuxlWM7CvfKerb0NOoGPA1+1y18OOCfZ2eOtm2NzDvnpQTPWLsM3mxvYSZoYKuHUtsXWEzT1svQ+X9TpytHCFz6Cn0Da0CaVMoGPoCHqPHK/4LRYSkVKMijbdEua0i+IBbkIH0E9nYDpADLHJyWRTpriFlR1NPY1z+WnEwgKuC31z4UuOM6ar8/ERPyM5QHwgAypxZDxgl9CvEviyIcZeyJxmwpkgg4NCnNkiss84fgU9htZjpc1jHNPCHOlM61EDl6UQ5GTP6jbgy5M+1Hln4liM0S9zmGvR0zAyspSNAYCE/NNIIYGODJWDtNVYB4c06UGEKQuUSaw28rWg+m7Q1/HL6mKcV0MKc7a89zCS6kLsy1wbSCa0C06I7aF7up9LpAPX8LkoSBliIfiWByx2HDNU2FPzSqcCy1yuYFIe6BTNogTp8XjFjGIFru19t4bC7yhQF0UOUHyqCYnxQpOEEcM8zJfINERLJMmD/IYgzI2MlCPprGjr2EkIwtx1STmhw0ssRQJKxqNYgR2HIMwtopQeenHlOnFMTyaCPQpxHw6+cOgX2g11Viu7mJ2gSzO/5viQu+TMkCzo5ufGB1vk+CVM4vCDbS99ffbKEI5J+9/Ax4l9fFjMERYzrffGlota/IjEpKEF7Lw9hP7LF6NkQkD8z4/5P0eRZrlVgPOgAAAAAElFTkSuQmCC) 0 0/contain;
  165. border: none;
  166. outline: none;
  167. cursor: pointer
  168. }
  169.  
  170.  
  171.  
  172. .word-details-pane-footer {
  173. padding: 0 30px 30px
  174. }
  175.  
  176. .word-details-pane mark.highlight {
  177. color: #2e94f7;
  178. background: none
  179. }
  180.  
  181.  
  182. .word-details-item:last-of-type {
  183. margin-bottom: 0
  184. }
  185.  
  186. .word-details-item>h2 {
  187. display: none;
  188. font-size: 20px;
  189. line-height: 28px;
  190. margin: 0 0 20px;
  191. font-weight: 400
  192. }
  193.  
  194. .word-details-button-expand {
  195. cursor: pointer
  196. }
  197.  
  198. .word-details-button-feedback {
  199. padding: 10px 25px;
  200. font-size: 14px;
  201. border-radius: 20px;
  202. background-color: #fff;
  203. border: 1px solid #2e94f7;
  204. color: #2e94f7
  205. }
  206.  
  207. .word-details a {
  208. color: #2e94f7
  209. }
  210.  
  211. .word-details a:hover {
  212. text-decoration: underline
  213. }
  214.  
  215. .word-details-ads,.word-details-ads-placeholder {
  216. display: none;
  217. min-height: 48px;
  218. padding: 10px 32px 10px 54px
  219. }
  220.  
  221. .word-details-ads {
  222. position: absolute;
  223. left: 0
  224. }
  225.  
  226. .word-details-ads-placeholder {
  227. position: relative;
  228. background: rgba(46,148,247,.1)
  229. }
  230.  
  231. .word-details-ads-placeholder:before {
  232. content: "";
  233. width: 16px;
  234. height: 17px;
  235. position: absolute;
  236. top: 10px;
  237. left: 30px;
  238. top: 14px;
  239. background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAiCAYAAAA+stv/AAAAAXNSR0IArs4c6QAABTRJREFUWAm9Vn1oVlUYf851M5vkgixJbEb/hFLuryRNpT8ipGgWtcVmTEVZECV9qcQCZxGVUGF/BVnQh7GSmBgLYuhipUIzyFl/BK0N01n2MXAr53vvPU+/53zc9973vdt436AD9z7nnOfrd37nPOdeRf+hMXfNo9/HP0KIXnXdvneqCRVU4yQ+zE9cQb/+2UNR/ADFarjaOFUBYP5kDp2LP0Xy9aQ1UZ0aqhZATVWOZ/p3EtO9xlfxH6r+jb+qigOnigHwcMetFOku7IHNqdQ/1SYXv4oBYL/3E+u5pJTNy3rqfwPAP3asoShamUmogtrMuMJBZYfwcrSdIlAf4eAZafo3oBwrZ9IBnREAD229n09vWyS2WP1Cihklh+QxEhspQOIaOn2mIW/hfGrLc3xq814AnDbPtAo+uelFKoQ9pKnOBJ8srDLJJLkwYEAIEDxhvCoPABXiNgr1Dvp2pJt/6JqbZ5MLgAfbX0GS5xF8UDXuHzGOYbzSJItim1SkeQAm1PeVBjfMMS23YHUzTQz35oEoA8DH29uAfJehOOK+JHCsAcAlT6QwAABar+eRzfMSW+lMXnoczAQWtDCm76KLP72QscEgA4AHtlxLYfSmTS6B6fvEQevFJliaetOHXcT1dDbc6m15oH0FRbTd2ktyBzTSO3hg4x3eTmT29Oqp10nzNSQlDh84XhAj02Keb+YYAeUOEJltO/n4U+9SOLaWosL7MFiQVZtRAN+30VvudQkD3N+6EPv1sKHZHDLQrUN328A8wtXnD5+XWTYa6O+xSSrwF2BwUT5bWFWkl/GRlnUeQJGBQtgKymvt6mEoqRUt9YY4aGCDb7KrF73DJleyYQSyZEsT39KOCmS7BmQ6YQArbDOo/epEhjh4vsV81upLqkBY8JWRZcTuvYZe5kWaPuLG8UPMzXNKASwzh88EESNx1C38WYe9B2I9WK43Nt5W7B0YJ32ZJlLmzVNHn8dLEgDc11wPVHicgZeRvpoKF3Y7Eo45Zx/ESm8r0jxpUOm+03sWIru9dgvGCw3J3S4rl3veMGACPMsHNzxKTStOYG7MJvHJygA7FtJ6B6L47bDxL+ulsjB7CAMdUgFO0vyB8ofMnpO36OOTTcTqZ5Tf4sQm396EKb4AwDQvZSB9XZCeBTC1YIxoXMbQQSkH3P9wmEnzuse8vc4VQZm90cMy0bu+z+/1NQo5XRWoRw5cBO0T+XUudMLb77GpEkd9ul+pnmp/EQDFeyDSR7HsDQm9fguydZ63RRKn2GazF30QDKvWQ6PiVAQQc48FAAOhS8kLzffd0E54hZeeVxlLX86T2wOJ42OIWgAwH5KutBSA2sOkpiZgfJVVubdxRl+kNJ/LxS9LmCQXELmNwfKHXpPchOqx3nH8cO7NnAPZY6lbL9N9mZNHPs1eJp9p/9l2vqa0vT13q46+78oAmInaK/E1pHPmapVkJqF8lCSQJHKBvfSBvfSg0tLrRMZ8CaR3+uQiEyL9JL925+3Yo35wnv3B8AZle4DAyVxilN8Jglb19JfdaWUZAFHyq+s2YtkfYN/VrFWRjjZTXwV71K6BrlKTXABixC+vfhA333sAMd+ewGlNS2Nmx0rFiPGM6vx6X1ZhRzNG5ZfW4tcqPoCSvGXaKijdAYno54hG0d+mdp84kpdc5pIqyDNQnV8NEd/diIO5CQdxNOdrmV8lzL+hMp4kveTmmZJLzhkZSINiZkV7Vt8GRpowvwYrux7ueDQWEZwHS+cx/gYfq8PUeOMx1XIQJTN7+xcs/bB+XniprgAAAABJRU5ErkJggg==) no-repeat 0/100%
  240. }
  241. .audio {
  242. display: inline-block;
  243. width: 20px;
  244. height: 20px;
  245. position: relative;
  246. overflow: hidden;
  247. cursor: pointer;
  248. vertical-align: middle;
  249. background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJwAAAA0CAYAAAB/91HOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDozZDg2NTg3NC04Mzg3LTQ1MGItYmY3My0xODVlMTgwZWZlMjUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDIyNzg4MDRCMEFGMTFFN0I2N0ZGQkVCRDRBNkU4RUUiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDIyNzg4MDNCMEFGMTFFN0I2N0ZGQkVCRDRBNkU4RUUiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDplNDU0MTcwYi02NzIwLTRjOGMtOTYxNy05M2Q1OWFiNzA3NTIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6M2Q4NjU4NzQtODM4Ny00NTBiLWJmNzMtMTg1ZTE4MGVmZTI1Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+ArAG/QAABIxJREFUeNrsnV1oHFUYhr8zu+ScVF2NEDBGsYogVi+SqghWsKSCF1LBCL3yQqmo6V6JV70ogSLUK/FmU1EsXnghqBFREMG/ohb8qa2IiiKkYBqFgG3TYmeS3fn8TpqU2TG7O5NkZs4m7wsfc/bkMJln5z2/MydRzEwQlJc8fAUQDAfBcBAEw0EwHATBcBAMB21OlZMUuvtVou+fJho+HBCHTKwUUWT9TitDW/uJfp/1iUmR5zEN3GRoZkrKS1o1pHjFXFG5QD1fjtHZoYl57tvWQzt3Eo0XAJ0lTyeNbzAeq8ma3/JnP1ZN7i3ciMRX6nxwbi70/xmq+dPy+UBSszso8DjapWqJw9SgT6Wu7WDmks2U9PXM4cEzvwSTXdalgyevLnUV2np6KnhHmvW7WhUQwN3v1fwnxqvmSBfcnMQ8kmzLMx7rYrqdJ+2D0Sxq5O4wVD/8D0YpGVqof5vzaG8XmC0dj1o8to5NzrOehrNN8iGJ9wWmr5lF/VFW3j3cw3c21w51u8NGWxWPHZS3DAbPenWp1/02678lV/FAvJEVmElztX5yYW5hboV2u89Rs4EnI540LZxtQGXyTd9InF/qvhcjYP+vSzDRwqquPPW8JB+TuAQTOHUTwFMAT9IWbmCoFrzJxCNLzm9Prui0otIepsax5bx62HDp5oAnOx5eoSKkauFUfSEC07G0+sTrNcOSOuZo9wKeAnk6Gm54wn8qMYxodJ9+SA6z0byLZ31n7g54iuXpaDhpH/fGashHvdrc2GZiHMbWc5xqDsBTLE+5M5C6I9ota9LPyGG6Vfmm52oObpcAT7E8nScNzFfGcv6kblb+PG0H0ZuNJ/U6nEyxXVsOWJPA49ikAYJgOAiGgyAYDoLhIBgOgmA4CIZbVK82pEpmw3wB4HHNcEpdiOXc0NV3BDxuG04R/xz97M8Hr8hhsFX50aqh0hZDnirbt0nduz858diyS/F2NDYaz3J+UpUT/KIjzHzv8mdJP0wNf7qDicPohbr0hkUBPHvAk6KFOzGmX5OL+jzpCScngo/l0N80rrjGnTFFXjx5VTIXeNKwJpk0sGf049JwfpHojMwPhhf9E5K6z9FhBHgK5Ek6S505WdUjylNj0lt/u8JANcZEg8yNo5J87nLf7ZVcukm58OQ4lCiMJy1jmmURe2Y7ILXjhasosh1WKzMgqaPNhbksF/OSJN+VqNg87Tk1iQBPNjxtt0qv18Lv37f1m10y/nzR7uCO1YBR/1xwXJJ2p/ctsRHvGUe7qdXz2BlbJBg8mRjOyu4z2688eiRuJIG6tc7hd/NMP8Wm9L86vGS0Kp6V9qg78m66EzxZPNr60PN4u0Adj3X2SsC2xDqB18l9peO5vP04Hgweyu6vJ50avFnvmJkKXhaIZ1usH33w6D79BnWHwNNqmaWWbothlg/v7Zv1Y1SiXdL7fy0AjaUR5Ywi70DfNj1KsS1rjgs8OS6LrEWfSdxfLutKxTPXnqwa+6zvBYk6dafAs5YpLP7XFpSn8D4cBMNBMBwEwXAQDAdBMBwEw0GbVP8JMAAdIoU8hRXz0AAAAABJRU5ErkJggg==) no-repeat -40px 0/auto 100%
  250. }
  251.  
  252. .audio-light {
  253. background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJwAAAA0CAYAAAB/91HOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDozZDg2NTg3NC04Mzg3LTQ1MGItYmY3My0xODVlMTgwZWZlMjUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDIyNzg4MDhCMEFGMTFFN0I2N0ZGQkVCRDRBNkU4RUUiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDIyNzg4MDdCMEFGMTFFN0I2N0ZGQkVCRDRBNkU4RUUiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDplNDU0MTcwYi02NzIwLTRjOGMtOTYxNy05M2Q1OWFiNzA3NTIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6M2Q4NjU4NzQtODM4Ny00NTBiLWJmNzMtMTg1ZTE4MGVmZTI1Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+P83CLAAAAp5JREFUeNrsnM9LFGEch91dQbAQPAgJGdEt6OQSgt6ko/0D4clIu9a5zvsnWIYXr9EhCSJI9CBCUHryVLf0JEixUYdix8/AQsM0s/uO6zvzfeN54DnsMDszn32/+77zY9+tRVE0BFAWdT4CoOCAggOg4ICCA6DggIIDCs43l+S4rP0nnx15jBbcvNyV3+WpPJJP5XCgDUOeQYifNHhyRK5G+WzKusf9k8dgHl9hrsuPUX+WAmkc8lyQPobUu3JfNtOdqfyZWnY/gCGHPEbP4RqyJV93Tz6TfJG35a3U8puGG4Y8PvJcUFd5Re7kdMuv5Fhi3TQWhxzyeMpTZOWaXJYfZNth/P8tH2dsx0oDkaeCPK4rTsqtyJ0jOZuzLQsNRB5/eXq+v+bwA8z4RuD77v0aF+J178mTvFE8Y/tlQh6/eXq+36XgHsi1giennfMeUAmQx2+enu93uUpNXxq/lVPdDWUdTMf4bQHyVIhLD9eWlxOvr8mvA3wjqu4RyOM3z8BDar8DCK2Bys7jO6+1PAMPqQAmnzQAUHBAwQEFB0DBAQUHQMEBBQdw/oL7kXp9NfDM5KkQl6lgh3Im8fqZXJHHgTZQ2XlekucvLs9Sl+XzAtu0/nMe8hj/edILuV1gh+/khOEejjwV5qk7Vuyi3HHc5h15IGeNNhB5qsxTcJLGw4KTNB4Zn3RCnpLnNDCtjjxmpwn2syFbspNx0J9lU95ILT81/HcI5PGQx+UqtSgLcmPo39nd8Y5+ydHEsj05Z/w2CnmMP2l4I6flp4zL49HUsvUA7tuRp6KLBv7eijxm/64r6bzclX+6QY7lEzkcUOOQx/A5XB5xdz0iv2XcjQ4R8nh6tAVg+qIBgIIDCg4oOAAKDig4AAoOAuBMgAEAYBYyuvW+UO8AAAAASUVORK5CYII=)
  254. }
  255.  
  256. .audio-state-playing {
  257. -webkit-animation: audio-playing .6s steps(3) infinite alternate;
  258. animation: audio-playing .6s steps(3) infinite alternate
  259. }
  260.  
  261. @-webkit-keyframes audio-playing {
  262. 0% {
  263. background-position: 0 0
  264. }
  265.  
  266. to {
  267. background-position: -60px 0
  268. }
  269. }
  270.  
  271. @keyframes audio-playing {
  272. 0% {
  273. background-position: 0 0
  274. }
  275.  
  276. to {
  277. background-position: -60px 0
  278. }
  279. }
  280.  
  281. .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}
  282. .hjenglish h3{font-size:1em;font-weight:normal}
  283. .hjenglish .detail-pron,.hjenglish .pronounces{color: #00c;}
  284. .hjenglish .detail-groups dd h3:before{counter-increment:eq;content:counter(eq) ".";display:block;width:22px;float:left}
  285. .detail-groups dd:first-of-type:last-of-type h3:before {
  286. display: none
  287. }
  288.  
  289. .detail-groups dd:first-of-type:last-of-type h3 p {
  290. margin: 0
  291. }
  292.  
  293. .detail-groups dd:first-of-type:last-of-type h3 p {
  294. margin: 0
  295. }
  296.  
  297. .detail-groups dd:first-of-type:last-of-type ul {
  298. margin-left: 0
  299. }
  300.  
  301. .detail-groups ul {
  302. //margin-left: 22px
  303. }
  304.  
  305. .detail-groups ul li {
  306. color: #999;
  307. margin-bottom: 14px
  308. }
  309.  
  310. .detail-groups ul li p {
  311. margin: 0 0 6px;
  312. line-height: 20px
  313. }
  314.  
  315. .detail-pron {
  316. color: #999;
  317. margin-left: 6px;
  318. font-family: Lucida Sans Unicode
  319. }
  320.  
  321. .detail .def-sentence-from {
  322. color: #666
  323. }
  324.  
  325. .detail .def-sentence-to {
  326. color: #999
  327. }
  328.  
  329. .detail .def-sentence-from .def-sentence-to span {
  330. vertical-align: top;
  331. margin: 1px 0 2px 2px;
  332. display: inline-block
  333. }
  334.  
  335. .detail .def-tags span {
  336. border: 1px solid #999;
  337. color: #666;
  338. border-radius: 2px;
  339. display: inline-block;
  340. line-height: 16px;
  341. font-size: 12px;
  342. width: 36px;
  343. text-align: center;
  344. margin-right: 8px
  345. }
  346.  
  347. .hjenglish .detail-groups dl{counter-reset:eq;margin-bottom:.5em;clear:both}
  348. .hjenglish ol,.hjenglish ul{list-style:none}
  349. .hjenglish dd{margin-left:1em}
  350. .hjenglish dd>p{margin-left:2.5em}
  351. `;
  352. // iframe 工具库
  353. var iframe = document.createElement('iframe');
  354. var iframeWin = null;
  355. var iframeDoc = null;
  356. iframe.style.display = 'none';
  357. var icon = document.createElement('tr-icon'), //翻译图标
  358. content = document.createElement('tr-content'), // 内容面板
  359. contentList = document.createElement('div'), //翻译内容结果集(HTML内容)列表
  360. selected, // 当前选中文本
  361. engineId, // 当前翻译引擎
  362. engineTriggerTime, // 引擎触发时间(milliseconds)
  363. idsType, // 当前翻译面板内容列表数组
  364. pageX, // 图标显示的 X 坐标
  365. pageY; // 图标显示的 Y 坐标
  366. // 初始化内容面板
  367. content.appendChild(contentList);
  368. // 发音缓存
  369. var audioCache = {}; // {'mp3 download url': data}
  370. // 翻译引擎结果集
  371. var engineResult = {}; // id: DOM
  372. // 唯一 ID
  373. var ids = {
  374. HJENGLISH: 'hjenglish',
  375. };
  376. // 唯一 ID 扩展
  377. var idsExtension = {
  378. // ID 组
  379. LIST_DICT: [ids.HJENGLISH,],
  380. LIST_DICT_LOWER_CASE: [ids.HJENGLISH,],
  381. // 去重比对(大小写翻译可能一样)
  382. lowerCaseMap: (function () {
  383. var obj = {};
  384. return obj;
  385. })(),
  386. // 标题
  387. names: (function () {
  388. var obj = {};
  389. obj[ids.HJENGLISH] = '沪江小D';
  390. return obj;
  391. })(),
  392. // 跳转到网站(“%q%”占位符或者 function text -> return URL)
  393. links: (function () {
  394. var obj = {};
  395. obj[ids.HJENGLISH] = 'https://dict.hjenglish.com/jp/jc/%q%';
  396. return obj;
  397. })(),
  398. // 翻译引擎
  399. engines: (function () {
  400. var obj = {};
  401. obj[ids.HJENGLISH] = function (text, time) {
  402. ajax('https://dict.hjenglish.com/jp/jc/' + encodeURIComponent(text), function (rst) {
  403. putEngineResult(ids.HJENGLISH, parseHjenglish(rst, time, text), time);
  404. showContent();
  405. }, function (rst) {
  406. putEngineResult(ids.HJENGLISH, htmlToDom('error: 无法连接翻译服务'), time);
  407. showContent();
  408. }, {
  409. headers: {
  410. 'Cookie': 'HJ_SID=' + uuid() + '; HJ_SSID_3=' + uuid() + '; HJ_CST=1; HJ_CSST_3=1; HJ_UID=' + uuid(),
  411. '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'
  412. }
  413. });
  414. };
  415.  
  416. return obj;
  417. })()
  418. };
  419. var vices = [];
  420. var vice;
  421. var ttt = '';
  422.  
  423. function speech(event) {
  424. var ss = icon.querySelector('img[icon-id="icon-speech"]');
  425.  
  426. if (event.target === ss) {
  427. var x = new SpeechSynthesisUtterance(ttt);
  428. x.voice = vice;
  429. speechSynthesis.speak(x);
  430.  
  431. }
  432. }
  433.  
  434. // 绑定图标拖动事件
  435. var iconDrag = new Drag(icon);
  436. // 图标数组
  437. var iconArray = [{
  438. name: '沪江小D',
  439. id: 'icon-dict',
  440. image: 'data:image/png;base64,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',
  441. trigger: function (text, time) {
  442. idsType = idsExtension.LIST_DICT;
  443. if (text != text.toLowerCase()) {
  444. idsType = idsExtension.LIST_DICT_LOWER_CASE; // 改为大小写 ID 组(大小写各请求一次)
  445. }
  446. idsType.forEach(function (id) {
  447. idsExtension.engines[id](text, time);
  448. });
  449. initContent(); // 初始化翻译面板
  450. displayContent(); // 立马显示翻译面板
  451. }
  452. }, {
  453. name: 'tts发音',
  454. id: 'icon-speech',
  455. image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAbCAYAAACJISRoAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANsSURBVEhLlVY7aBRRFD1vN5vVJKtoosFI4icYEEHE+IckiBFJITaWFlpYiIWdFmKhoihYamWhkM7KylYUC+OfWAiCHxJFo0ENyWqya3a8n/f2vdmdgXjZ3fPOnTfvnnNn3syag8NRBPrAGCQiCPGfWLNOhrKaCJEm6oh+ZUDcYh2X8PM1HUctIooDJEU6ol8ZJHCLGv64puNci1gdiSjDep7mRCHObRGvqA7pkzERcjSzMRs566lOFLwjDj1HZXkMlOWyQOdSgxM7gFN7DLpbgYZMuhNNx9EK8wrsQH4X5yL0rwXODwID64DdXcDpPqBjSboTTce5bZfqYIUtjUAhb9DWDBzdanB8O6RV994Czz4DbU3AqkK6E4U4lyKG6vHiBzZEOLcXuEjKL+8H9nUDU7PA9ccRhl8CEzNAls7I0jVKcrJ+eYSeNl7UO+KQIrmswZEtwLFeQ/0HVrYA7fTlRS89AEbGDcoVmW8j2cmFQYNrQ9QRWk8PK0oRvmv61gCleeDqQ+AGKecYnwLGfgKVao9dqJNCPkIrta8hU3PczbcoRTJUsSUP/CkDoxPA96JTSKGSZOhDnZzcZUg90Nxolbtw10TtahFWxpSrahsDXY4HKSY8j28Cbm+eOhE/7J1w2CIxHRQBV0lOlI0EbkcSgRPGqpN4BFwlOVE2ErgdSQROGKtOmHBVVRjocjxIMVmoEw4pwnfPTIl3OLC5HVjRHOhSSRZdqJPRr8Cjj3TD/E13wiFFSvNGJufpOXWmX+8aDr6oXctoEiurVU78zmu63UeAYindCaMUKc/Tjn4F3Hoeyd74RpuQNyJvyLMDwM5OfQr7UCez5KBIHXD7aOwX8O4H8Yp3wmhfvzyinU/fPLWMqy8iPLxJH4zztNvvv9ei21YDV2jDPvlU7YYEn9NEjyZ6/GFmTnPusNWntEwK+NpMz0WYLAK3X0S4+ZTzwFAP0EsFJn8DX6bViV9GdRZLEZ3Lxb0TjqoT7rHkWFLA+X3SUQAObSSXDcDdN8AHagl12K0hYU9LxAX9W+E3Y5ZfVHTa34qRa8D5+uUs1qxj28UTUpA+lcjQ4noXUkclrzP8vBinhWXEhShi10RQhvVcxAd5HVlOBxO5nuSdVJWohHpuUaOGO+WcD7nFqpOYkpDLgLhFjQQeYuAkAvAPy4GovdmaNF4AAAAASUVORK5CYII=',
  456. trigger: function (text, time) {
  457. speechSynthesis.getVoices();
  458. ttt = text;
  459. setTimeout(() => {
  460. if (vices.length < 1) {
  461. vices = speechSynthesis.getVoices();
  462. vices.forEach(value => {
  463. if (!vice && value.lang === 'ja-JP') {
  464. vice = value;
  465. }
  466. });
  467. if (!vice) {
  468. icon.querySelector('img[icon-id="icon-speech"]').title = '似乎无可用的tts,请先安装';
  469.  
  470. }
  471. }
  472. if (vice) {
  473. var s = new SpeechSynthesisUtterance();
  474. s.voice = vice;
  475. s.text = text;
  476. speechSynthesis.speak(s);
  477. var ss = icon.querySelector('img[icon-id="icon-speech"]');
  478. ss.addEventListener('click', speech, false)
  479. }
  480.  
  481. }, 1000);
  482.  
  483. }
  484. }];
  485. // 添加翻译引擎图标
  486. iconArray.forEach(function (obj) {
  487. var img = document.createElement('img');
  488. img.setAttribute('src', obj.image);
  489. img.setAttribute('alt', obj.name);
  490. img.setAttribute('title', obj.name);
  491. img.setAttribute('icon-id', obj.id);
  492. img.addEventListener('mouseup', function () {
  493. if (engineId == obj.id) {
  494. // 已经是当前翻译引擎,不做任何处理
  495. } else {
  496. icon.setAttribute('activate', 'activate'); // 标注面板展开
  497. engineId = obj.id; // 翻译引擎 ID
  498. engineTriggerTime = new Date().getTime(); // 引擎触发时间
  499. engineActivateShow(); // 显示翻译引擎指示器
  500. audioCache = {}; // 清空发音缓存
  501. engineResult = {}; // 清空翻译引擎结果集
  502. obj.trigger(selected, engineTriggerTime); // 启动翻译引擎
  503. }
  504. });
  505. icon.appendChild(img);
  506. });
  507. // 添加内容面板(放图标后面)
  508. icon.appendChild(content);
  509. // 添加样式、翻译图标到 DOM
  510. var root = document.createElement('div');
  511. document.documentElement.appendChild(root);
  512. var shadow = root.attachShadow({
  513. mode: 'closed'
  514. });
  515. // iframe 工具库加入 Shadow
  516. shadow.appendChild(iframe);
  517. iframeWin = iframe.contentWindow;
  518. iframeDoc = iframe.contentDocument;
  519. // 外部样式表
  520. var link = document.createElement('link');
  521. link.rel = 'stylesheet';
  522. link.type = 'text/css';
  523. link.href = createObjectURLWithTry(new Blob(['\ufeff', style.textContent], {
  524. type: 'text/css;charset=UTF-8'
  525. }));
  526. // 多种方式最大化兼容:Content Security Policy
  527. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
  528. shadow.appendChild(style); // 内部样式表
  529. shadow.appendChild(link); // 外部样式表
  530. // 翻译图标加入 Shadow
  531. shadow.appendChild(icon);
  532. // 鼠标事件:防止选中的文本消失
  533. document.addEventListener('mousedown', function (e) {
  534. log('mousedown event:', e);
  535. if (e.target === icon || (e.target.parentNode && e.target.parentNode === icon)) { // 点击了翻译图标
  536. e.preventDefault();
  537. }
  538. });
  539. // 鼠标事件:防止选中的文本消失;显示、隐藏翻译图标
  540. document.addEventListener('mouseup', showIcon);
  541. // 选中变化事件
  542. document.addEventListener('selectionchange', showIcon);
  543. document.addEventListener('touchend', showIcon);
  544. // 内容面板滚动事件
  545. content.addEventListener('scroll', function (e) {
  546. if (content.scrollHeight - content.scrollTop === content.clientHeight) {
  547. log('scroll bottom', e);
  548. e.preventDefault();
  549. e.stopPropagation();
  550. } else if (content.scrollTop === 0) {
  551. log('scroll top', e);
  552. e.preventDefault();
  553. e.stopPropagation();
  554. }
  555. });
  556. /**日志输出*/
  557. function log() {
  558. var debug = false;
  559. if (!debug) {
  560. return;
  561. }
  562. if (arguments) {
  563. for (var i = 0; i < arguments.length; i++) {
  564. console.log(arguments[i]);
  565. }
  566. }
  567. }
  568. /**鼠标拖动*/
  569. function Drag(element) {
  570. this.dragging = false;
  571. this.startDragTime = 0;
  572. this.stopDragTime = 0;
  573. this.mouseDownPositionX = 0;
  574. this.mouseDownPositionY = 0;
  575. this.elementOriginalLeft = parseInt(element.style.left);
  576. this.elementOriginalTop = parseInt(element.style.top);
  577. var ref = this;
  578. this.startDrag = function (e) {
  579. e.preventDefault();
  580. ref.dragging = true;
  581. ref.startDragTime = new Date().getTime();
  582. ref.mouseDownPositionX = e.clientX;
  583. ref.mouseDownPositionY = e.clientY;
  584. ref.elementOriginalLeft = parseInt(element.style.left);
  585. ref.elementOriginalTop = parseInt(element.style.top);
  586. // set mousemove event
  587. window.addEventListener('mousemove', ref.dragElement);
  588. log('startDrag');
  589. };
  590. this.unsetMouseMove = function () {
  591. // unset mousemove event
  592. window.removeEventListener('mousemove', ref.dragElement);
  593. };
  594. this.stopDrag = function (e) {
  595. e.preventDefault();
  596. ref.dragging = false;
  597. ref.stopDragTime = new Date().getTime();
  598. ref.unsetMouseMove();
  599. log('stopDrag');
  600. };
  601. this.dragElement = function (e) {
  602. log('dragging');
  603. if (!ref.dragging) {
  604. return;
  605. }
  606. e.preventDefault();
  607. // move element
  608. element.style.left = ref.elementOriginalLeft + (e.clientX - ref.mouseDownPositionX) + 'px';
  609. element.style.top = ref.elementOriginalTop + (e.clientY - ref.mouseDownPositionY) + 'px';
  610. log('dragElement');
  611. };
  612. element.onmousedown = this.startDrag;
  613. element.onmouseup = this.stopDrag;
  614. }
  615. /**是否拖动图标*/
  616. function isDrag() {
  617. return iconDrag.elementOriginalLeft !== parseInt(icon.style.left) ||
  618. iconDrag.elementOriginalTop !== parseInt(icon.style.top);
  619. }
  620. /**强制结束拖动*/
  621. function forceStopDrag() {
  622. if (iconDrag) {
  623. // 强制设置鼠标拖动事件结束,防止由于网页本身的其它鼠标事件冲突而导致没有侦测到:mouseup
  624. iconDrag.dragging = false;
  625. iconDrag.unsetMouseMove();
  626. }
  627. }
  628. /**是否包含汉字*/
  629. function hasChineseByRange(str) {
  630. return /[\u4e00-\u9fa5]/ig.test(str);
  631. }
  632. /**uuid*/
  633. function uuid() {
  634. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
  635. var r = Math.random() * 16 | 0,
  636. v = c == 'x' ? r : (r & 0x3 | 0x8);
  637. return v.toString(16);
  638. });
  639. }
  640. /**对象转 xml*/
  641. function objToXml(obj) {
  642. var xml = '';
  643. for (var prop in obj) {
  644. if (obj[prop] instanceof iframeWin.Function) {
  645. continue;
  646. }
  647. xml += obj[prop] instanceof iframeWin.Array ? '' : '<' + prop + '>';
  648. if (obj[prop] instanceof iframeWin.Array) {
  649. for (var array in obj[prop]) {
  650. if (obj[prop][array] instanceof iframeWin.Function) {
  651. continue;
  652. }
  653. xml += '<' + prop + '>';
  654. xml += objToXml(new iframeWin.Object(obj[prop][array]));
  655. xml += '</' + prop + '>';
  656. }
  657. } else if (obj[prop] instanceof iframeWin.Object) {
  658. xml += objToXml(new iframeWin.Object(obj[prop]));
  659. } else {
  660. xml += obj[prop];
  661. }
  662. xml += obj[prop] instanceof iframeWin.Array ? '' : '</' + prop + '>';
  663. }
  664. xml = xml.replace(/<\/?[0-9]{1,}>/g, '');
  665. return xml
  666. }
  667. /**xml 转 html*/
  668. function xmlToHtml(xml, tag) {
  669. return xml.replace(/<([^/]+?)>/g, '<' + tag + ' class="$1">')
  670. .replace(/<\/(.+?)>/g, '</' + tag + '>');
  671. }
  672. // html 字符串转 DOM
  673. function htmlToDom(html) {
  674. var div = document.createElement('div');
  675. div.innerHTML = html;
  676. return div;
  677. }
  678. /**清理 html*/
  679. function cleanHtml(html) {
  680. html = html.replace(/<script[\s\S]*?<\/script>/ig, '')
  681. .replace(/<link[\s\S]*?>/ig, '')
  682. .replace(/<style[\s\S]*?<\/style>/ig, '')
  683. .replace(/<img[\s\S]*?>/ig, '');
  684. html = cleanAttr(html, 'on[a-z]*');
  685. return html;
  686. }
  687. /**
  688. * 清理指定属性(忽略大小写)
  689. * @param attr 支持正则表示(如“on[a-z]*”,表示清理“on”开头的属性:onclick、onmove等)
  690. */
  691. function cleanAttr(html, attr) {
  692. var regex = ' ' + attr + '="([^"<>]*)"';
  693. return html.replace(new RegExp(regex, 'ig'), '');
  694. }
  695. /**带异常处理的 createObjectURL*/
  696. function createObjectURLWithTry(blob) {
  697. try {
  698. return iframeWin.URL.createObjectURL(blob);
  699. } catch (error) {
  700. log(error);
  701. }
  702. return '';
  703. }
  704. /**ajax 跨域访问公共方法*/
  705. function ajax(url, success, error, obj) {
  706. if (!!!obj) {
  707. obj = {};
  708. }
  709. if (!!!obj.method) {
  710. obj.method = 'GET';
  711. }
  712. // >>>因为Tampermonkey跨域访问(a.com)时会自动携带对应域名(a.com)的对应cookie
  713. // 不会携带当前域名的cookie
  714. // 所以,GM_xmlhttpRequest【不存在】cookie跨域访问安全性问题
  715. // 以下设置的cookie会添加到已有cookie的后面<<<
  716. if (!!!obj.headers) {
  717. obj.headers = {
  718. 'cookie': ''
  719. };
  720. }
  721. GM_xmlhttpRequest({
  722. method: obj.method,
  723. url: url,
  724. headers: obj.headers,
  725. responseType: obj.responseType,
  726. data: obj.data,
  727. onload: function (res) {
  728. success(res.responseText, res, obj);
  729. },
  730. onerror: function (res) {
  731. error(res.responseText, res, obj);
  732. },
  733. onabort: function (res) {
  734. error('the request was aborted', res, obj);
  735. },
  736. ontimeout: function (res) {
  737. error('the request failed due to a timeout', res, obj);
  738. },
  739. onreadystatechange: function () {
  740. log('ajax:', arguments);
  741. }
  742. });
  743. }
  744. /**放入翻译引擎结果集*/
  745. function putEngineResult(id, value, time) {
  746. if (time == engineTriggerTime) { // 是本次触发的异步ajax请求
  747. engineResult[id] = value;
  748. }
  749. }
  750. /**初始化面板*/
  751. function initContent() {
  752. contentList.innerHTML = ''; // 清空翻译内容列表
  753.  
  754. // 初始化翻译引擎结构(此时内容暂未填充)
  755. idsType.forEach(function (id) {
  756. if (id in idsExtension.names) {
  757. var engine = document.createElement('tr-engine');
  758. engine.setAttribute('data-id', id);
  759. engine.style.display = 'none'; // 暂无内容默认隐藏
  760. // 标题
  761. if (idsExtension.names[id]) {
  762. var title = document.createElement('a');
  763. title.innerHTML = idsExtension.names[id];
  764. title.setAttribute('class', 'title');
  765. var href = 'javascript:void(0)';
  766. if (idsExtension.links[id]) {
  767. var link = idsExtension.links[id];
  768. if (typeof link == 'string') {
  769. if (link.length > 0) {
  770. href = link.replace(/%q%/ig, encodeURIComponent(selected));
  771. }
  772. } else if (typeof link == 'function') {
  773. var fnHref = link(selected);
  774. if (fnHref.length > 0) {
  775. href = fnHref;
  776. }
  777. }
  778. }
  779. title.setAttribute('rel', 'noreferrer noopener');
  780. title.setAttribute('target', '_blank');
  781. title.setAttribute('href', href);
  782. title.setAttribute('title', '打开源网站');
  783. engine.appendChild(title);
  784. }
  785. contentList.appendChild(engine);
  786. }
  787. });
  788. }
  789. /**显示内容面板*/
  790. function displayContent() {
  791. var panelWidth = iconWidth + 8; // icon 展开后总宽度(8:冗余距离)
  792. var panelHeight = iconHeight + 8; // icon 展开后总高度(8:冗余距离)
  793. // 计算位置
  794. log('content position:',
  795. 'window.scrollY', window.scrollY,
  796. 'document.documentElement.scrollTop', document.documentElement.scrollTop,
  797. 'document.body.scrollTop', document.body.scrollTop,
  798. 'window.innerHeight', window.innerHeight,
  799. 'document.documentElement.clientHeight', document.documentElement.clientHeight,
  800. 'document.body.clientHeight', document.body.clientHeight,
  801. 'icon.style.top', icon.style.top,
  802. 'window.scrollX', window.scrollX,
  803. 'document.documentElement.scrollLeft', document.documentElement.scrollLeft,
  804. 'document.body.scrollLeft', document.body.scrollLeft,
  805. 'window.innerWidth', window.innerWidth,
  806. 'document.documentElement.clientWidth', document.documentElement.clientWidth,
  807. 'document.body.clientWidth', document.body.clientWidth,
  808. 'icon.style.left', icon.style.left
  809. );
  810. var scrollTop = Math.max(parseInt(document.documentElement.scrollTop), parseInt(document.body.scrollTop));
  811. var scrollLeft = Math.max(parseInt(document.documentElement.scrollLeft), parseInt(document.body.scrollLeft));
  812. var clientHeight = [parseInt(document.documentElement.clientHeight), parseInt(document.body.clientHeight)].filter(function (x) {
  813. return x <= parseInt(window.innerHeight);
  814. }).sort(function (a, b) {
  815. return a > b ? -1 : (a == b ? 0 : 1);
  816. })[0]; // 找出最大值且小于等于 window 的高度
  817. if (!clientHeight) { // 网页缩放导致可能数组为空([0] 为 undefined)
  818. clientHeight = parseInt(window.innerHeight);
  819. }
  820. var clientWidth = [parseInt(document.documentElement.clientWidth), parseInt(document.body.clientWidth)].filter(function (x) {
  821. return x <= parseInt(window.innerWidth);
  822. }).sort(function (a, b) {
  823. return a > b ? -1 : (a == b ? 0 : 1);
  824. })[0]; // 找出最大值且小于等于 window 的宽度
  825. if (!clientWidth) { // 网页缩放导致可能数组为空([0] 为 undefined)
  826. clientWidth = parseInt(window.innerWidth);
  827. }
  828. // 设置新的位置
  829. var iconNewTop = -1;
  830. if (parseInt(icon.style.top) < scrollTop) { // 面板在滚动条顶部可见部分之上(隐藏了部分或全部)
  831. log('Y adjust top');
  832. iconNewTop = scrollTop; // 设置为滚动条顶部可见部分位置
  833. } else if (parseInt(icon.style.top) + panelHeight > scrollTop + clientHeight) { // 面板在滚动条滚到最底部时之下(隐藏了部分或全部)
  834. log('Y adjust bottom');
  835. iconNewTop = parseInt(scrollTop + clientHeight - panelHeight); // 设置面板底部不超过滚动条滚到最底部时可见部分位置
  836. if (iconNewTop < scrollTop) { // 如果此时又出现:面板在滚动条顶部可见部分之上(隐藏了部分或全部)
  837. log('Y adjust bottom top');
  838. iconNewTop = scrollTop; // 设置为滚动条顶部可见部分位置
  839. }
  840. }
  841. if (iconNewTop != -1 && Math.abs(iconNewTop - parseInt(icon.style.top)) <= panelHeight) {
  842. log('Y set iconNewTop', iconNewTop);
  843. icon.style.top = iconNewTop + 'px';
  844. }
  845. var iconNewLeft = -1;
  846. if (parseInt(icon.style.left) < scrollLeft) {
  847. log('X adjust left');
  848. iconNewLeft = scrollLeft;
  849. } else if (parseInt(icon.style.left) + panelWidth > scrollLeft + clientWidth) {
  850. log('X adjust right');
  851. iconNewLeft = parseInt(scrollLeft + clientWidth - panelWidth);
  852. if (iconNewLeft < scrollLeft) {
  853. log('X adjust right left');
  854. iconNewLeft = scrollLeft;
  855. }
  856. }
  857. if (iconNewLeft != -1 && Math.abs(iconNewLeft - parseInt(icon.style.left)) <= panelWidth) {
  858. log('X set iconNewLeft', iconNewLeft);
  859. icon.style.left = iconNewLeft + 'px';
  860. }
  861. content.scrollTop = 0; // 翻译面板滚动到顶端
  862. content.scrollLeft = 0; // 翻译面板滚动到左端
  863. content.style.display = 'block';
  864. }
  865. /**内容面板填充数据*/
  866. function showContent() {
  867. // 填充已有结果集引擎内容
  868. idsType.forEach(function (id) {
  869. if (engineResult[id] && !(id in idsExtension.lowerCaseMap)) { // 跳过小写的内容填充
  870. var engine = contentList.querySelector('tr-engine[data-id="' + id + '"]');
  871. if (engine) {
  872. engine.appendChild(engineResult[id]);
  873. engine.removeAttribute('data-id');
  874. engine.style.display = 'block';
  875. }
  876. }
  877. });
  878. // 比较大小写内容
  879. for (var id in idsExtension.lowerCaseMap) {
  880. if (engineResult[id] &&
  881. engineResult[idsExtension.lowerCaseMap[id]] &&
  882. engineResult[id].innerHTML !== engineResult[idsExtension.lowerCaseMap[id]].innerHTML &&
  883. engineResult[id].innerHTML.toLowerCase() !== engineResult[idsExtension.lowerCaseMap[id]].innerHTML.toLowerCase()) {
  884. var engine = contentList.querySelector('tr-engine[data-id="' + id + '"]');
  885. if (engine) {
  886. engine.appendChild(engineResult[id]);
  887. engine.removeAttribute('data-id');
  888. engine.style.display = 'block';
  889. }
  890. }
  891. }
  892. }
  893. /**隐藏翻译引擎指示器*/
  894. function engineActivateHide() {
  895. icon.querySelectorAll('img[activate]').forEach(function (ele) {
  896. ele.removeAttribute('activate');
  897. });
  898. }
  899. /**显示翻译引擎指示器*/
  900. function engineActivateShow() {
  901. engineActivateHide();
  902. icon.querySelector('img[icon-id="' + engineId + '"]').setAttribute('activate', 'activate');
  903. }
  904. /**显示 icon*/
  905. function showIcon(e) {
  906. log('showIcon event:', e);
  907. var offsetX = 4; // 横坐标翻译图标偏移
  908. var offsetY = 8; // 纵坐标翻译图标偏移
  909. // 更新翻译图标 X、Y 坐标
  910. if (e.pageX && e.pageY) { // 鼠标
  911. log('mouse pageX/Y');
  912. pageX = e.pageX;
  913. pageY = e.pageY;
  914. }
  915. if (e.changedTouches) { // 触屏
  916. if (e.changedTouches.length > 0) { // 多点触控选取第 1 个
  917. log('touch pageX/Y');
  918. pageX = e.changedTouches[0].pageX;
  919. pageY = e.changedTouches[0].pageY;
  920. // 触屏修改翻译图标偏移(Android、iOS 选中后的动作菜单一般在当前文字顶部,翻译图标则放到底部)
  921. offsetX = -26; // 单个翻译图标块宽度
  922. offsetY = 16 * 3; // 一般字体高度的 3 倍,距离系统自带动作菜单、选择光标太近会导致无法点按
  923. }
  924. }
  925. log('selected:' + selected + ', pageX:' + pageX + ', pageY:' + pageY)
  926. if (e.target == icon || (e.target.parentNode && e.target.parentNode == icon)) { // 点击了翻译图标
  927. e.preventDefault();
  928. return;
  929. }
  930. selected = window.getSelection().toString().trim(); // 当前选中文本
  931. log('selected:' + selected + ', icon display:' + icon.style.display);
  932. if (selected && icon.style.display !== 'block' && /[\u30a1-\u30f6\u3041-\u3093\uFF00-\uFFFF\u4e00-\u9fa5]/.test(selected) && pageX && pageY) { // 显示翻译图标
  933. log('show icon');
  934. icon.style.top = pageY + offsetY + 'px';
  935. icon.style.left = pageX + offsetX + 'px';
  936. icon.style.display = 'block';
  937. // 兼容部分 Content Security Policy
  938. icon.style.position = 'absolute';
  939. icon.style.zIndex = zIndex;
  940. } else if (!selected) { // 隐藏翻译图标
  941. log('hide icon');
  942. hideIcon();
  943. }
  944. }
  945. /**隐藏 icon*/
  946. function hideIcon() {
  947. icon.style.display = 'none';
  948. icon.removeAttribute('activate'); // 标注面板关闭
  949. content.style.display = 'none';
  950. engineId = '';
  951. engineTriggerTime = 0;
  952. pageX = 0;
  953. pageY = 0;
  954. engineActivateHide();
  955. audioCache = {};
  956. engineResult = {};
  957. forceStopDrag();
  958. var s = icon.querySelector('.langs-cj');
  959. if (s) {
  960. s.parentNode.removeChild(s);
  961. }
  962. var k = icon.querySelector('img[icon-id="icon-speech"]');
  963. speechSynthesis.cancel();
  964. if (k) {
  965. k.removeEventListener('click', speech, false)
  966. }
  967. }
  968. /**发音*/
  969. function play(obj) {
  970. if (obj.url in audioCache) { // 查找缓存
  971. log('audio in cache', obj, audioCache);
  972. playArrayBuffer(audioCache[obj.url]); // 播放
  973. } else {
  974. ajax(obj.url, function (rst, res) {
  975. audioCache[obj.url] = res.response; // 放入缓存
  976. playArrayBuffer(audioCache[obj.url]); // 播放
  977. }, function (rst) {
  978. log(rst);
  979. }, {
  980. responseType: 'arraybuffer'
  981. });
  982. }
  983. }
  984. /**播放 ArrayBuffer 音频*/
  985. function playArrayBuffer(arrayBuffer) {
  986. var context = new iframeWin.AudioContext() || new iframeWin.webkitAudioContext();
  987. context.decodeAudioData(arrayBuffer.slice(0), function (audioBuffer) { // `slice(0)`克隆一份(`decodeAudioData`后原数组清空)
  988. var bufferSource = context.createBufferSource();
  989. bufferSource.buffer = audioBuffer;
  990. bufferSource.connect(context.destination);
  991. bufferSource.start();
  992. });
  993. }
  994. /**得到发音按钮*/
  995. function getPlayButton(obj) {
  996. var type = document.createElement('a');
  997. type.innerHTML = obj.name;
  998. type.setAttribute('href', 'javascript:void(0)');
  999. type.setAttribute('class', 'audio-button');
  1000. type.setAttribute('title', '点击发音');
  1001. type.addEventListener('mouseup', function () {
  1002. play(obj);
  1003. });
  1004. return type;
  1005. }
  1006.  
  1007. // 音频播放器
  1008. function AudioPlayer() {
  1009. var audio = document.createElement('audio');
  1010. audio.setAttribute('controls', 'controls');
  1011. audio.style.display = 'none';
  1012. // audio.setAttribute('src', src);
  1013. document.body.appendChild(audio);
  1014.  
  1015. this.play = function (src) {
  1016. audio.setAttribute('src', src);
  1017. audio.play();
  1018. return this;
  1019. };
  1020. this.stop = function () {
  1021. audio.pause();
  1022. return this;
  1023. };
  1024. // 播放结束回调
  1025. this.end = function (callback) {
  1026. var repeat = setInterval(function () {
  1027. if (audio.ended) {
  1028. clearInterval(repeat);
  1029. callback && callback();
  1030. }
  1031. }, 100);
  1032. setTimeout(function () {
  1033. clearInterval(repeat);
  1034. }, 5000);
  1035. };
  1036.  
  1037. return this;
  1038. }
  1039.  
  1040.  
  1041. //查日语没有结果时,查中日词典
  1042. function cj(time, tex, audio) {
  1043. ajax('https://dict.hjenglish.com/jp/cj/' + encodeURIComponent(tex), function (rst) {
  1044. putEngineResult(ids.HJENGLISH, function (rst, time, text, audio) {
  1045. var dom = document.createElement('div');
  1046. dom.setAttribute('class', ids.HJENGLISH);
  1047. var parser = new DOMParser(), doc = parser.parseFromString(rst, 'text/html');
  1048. //content = doc.documentElement;
  1049. var x = doc.getElementsByClassName('word-details')[0];
  1050. if (!x) {
  1051.  
  1052. return htmlToDom('error: 查询无结果,可能没这个词');
  1053. }
  1054. var engine = contentList.querySelector('tr-engine[data-id="' + ids.HJENGLISH + '"]');
  1055. var a = engine.querySelector('a.title');
  1056. a.href = a.href.replace('/jc/', '/cj/');
  1057. //engine.querySelector('a[rel=noreferrer noopener]');
  1058. var fot = x.querySelector('.word-details-pane-footer');
  1059. fot.parentNode.removeChild(fot);
  1060. var add = x.querySelector('.add-scb');
  1061. add.parentNode.removeChild(add);
  1062. var s = x.querySelector('.simple-definition');
  1063. var ar = s.textContent.split(';');
  1064. var y = '<ol>';
  1065. if (ar.length > 1) {
  1066. ar.forEach(function (string, index,) {
  1067. y += `<li>${string}</li>`;
  1068. });
  1069. y += '</ol>';
  1070. s.innerHTML = y;
  1071. }
  1072. var t = x.querySelectorAll('.detail-groups dl dd');
  1073. if (t.length > 0) {
  1074. t.forEach((value => {
  1075. value.style = 'margin-inline-start:6px';
  1076. }))
  1077. }
  1078. var ul = x.querySelectorAll('.detail-groups dl dd ul');
  1079. //console.log('sss')
  1080. if (ul.length > 0) {
  1081. ul.forEach((v, i) => {
  1082. v.style.display = 'none';
  1083. //console.log(v.childNodes.length)
  1084. if (v.children.length < 1) {
  1085. return;
  1086. }
  1087. var y = v.previousElementSibling.lastElementChild;
  1088. var s = document.createElement('b');
  1089. s.style.cursor = 'pointer';
  1090. s.style.color = 'firebrick';
  1091. s.style.fontSize = '0.8em';
  1092. s.textContent = '例';
  1093. s.title = '点击查看或隐藏例句';
  1094. s.onclick = (event) => {
  1095. v.style.display = v.style.display === 'none' ? 'block' : 'none';
  1096. };
  1097. y.appendChild(s);
  1098. });
  1099. }
  1100. var er = x.querySelectorAll('.detail-groups dl dd h3');
  1101. if (er.length > 0) {
  1102. er.forEach(value => {
  1103. value.style.fontSize = '1em';
  1104. })
  1105. }
  1106.  
  1107. var li = x.querySelectorAll('.detail-groups dl dd ol,ul');
  1108. if (li) {
  1109. li.forEach(function (e) {
  1110. e.style.listStyle = 'list-style: none';
  1111. });
  1112. }
  1113. //添加音频按钮
  1114. var auds = x.querySelectorAll('.word-audio');
  1115. auds.forEach(function (aud) {
  1116. if (aud.getAttribute('data-src')) {
  1117. aud.classList.add('audio');
  1118. if (aud.parentElement.classList.contains('pronounces')) {
  1119. aud.classList.add('audio-light');
  1120. }
  1121. if (aud.parentElement.classList.contains('def-sentence-from')) {
  1122. aud.parentElement.innerHTML = aud.parentElement.innerHTML.replace(tex, `<mark data-markjs="true" class="highlight">${tex}</mark>`);
  1123. }
  1124. }
  1125. });
  1126.  
  1127. return x;
  1128. }(rst, time, tex, audio), time);
  1129. showContent();
  1130. }, function (rst) {
  1131. putEngineResult(ids.HJENGLISH, htmlToDom('error: 无法连接翻译服务'), time);
  1132. showContent();
  1133. }, {
  1134. headers: {
  1135. 'Cookie': 'HJ_SID=' + uuid() + '; HJ_SSID_3=' + uuid() + '; HJ_CST=1; HJ_CSST_3=1; HJ_UID=' + uuid(),
  1136. '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'
  1137. }
  1138. });
  1139. }
  1140.  
  1141.  
  1142. /**沪江小D排版*/
  1143. function parseHjenglish(rst, time, tex) {
  1144. var audio = new AudioPlayer();
  1145. var dom = document.createElement('div');
  1146. dom.addEventListener('click', function (event) {
  1147. var tar = event.target;
  1148. if (tar.getAttribute('data-src') && tar.classList.contains('audio')) {
  1149. audio.play(tar.getAttribute('data-src'))
  1150. }
  1151. }, false);
  1152. dom.setAttribute('class', ids.HJENGLISH);
  1153. var parser = new DOMParser(), doc = parser.parseFromString(rst, 'text/html'),
  1154. //content = doc.documentElement;
  1155. content = doc.getElementsByClassName('word-details')[0];
  1156. if (!content) {
  1157. return cj(time, tex, audio);
  1158. }
  1159. dom.appendChild(content);
  1160. //添加音频按钮
  1161. var auds = dom.querySelectorAll('.word-audio');
  1162. auds.forEach(function (aud) {
  1163. if (aud.getAttribute('data-src')) {
  1164. aud.classList.add('audio');
  1165. if (aud.parentElement.classList.contains('pronounces')) {
  1166. aud.classList.add('audio-light');
  1167. }
  1168. if (aud.parentElement.classList.contains('def-sentence-from')) {
  1169. aud.parentElement.innerHTML = aud.parentElement.innerHTML.replace(tex, `<mark data-markjs="true" class="highlight">${tex}</mark>`);
  1170. }
  1171. }
  1172. });
  1173.  
  1174. var panee = dom.querySelectorAll('.word-details-pane-footer');
  1175. panee.forEach(function (pane) {
  1176. pane.parentNode.removeChild(pane);
  1177. });
  1178. var h = dom.querySelectorAll('.simple h2');
  1179. if (h) {
  1180. h.forEach(function (h) {
  1181. h.outerHTML = `<b>${h.textContent}</b>`;
  1182. })
  1183. }
  1184.  
  1185. var wDHs = dom.querySelectorAll('.word-details-header>p');
  1186. wDHs.forEach(function (wDH) {
  1187. wDH.parentNode.removeChild(wDH);
  1188. });
  1189. var addScbs = dom.querySelectorAll('.add-scb');
  1190. addScbs.forEach(function (addScb) {
  1191. addScb.parentNode.removeChild(addScb)
  1192.  
  1193. });
  1194.  
  1195. var feed = dom.querySelector('.button word-details-button-feedback');
  1196. if (feed) {
  1197. feed.parentNode.removeChild(feed)
  1198. }
  1199. var tabss = dom.querySelectorAll('.word-details-tab');
  1200.  
  1201. var ul = dom.querySelectorAll('.detail-groups dl dd ul');
  1202. if (ul.length > 0) {
  1203. ul.forEach((v, i) => {
  1204. v.style.display = 'none';
  1205.  
  1206. if (v.children.length < 1) {
  1207. return;
  1208. }
  1209. var y = v.previousElementSibling.lastElementChild;
  1210. var s = document.createElement('b');
  1211. s.style.cursor = 'pointer';
  1212. s.style.color = 'firebrick';
  1213. s.style.fontSize = '0.8em';
  1214. s.textContent = '例';
  1215. s.title = '点击查看或隐藏例句';
  1216. s.onclick = (event) => {
  1217. v.style.display = v.style.display === 'none' ? 'block' : 'none';
  1218. };
  1219. y.appendChild(s);
  1220. });
  1221. }
  1222.  
  1223. if (tabss.length > 1) {
  1224. var panes = dom.querySelectorAll('.word-details-pane');
  1225. var j = 0;
  1226. var dat = panes;
  1227. for (j; j < tabss.length; ++j) {
  1228. tabss[j].addEventListener('click', function () {
  1229. if (this.classList.contains('word-details-tab-active')) {
  1230. return false
  1231. }
  1232. this.parentNode.querySelector('.word-details-tab-active').classList.remove('word-details-tab-active');
  1233. //this.parentNode.querySelector('.word-details-tab-active').classList.remove('word-details-tab-active');
  1234. var that = this;
  1235. this.classList.add('word-details-tab-active');
  1236. tabss.forEach(function (v, k, p) {
  1237. if (v === that) {
  1238.  
  1239. panes = dom.querySelectorAll('.word-details-pane');
  1240. panes.forEach((value, key) => {
  1241. if (value.style.display === 'block' || value.style.display === '') {
  1242. value.style.display = 'none';
  1243. }
  1244. });
  1245. panes.forEach((value, key) => {
  1246. if (key === k) {
  1247. value.style.display = 'block';
  1248. }
  1249. });
  1250. }
  1251. });
  1252. }, true)
  1253. }
  1254. }
  1255. if (/[\u4e00-\u9fa5]/.test(tex) || /[^\x00-\xff]/.test(tex)) {
  1256. var img = icon.querySelector('img');
  1257. var im = document.createElement('span');
  1258. im.style = `
  1259. font-size: 14px;
  1260. line-height: 20px;
  1261. color: rgb(89, 8, 99);
  1262. cursor: pointer;
  1263. float: right;
  1264. margin-right: 1rem;
  1265. `;
  1266. im.title = '点击查看汉字日文查询';
  1267. im.classList.add('langs-cj');
  1268. im.textContent = '中日';
  1269. im.onclick = function () {
  1270. im.parentNode.removeChild(im)
  1271. contentList.querySelector('tr-engine').setAttribute('data-id', ids.HJENGLISH);
  1272. return cj(time, tex, audio);
  1273. };
  1274. img.parentNode.insertBefore(im, img.nextSibling)
  1275. }
  1276.  
  1277. //var uls = dom.querySelectorAll('.detail-groups');
  1278. //debugger
  1279. return dom;
  1280. }
  1281. /**
  1282. * 谷歌翻译 token 计算
  1283. * https://github.com/hujingshuang/MTrans
  1284. * */
  1285. function token(a) {
  1286. var k = "";
  1287. var b = 406644;
  1288. var b1 = 3293161072;
  1289.  
  1290. var jd = ".";
  1291. var sb = "+-a^+6";
  1292. var Zb = "+-3^+b+-f";
  1293.  
  1294. for (var e = [], f = 0, g = 0; g < a.length; g++) {
  1295. var m = a.charCodeAt(g);
  1296. 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)
  1297. }
  1298. a = b;
  1299. for (f = 0; f < e.length; f++) a += e[f],
  1300. a = RL(a, sb);
  1301. a = RL(a, Zb);
  1302. a ^= b1 || 0;
  1303. 0 > a && (a = (a & 2147483647) + 2147483648);
  1304. a %= 1E6;
  1305. return a.toString() + jd + (a ^ b)
  1306. };
  1307.  
  1308. function RL(a, b) {
  1309. var t = "a";
  1310. var Yb = "+";
  1311. for (var c = 0; c < b.length - 2; c += 3) {
  1312. var d = b.charAt(c + 2),
  1313. d = d >= t ? d.charCodeAt(0) - 87 : Number(d),
  1314. d = b.charAt(c + 1) == Yb ? a >>> d : a << d;
  1315. a = b.charAt(c) == Yb ? a + d & 4294967295 : a ^ d
  1316. }
  1317. return a
  1318. }
  1319. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址