鼠标拖拽

鼠标拖拽,按住鼠标左键拖拽选中文本、链接、图片后复制、打开、搜索,Alt+Y进入设置,Esc退出设置

目前為 2021-05-14 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name 鼠标拖拽
  3. // @version 1.3
  4. // @namespace http://tampermonkey.net/
  5. // @description 鼠标拖拽,按住鼠标左键拖拽选中文本、链接、图片后复制、打开、搜索,Alt+Y进入设置,Esc退出设置
  6. // @author lyscop
  7. // @icon https://i.imgur.com/obQUjIi.png
  8. // @include *
  9. // @run-at document-end
  10. // @grant GM_addStyle
  11. // @grant GM_openInTab
  12. // @grant GM_setValue
  13. // @grant GM_getValue
  14. // @grant GM.setValue
  15. // @grant GM.getValue
  16. // @grant GM_setClipboard
  17. // @grant GM_download
  18. // @grant GM_addValueChangeListener
  19. // @grant GM_notification
  20. // @grant window.close
  21. // @grant GM_getResourceText
  22. // @grant GM_xmlhttpRequest
  23. // @grant GM_deleteValue
  24. // @grant GM_listValues
  25. // ==/UserScript==
  26.  
  27.  
  28. (function() {
  29. 'use strict';
  30. //==========①=========================
  31. let storage = {
  32. get: function(name, defaultValue) {
  33. return GM_getValue(name, defaultValue);
  34. },
  35. set: function(name, data) {
  36. return GM_setValue(name, data);
  37. }
  38. },
  39. runtime = {
  40. sendMessage: function(data){
  41. return Promise.resolve(this.processMessage(data));
  42. },
  43. processMessage: function(data){
  44. switch (data.subject) {
  45. case "gestureFrameMousedown":
  46. case "gestureFrameMousemove":
  47. case "gestureFrameMouseup":
  48. gestureHandler.handleMessage(data);
  49. break;
  50. case 'gestureChange':
  51. /*if(this.captureGesture){
  52. Ui.captureGesture(data.data.gesture, "recorddingGesture");
  53.  
  54. return;
  55. }*/
  56. try {
  57. let actionName = '';
  58. if(cfg.gesture[data.data.gesture].alias)
  59. actionName = cfg.gesture[data.data.gesture].alias;
  60. else
  61. actionName = local.gesture[cfg.gesture[data.data.gesture].name][cfg.language];
  62. return {action:actionName};
  63. } catch(e) {}
  64. break;
  65. case 'gestureEnd':
  66. /*if(this.captureGesture){
  67. Ui.captureGesture(data.data.gesture);
  68. return;
  69. }*/
  70. try {
  71. let action = cfg.gesture[data.data.gesture];
  72. Fn[action.name](action.arg, data.data);
  73. } catch(e) {
  74. // console.log(e);
  75. }
  76. break;
  77. case 'dragChange':
  78. if(this.captureGesture){
  79. Ui.captureGesture(data.data.gesture, "recorddingGesture");
  80.  
  81. return;
  82. }
  83. try {
  84. let actionName = '',
  85. typeAndData = getDragFn(data.data);
  86. if(typeAndData[1].alias)
  87. actionName = typeAndData[1].alias;
  88. else
  89. actionName = local[typeAndData[0]][typeAndData[1].name][cfg.language];
  90. return {action:actionName};
  91. } catch(e) {}
  92. break;
  93. case 'dragEnd':
  94. if(this.captureGesture){
  95. Ui.captureGesture(data.data.gesture);
  96. return;
  97. }
  98. try {
  99. let action = getDragFn(data.data)[1];
  100. Fn[action.name](action.arg, data.data);
  101. } catch(e) {
  102. // console.log(e);
  103. }
  104. break;
  105. default:
  106. break;
  107. }
  108. },
  109. captureGesture:false
  110. },
  111. _cfg = {
  112. Gesture: {
  113. mouseButton: 2,
  114. suppressionKey: "",
  115. distanceThreshold: 2,
  116. distanceSensitivity: 20,
  117. Timeout: {
  118. active: true,
  119. duration: 1
  120. }
  121. },
  122. Hinter: {
  123. background : '',
  124. fontSize: 0,
  125. lineColor: null,
  126. minLineWidth: 1,
  127. maxLineWidth: 10,
  128. lineGrowth: 0.6,
  129. funNotDefine: null
  130. },
  131. Drag: {
  132. linktextAslink: true,
  133. dragInTextarea: true
  134. },
  135. directions: 8,//方向
  136. language: "zh",
  137. gesture:{
  138. //"2": {name:"toTop", arg:[]},
  139. },
  140. text: {// dragText
  141. "9": {name:"copyText", arg:[]},
  142. "4": {name:"deleteText", arg:[]},
  143. "7": {name:"cutText", arg:[]},
  144. "1": {name:"pasteText", arg:[]},
  145. "2": {name:"space", arg:[]},
  146. "3": {
  147. name:"searchText",
  148. arg:["https://www.baidu.com/s?wd=", true, true]
  149. },
  150. "6": {
  151. name:"searchText",
  152. arg:["http://www.google.com/search?q=", true, true]
  153. }
  154. },
  155. link: {// drag link
  156. "3": {name:"openLink", arg:[]},
  157. "9": {name:"copyLink", arg:[]},
  158. "1": {name:"copyLinkText", arg:[]},
  159. },
  160. image: {// drag image
  161. "46": {name:"saveImg", arg:[]},
  162. "64": {name:"copyImg", arg:[]},
  163. "2": {name:"openImgURL", arg:[]},
  164. "3": {
  165. name:"searchImg",
  166. arg:['https://graph.baidu.com/details?isfromtusoupc=1&tn=pc&carousel=0&promotion_name=pc_image_shituindex&extUiData%5bisLogoShow%5d=1&image=U-R-L', true, true]
  167. },
  168. "7": {
  169. name:"searchImg",
  170. arg:['https://yandex.com/images/search?rpt=imageview&url=U-R-L', true, true]
  171. },
  172. "4": {
  173. name:"searchImg",
  174. arg:['https://www.tineye.com/search?url=U-R-L', true, true]
  175. },
  176. "6": {
  177. name:"searchImg",
  178. arg:['https://www.google.com/searchbyimage?image_url=U-R-L', true, true]
  179. },
  180. "9": {name:"copyImgLink", arg:[]},
  181. "1": {name:"copyImgURL", arg:[]},
  182. "8": {name:"openImgLink", arg:[]},
  183. //"4": {name:"selectImg", arg:[]}
  184. },
  185. },
  186. cfg = storage.get('cfg',_cfg),
  187. Fn = {
  188. userDefine: function(argumentArr, data){
  189. try {
  190. new Function("mpArray", "mpData", mpUnescape(argumentArr[0]))(data);
  191. } catch(e) {
  192. console.log(e);
  193. }
  194. },
  195. stopLoading: function() {
  196. window.stop();
  197. },
  198. reload: function() {
  199. history.go(0);
  200. //window.location.reload();
  201. },
  202. reloadNoCache: function() {
  203. window.location.reload(true);
  204. },
  205. close: function() {
  206. window.close();
  207. },
  208. back: function() {
  209. history.back();
  210. },
  211. forward: function() {
  212. history.forward();
  213. },
  214. toTop: function() {
  215. document.documentElement.scrollTo(0, 0);
  216. },
  217. toBottom: function() {
  218. document.documentElement.scrollTo(0, 9999999);
  219. },
  220. reopenTab: function() {
  221. //GreasyMonkdy:
  222. // GM_openInTab(GM_getValue('latestTab'),false);
  223. //TamperMonkey:
  224. GM_openInTab(GM_getValue('latestTab', 'about:blank'), {
  225. active: true
  226. });
  227. },
  228. URLLevelUp: function() {
  229. //当前网址的层次结构向上一层
  230. if (window.location.href[window.location.href.length - 1] === "/")
  231. window.location.href = "../";
  232. else
  233. window.location.href = "./";
  234. },
  235. //clone curren tab ,background
  236. cloneTab: function() {
  237. GM_openInTab(location.href, {
  238. active: false
  239. });
  240. },
  241. //open new blank tab
  242. openBlankTab: function() {
  243. GM_openInTab('about:blank', {
  244. active: true
  245. });
  246. },
  247. //view source
  248. viewSource: function() {
  249. GM_openInTab('view-source:'+location.href, {
  250. active: true
  251. });
  252. },
  253. fkVip: function(argumentArr) {
  254. GM_openInTab(argumentArr[0]+location.href, {active:true});
  255. },
  256. closeOtherTabs: function() {
  257. GM_setValue('closeAll', Date());
  258. },
  259.  
  260. deleteText: function() {
  261. try {
  262. if(document.execCommand("Delete", "false", null)){
  263. //success info
  264. count(newFn.deleteText);
  265. console.log("doSomethingOk");
  266. } else{
  267. //fail info
  268. console.log("doSomethingNotOk");
  269. }
  270. } catch (error) {
  271. return document.execCommand("Delete", "false", null);
  272. }
  273. },
  274. cutText: function() {
  275. try {
  276. if(document.execCommand("Cut", "false", null)){
  277. count(newFn.cutText);
  278. console.log("doSomethingOk");
  279.  
  280. } else{
  281. //fail info
  282. console.log("doSomethingNotOk");
  283. }
  284. } catch (error) {
  285. return document.execCommand("Cut", "false", null);
  286. }
  287. },
  288. pasteText: function() {
  289. try {
  290. if(window.navigator.clipboard.readText()
  291. .then(text => {
  292. document.execCommand("insertText", "false", text);
  293. })
  294. .catch(err => {
  295. console.error('Failed to read clipboard contents: ', err);
  296. })) {
  297. //success info
  298. count(newFn.pasteText);
  299. console.log("doSomethingOk");
  300. } else{
  301. //fail info
  302. console.log("doSomethingNotOk");
  303. }
  304. } catch (error) {
  305. return;
  306. }
  307. },
  308. space: function() {
  309. try {
  310.  
  311. if(document.execCommand("insertText", "false", " ")){
  312. count(newFn.space);
  313. console.log("doSomethingOk");
  314. } else{
  315. //fail info
  316. console.log("doSomethingNotOk");
  317. }
  318. } catch (error) {
  319. return document.execCommand("insertText", "false", " ");
  320. }
  321. },
  322. searchText: function(argumentArr, data) {
  323. GM_openInTab(argumentArr[0] + encodeURIComponent(data.textSelection),
  324. {
  325. //active: argumentArr[1] != "false",
  326. //insert: argumentArr[2] != "false",
  327. active: false,
  328. insert: true,
  329. setParent: true //makes the browser re-focus the current tab on close.
  330. });
  331. count(newFn.searchText);
  332. },
  333. copyText: function(argumentArr, data) {
  334. GM_setClipboard(data.textSelection, "text");
  335. //showclipboard(data.textSelection);
  336. window.navigator.clipboard.readText()
  337. .then(text => {
  338.  
  339. showclipboard(text);
  340. })
  341. .catch(err => {
  342. console.error('Failed to read clipboard contents: ', err);
  343. });
  344. count(newFn.copyText);
  345. },
  346. openLink: function(argumentArr, data) {
  347. //TamperMonkey
  348. GM_openInTab(getLink(data), {
  349. active: false,
  350. insert: true,
  351. setParent :true
  352. });
  353. count(newFn.openLink);
  354. },
  355. copyLink: function(argumentArr, data) {
  356. GM_setClipboard(getLink(data), "text");
  357.  
  358. //showclipboard(getLink(data));
  359. window.navigator.clipboard.readText()
  360. .then(text => {
  361.  
  362. showclipboard(text);
  363. })
  364. .catch(err => {
  365. console.error('Failed to read clipboard contents: ', err);
  366. });
  367. count(newFn.copyLink);
  368. },
  369. copyLinkText: function(argumentArr, data) {
  370. GM_setClipboard(data.target.textContent || data.textSelection, "text");
  371.  
  372. //showclipboard(data.target.textContent || data.textSelection);
  373. window.navigator.clipboard.readText()
  374. .then(text => {
  375.  
  376. showclipboard(text);
  377. })
  378. .catch(err => {
  379. console.error('Failed to read clipboard contents: ', err);
  380. });
  381. count(newFn.copyLinkText);
  382.  
  383. },
  384.  
  385. copyImgLink: function(argumentArr, data) {
  386. GM_setClipboard(getLink(data), "text");
  387.  
  388. window.navigator.clipboard.readText()
  389. .then(text => {
  390.  
  391. showclipboard(text);
  392. })
  393. .catch(err => {
  394. console.error('Failed to read clipboard contents: ', err);
  395. });
  396. count(newFn.copyImgLink);
  397.  
  398. },
  399. openImgLink: function(argumentArr, data) {
  400. GM_openInTab(getLink(data), {
  401. active: false,
  402. insert: true,
  403. setParent :true
  404. });
  405. count(newFn.openImgLink);
  406. },
  407. saveImg: function(argumentArr, data) {
  408. //TamperMonkey
  409. let name = data.target.src.split('/').pop();
  410.  
  411. let d = new Date();
  412. let TimeDateFormatText = '[Year]-[Month]-[Day] [Hour][Minute]';
  413. let timetext = TimeDateFormatText.replace(/\[YEAR\]/gi, d.getFullYear().toString()).replace(/\[MONTH\]/gi, ('0' +(d.getMonth()+1).toString()).slice(-2)).replace(/\[DAY\]/gi, ('0' +d.getDate().toString()).slice(-2)).replace(/\[HOUR\]/gi, ('0' +d.getHours().toString()).slice(-2)).replace(/\[MINUTE\]/gi, ('0' +d.getMinutes().toString()).slice(-2)).replace(/\[SECOND\]/gi, ('0' +d.getSeconds().toString()).slice(-2));
  414.  
  415. GM_download(data.target.src, timetext);
  416. showclipboard("已保存");
  417. count(newFn.saveImg);
  418. //method 2
  419. /*
  420. let a = document.createElement('a');
  421. a.href = dObj.img; a.setAttribute('download', dObj.img.split('/').pop());
  422. document.documentElement.appendChild(a);
  423. a.click();
  424. a.parentElement.remove(a);
  425. */
  426. /* //jQuery:
  427. $("<a>").attr("href", actionFn.request.selimg).attr("download", actionFn.request.selimg.split('/').pop()).appendTo("body");
  428. a[0].click();
  429. a.remove();
  430. */
  431. },
  432. searchImg: function(argumentArr, data) {
  433. //TamperMonkey
  434. GM_openInTab(argumentArr[0].replace(/U-R-L/, data.target.src), {
  435. //active: argumentArr[1] != "false",
  436. //insert: argumentArr[2] != "true",
  437. active: false,
  438. insert: true,
  439. setParent: true
  440. });
  441. count(newFn.searchImg);
  442. },
  443. selectImg: function(argumentArr, data) {
  444. // it may not working on some browsers [develping standard]
  445. //TamperMonkey
  446. document.execCommand('selectAll');
  447. let sel = document.getSelection();
  448. sel.collapse(data.target.self, 0);
  449. sel.modify("extend", "forward", "character");
  450. },
  451. //not working:
  452. copyImage: function(argumentArr, data) {
  453. /*let canvas = canvasDrawTheImage(e);
  454. // get image as blob
  455. canvas.canvas.toBlob((blob) => {
  456. GM_setClipboard(blob, {
  457. type: canvas.type,
  458. mimetype: canvas.mime
  459. });
  460. }, canvas.mime);*/
  461. copyImageto(data.target.src);
  462. count(newFn.copyImage);
  463. },
  464. /*image2DataURL: function(e) {
  465. //canvas绘制图片,由于浏览器的安全考虑:
  466. //如果在使用canvas绘图的过程中,使用到了外域的图片资源,那么在toDataURL()时会抛出安全异常:
  467. let canvas = canvasDrawTheImage(e).canvas;
  468. let dataURL = canvas.toDataURL();
  469. GM_setClipboard(dataURL, "text");
  470. },*/
  471. copyImgURL: function(argumentArr, data) {
  472. //TamperMonkey
  473. GM_setClipboard(data.target.src, "text");
  474.  
  475. showclipboard(data.target.src);
  476. count(newFn.copyImgURL);
  477. },
  478. openImgURL: function(argumentArr, data) {
  479. //TamperMonkey
  480. GM_openInTab(data.target.src, {
  481. active: false,
  482. insert: true,
  483. setParent :true
  484. });
  485. count(newFn.openImgURL);
  486. },
  487. setting: function() {
  488. if (document.getElementById('MPsetting')) {
  489. return;
  490. }else Ui.init();
  491. }
  492. },
  493. local = {
  494. gesture:{
  495. /*stopLoading: {zh:'停止加载', en:'StopLoading'},
  496. reload: {zh:'刷新', en:'Refresh'},
  497. reloadNoCache: {zh:'清缓存刷新', en:'Refresh Without Cache'},
  498. close: {zh:'关闭', en:'Close'},
  499. back: {zh:'后退', en:'Back'},
  500. forward: {zh:'前进', en:'Forward'},
  501. toTop: {zh:'到顶部', en:'Scroll to Top'},
  502. toBottom: {zh:'到底部', en:'Scroll to Bottom'},
  503. reopenTab: {zh:'打开最近关闭窗口', en:'Reopen Latest Closed Window'},
  504. setting: {zh:'设置', en:'Settings'},
  505. URLLevelUp: {zh:'网址向上一层', en:'URL hierarchy up'},
  506. cloneTab: {zh:'克隆标签页', en:'Duplicate This Tab'},
  507. openBlankTab: {zh:'打开空白页', en:'Open New Blank Tab'},
  508. viewSource: {zh:'看网页源代码', en:'View Source'},
  509. fkVip: {zh:'破解VIP视频', en:'Crack to Watch VIP Video'},
  510. closeOtherTabs: {zh:'关闭其他标签', en:'Close Other Tabs'},
  511. translateSelect: {zh:'开启划词翻译', en:'Turn on Select And Translate'},
  512. //开发者功能
  513. contentEditable: {zh:'元素内容可编辑', en:'Element Content Editable'},
  514. userDefine: {zh:'自定义', en:'User Define'}*/
  515. },
  516. //drag text
  517. text: {
  518. searchText: {zh:'搜索选中文本', en:'Search Selected Text'},
  519. copyText: {zh:'复制选中文本', en:'Copy Selected Text'},
  520. deleteText: {zh:'退格', en:'Delete Selected Text'},
  521. cutText: {zh:'剪切', en:'Cut Selected Text'},
  522. pasteText: {zh:'粘贴', en:'Paste Selected Text'},
  523. space: {zh:'空格', en:'Input Space'},
  524. userDefine: {zh:'自定义', en:'User Define'}
  525. },
  526. //drag link
  527. link:{
  528. openLink: {zh:'打开链接', en:'Open Link'},
  529. copyLink: {zh:'复制链接', en:'Copy Link'},
  530. copyLinkText: {zh:'复制链接文字', en:'Copy Link Text'},
  531. userDefine: {zh:'自定义', en:'User Define'}
  532. },
  533. //drag image
  534. image:{
  535. saveImg: {zh:'保存图片', en:'Save Image'},
  536. searchImg: {zh:'搜索图片', en:'Search Image'},
  537. copyImage: {zh:'复制图片', en:'Copy Image to ClickBoard'},
  538. copyImgURL: {zh:'复制图片链接(img)', en:'Copy ImageURL'},
  539. openImgURL: {zh:'新标签打开图片(img)', en:'Open Image in New Tab'},
  540. copyImgLink: {zh:'复制图片链接', en:'Open Image in New Tab'},
  541. openImgLink: {zh:'打开图片链接', en:'Open Image in New Tab'},
  542. // image2DataURL: {zh:'复制图片为DataURL',en:'Copy Image as DataURL'},
  543. //selectImg: {zh:'选中图片', en:'Select This Image'},
  544. userDefine: {zh:'自定义', en:'User Define'}
  545. }
  546. };
  547.  
  548. let mouseEvent = null;
  549.  
  550. document.addEventListener('mousemove', event => {
  551. mouseEvent = event;
  552. });
  553.  
  554. document.addEventListener('keydown',function(event) {
  555.  
  556. var keynum;
  557. if(window.event) // IE
  558. keynum = event.keyCode;
  559. else if(event.which) // Netscape/Firefox/Opera
  560. keynum = event.which;
  561.  
  562. if(keynum == 89 && event.altKey) {//Alt+Y设置
  563. if (document.getElementById('MPsetting')) {
  564. return;
  565. }else Ui.init();
  566. }else if(keynum ==73 && event.altKey) {//Alt+I重置
  567. var mymessage = confirm("是否确定重置设置?");
  568. if(mymessage == true) {
  569. GM_deleteValue('cfg');
  570. }
  571. }else if(keynum == 27) {//Esc退出设置
  572. Ui.closesetting()
  573. }else if(keynum ==85 && event.altKey) {//Alt+U计数
  574. let allValue = GM_listValues();
  575. let vala = [];
  576. let valb = [];
  577. let valc = [];
  578. allValue.forEach(function(value, index) {//["searchText","Google搜索"]
  579.  
  580. Object.keys(local).forEach(function (value1, index1) {//[iconData[iconArraya], iconDara[iconArrayb]]
  581.  
  582. Object.keys(local[value1]).forEach(function(n) {//[name:,image:,host:][name:,image:,host:]
  583.  
  584. if(index1 == 1){
  585. if(value === n){
  586. vala.push(GM_getValue(value));
  587. }
  588. } else if(index1 == 2){
  589. if(value === n){
  590. valb.push(GM_getValue(value));
  591. }
  592. } else if(index1 == 3){
  593. if(value === n){
  594. valc.push(GM_getValue(value));
  595. }
  596. }
  597.  
  598. });
  599. });
  600. });
  601.  
  602. vala.sort(compare( "times"));
  603. valb.sort(compare( "times"));
  604. valc.sort(compare( "times"));
  605.  
  606. console.log("文字功能统计数据:");
  607. console.log(vala);
  608. console.log("链接功能统计数据:");
  609. console.log(valb);
  610. console.log("图片功能统计数据:");
  611. console.log(valc);
  612.  
  613. }
  614.  
  615. });
  616. //========②supported functions=======
  617. function getLink(data){
  618. if(data.link)
  619. return data.link.href;
  620. else if(data.target.src)
  621. return data.target.src;
  622. else return data.textSelection;
  623. }
  624.  
  625. //--> check if string is an url
  626. function isURL (string) {
  627. try {
  628. new URL(string);
  629. }
  630. catch (e) {
  631. return false;
  632. }
  633. return true;
  634. }
  635.  
  636. //--> checks if the current window is framed or not
  637. function inIframe () {
  638. try {
  639. return window.self !== window.top;
  640. }
  641. catch (e) {
  642. return true;
  643. }
  644. }
  645.  
  646. //--> returns all available data of the given target
  647. //--> this data is used by some background actions
  648. function getTargetData(target) {
  649. let data = {};
  650.  
  651. data.target = {
  652. src: target.currentSrc || target.src || null,
  653. title: target.title || null,
  654. alt: target.alt || null,
  655. textContent: target.textContent.trim(),
  656. nodeName: target.nodeName,
  657. self: target
  658. };
  659.  
  660. let link = getClosestLink(target);
  661. if (link) {
  662. data.link = {
  663. href: link.href || null,
  664. title: link.title || null,
  665. textContent: link.textContent.trim()
  666. };
  667. }
  668.  
  669. data.textSelection = getTextSelection();
  670.  
  671. return data;
  672. }
  673.  
  674. //--> returns the selected text, if no text is selected it will return an empty string
  675. //--> inspired by https://stackoverflow.com/a/5379408/3771196
  676. function getTextSelection () {
  677. // get input/textfield text selection
  678. if (document.activeElement &&
  679. typeof document.activeElement.selectionStart === 'number' &&
  680. typeof document.activeElement.selectionEnd === 'number') {
  681. return document.activeElement.value.slice(
  682. document.activeElement.selectionStart,
  683. document.activeElement.selectionEnd
  684. );
  685. }
  686. // get normal text selection
  687. return window.getSelection().toString();
  688. }
  689.  
  690. //--> calculates and returns the distance
  691. //--> between to points
  692. function getDistance(x1, y1, x2, y2) {
  693. return Math.hypot(x2 - x1, y2 - y1);
  694. }
  695.  
  696. //--> returns the closest hierarchical link node or null of given element
  697. function getClosestLink (node) {
  698. // bubble up the hierarchy from the target element
  699. while (node !== null && node.nodeName.toLowerCase() !== "a" && node.nodeName.toLowerCase() !== "area")
  700. node = node.parentElement;
  701. return node;
  702. }
  703. function getDirection(x, y, cx, cy){
  704. /*=================
  705. | |
  706. | 1↖ 2↑ 3↗ |
  707. | |
  708. | 4← 5 6→ |
  709. | |
  710. | 7↙ 8↓ 9↘ |
  711. | |
  712. |=================*/
  713. let d, t;
  714. if(cfg.directions == 4){ //4 directions
  715. if (Math.abs(cx - x) < Math.abs(cy - y)) {
  716. d = cy > y ? "8" : "2";
  717. } else {
  718. d = cx > x ? "6" : "4";
  719. }
  720. }else{ //8 directions
  721. t = (cy-y)/(cx-x);
  722. if (-0.4142<= t && t < 0.4142) d = cx > x ? '6' : "4";
  723. else if(2.4142 <= t || t< -2.4142) d = cy > y ? '8' : '2';
  724. else if(0.4142 <= t && t < 2.4142) d = cx > x ? '9' : '1';
  725. else d = cy > y ? '7' : '3';
  726. }
  727. return d;
  728. }
  729. // data: data.data
  730. function getDragFn(data){
  731. // let
  732. if(data.target.nodeName === "IMG")
  733. return ['image',cfg.image[data.gesture]];
  734. else if(data.link || data.target.nodeName === "A" || isURL(data.textSelection))
  735. return ['link', cfg.link[data.gesture]];
  736. else
  737. return ['text', cfg.text[data.gesture]];
  738. }
  739.  
  740. function mpEscape(str){
  741. if(!str) return;
  742. return str.replace(/"/g, "&quot;").replace(/'/g, "&apos;");
  743. }
  744. function mpUnescape(str){
  745. if(!str) return;
  746. return str.replace(/&quot;/g,'"').replace(/&apos;/g, "'");
  747. }
  748. function count(a) {
  749. //存储次数和日期
  750. let d = new Date();
  751. let TimeDateFormatText = '[Year]/[Month]/[Day] [Hour]:[Minute]:[Second]';
  752. let timetext = TimeDateFormatText.replace(/\[YEAR\]/gi, d.getFullYear().toString()).replace(/\[MONTH\]/gi, ('0' +(d.getMonth()+1).toString()).slice(-2)).replace(/\[DAY\]/gi, ('0' +d.getDate().toString()).slice(-2)).replace(/\[HOUR\]/gi, ('0' +d.getHours().toString()).slice(-2)).replace(/\[MINUTE\]/gi, ('0' +d.getMinutes().toString()).slice(-2)).replace(/\[SECOND\]/gi, ('0' +d.getSeconds().toString()).slice(-2));
  753.  
  754. if(GM_getValue(a)){
  755. GM_setValue(a, {
  756. 'name':a,
  757. 'times': GM_getValue(a).times + 1,
  758. 'date': timetext
  759. });
  760. }else{
  761. GM_setValue(a, {
  762. 'name':a,
  763. 'times': 1,
  764. 'date': timetext
  765. });
  766. }
  767.  
  768. console.log(a + ":" + GM_getValue(a).times + "times\0" + GM_getValue(a).date);
  769.  
  770. }
  771.  
  772. function compare( propertyName) {
  773. return function( object1, object2) {
  774. var value1 = object1[propertyName];
  775. var value2 = object2[propertyName];
  776. if(value1 < value2) {
  777. return 1;
  778. } else if(value1 > value2) {
  779. return - 1;
  780. } else {
  781. return 0;
  782. }
  783. }
  784. }
  785.  
  786. //对象的元素中获取该元素的名字
  787. const handler = {
  788. get: function(obj, prop) {
  789. //console.log(prop);
  790. //return obj[prop];
  791. return prop;
  792. }
  793. };
  794.  
  795. const newFn = new Proxy(Fn, handler);
  796. //复制图片到剪切板
  797. function imageToBlob(imageURL) {
  798. const img = new Image;
  799. const c = document.createElement("canvas");
  800. const ctx = c.getContext("2d");
  801. img.crossOrigin = "";
  802. //img.src = imageURL;
  803. img.src = imageURL + '?v=' + Math.random();
  804. return new Promise(resolve => {
  805. img.onload = function () {
  806. c.width = this.naturalWidth;
  807. c.height = this.naturalHeight;
  808. ctx.drawImage(this, 0, 0);
  809. c.toBlob((blob) => {
  810. // here the image is a blob
  811. resolve(blob)
  812. }, "image/png", 0.75);
  813. };
  814. })
  815. }
  816.  
  817. async function copyImageto(imageURL){
  818. const blob = await imageToBlob(imageURL)
  819. const item = new ClipboardItem({ "image/png": blob });
  820. navigator.clipboard.write([item]);
  821. showclipboard("已复制");
  822. }
  823.  
  824. //========③Hinter====================
  825. const Hinter = (function(){
  826. let modul = {};
  827.  
  828. modul.enable = function enable(){
  829. GestureHandler
  830. .on("start", addCanvas)
  831. .on("update", updateTrack)
  832. .on("change", updateHint)
  833. .on("abort", reset)
  834. .on("end", reset);
  835. };
  836.  
  837. modul.applySettings = function applySettings(Config){
  838. //background = Config.Hinter.background;//隐藏提示
  839. fontSize = Config.Hinter.fontSize;
  840. //lineColor = Config.Hinter.lineColor;
  841. minLineWidth = Config.Hinter.minLineWidth;
  842. maxLineWidth = Config.Hinter.maxLineWidth;
  843. //lineGrowth = Config.Hinter.lineGrowth;
  844. funNotDefine = Config.Hinter.funNotDefine;
  845. updateHintLayer();
  846. };
  847.  
  848. //private methods & value
  849. let
  850. background = '',//隐藏提示
  851. fontSize = 0,
  852. lineColor = null,
  853. minLineWidth = 1,
  854. maxLineWidth = 10,
  855. lineGrowth = 0.6,
  856. funNotDefine = '';
  857. let canvas = null,
  858. tip = null,
  859. ctx = null,
  860. hasCanvas = false;
  861.  
  862. function updateHintLayer(){
  863. canvas = tip = ctx = hasCanvas = null;
  864. createCanvaTips();
  865. }
  866. function createCanvaTips(){
  867. //create <canvas>
  868. canvas = document.createElement("canvas");
  869. canvas.id = 'MPcanvas';
  870. ctx = canvas.getContext("2d");
  871. //create tips<div>
  872. tip = document.createElement('div');
  873. tip.id = 'MPtips';
  874. tip.style.cssText = `background:#${background} !important; font-size: ${fontSize}px !important;`;
  875. }
  876. //<canvas> & tip<div> is ready, when mousemove or drag, append to show track & tips
  877. function addCanvas(e) {
  878. if(!canvas || !tip) createCanvaTips();
  879. document.documentElement.appendChild(tip); //append tip <div>
  880. document.documentElement.appendChild(canvas); //append <canvas>
  881. canvas.width = window.innerWidth; //set canvas attribute to clear content
  882. canvas.height = window.innerHeight;
  883. ctx.lineCap = "round";
  884. ctx.lineJoin = "round";
  885. //if(lineColor.length>6) canvas.style.opacity = parseInt(lineColor.slice(6),16)/255;
  886. canvas.style.opacity = 0;//不显示轨迹
  887. ctx.lineWidth = minLineWidth;
  888. //ctx.strokeStyle = '#' + lineColor.slice(0,6); //like delicious link color//line color
  889. hasCanvas = true;
  890. //allow drop
  891. tip.addEventListener('dragover', ()=>event.preventDefault(), false);
  892. canvas.addEventListener('dragover', ()=>event.preventDefault(), false);
  893. }
  894. //remove <canvas> and tips<div>,set flags to false
  895. function reset() {
  896. if (hasCanvas) {
  897. document.documentElement.removeChild(canvas);
  898. tip.innerHTML = '';
  899. document.documentElement.removeChild(tip);
  900. }
  901. hasCanvas = false;
  902. }
  903. //show Tips
  904. function updateHint(gesture,fnName){
  905. tip.innerHTML = gesture.join("") + '<br/>' + (fnName ? fnName : funNotDefine);
  906. }
  907. function updateTrack(x,y){
  908. if (hasCanvas) {
  909. ctx.lineWidth = Math.min(maxLineWidth, ctx.lineWidth += lineGrowth);
  910. ctx.lineTo(x, y);
  911. ctx.stroke();
  912. ctx.closePath();
  913. ctx.beginPath();
  914. ctx.moveTo(x, y);
  915. }
  916. }
  917. // due to modul pattern: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html
  918. return modul;
  919. })();
  920.  
  921. //========④GesturedHadler============
  922. //--> GestureHandler "singleton" class using the modul pattern
  923. //--> the handler behaves different depending on whether it's injected in a frame or not
  924. //--> frame: detects gesture start, move, end and sends an indication message
  925. //--> main page: detects whole gesture including frame indication messages and reports it to the background script
  926. //--> provides 4 events: on start, update, change and end
  927. //--> on default the handler is disabled and must be enabled via enable()
  928. //--> REQUIRES: contentCommons.js
  929. const GestureHandler = (function() {
  930. // public variables and methods
  931. let modul = {};
  932.  
  933. //-->Add callbacks to the given events
  934. modul.on = function on(event, callback) {
  935. // if event does not exist or function already applied skip it
  936. if (event in events && !events[event].includes(callback))
  937. events[event].push(callback);
  938. return this;
  939. };
  940.  
  941. //-->applies necessary settings
  942. modul.applySettings = function applySettings(Settings) {
  943. mouseButton = Number(Settings.Gesture.mouseButton);
  944. suppressionKey = Settings.Gesture.suppressionKey;
  945. distanceSensitivity = Settings.Gesture.distanceSensitivity;
  946. distanceThreshold = Settings.Gesture.distanceThreshold;
  947. timeoutActive = Settings.Gesture.Timeout.active;
  948. timeoutDuration = Settings.Gesture.Timeout.duration;
  949. };
  950.  
  951. //-->Add the event listeners
  952. modul.enable = function enable() {
  953. if (inIframe()) {
  954. //window.addEventListener('mousedown', handleFrameMousedown, true);//去掉鼠标手势动作
  955. //window.addEventListener('mousemove', handleFrameMousemove, true);
  956. //window.addEventListener('mouseup', handleFrameMouseup, true);
  957. window.addEventListener('dragstart', handleDragstart, true);
  958. } else {
  959. // chrome.runtime.onMessage.addListener(handleMessage);
  960. window.addEventListener('mousedown', handleMousedown, true);
  961. }
  962. };
  963.  
  964. //-->Remove the event listeners and resets the handler
  965. modul.disable = function disable() {
  966. if (inIframe()) {
  967. //window.removeEventListener('mousedown', handleFrameMousedown, true);
  968. //window.removeEventListener('mousemove', handleFrameMousemove, true);
  969. //window.removeEventListener('mouseup', handleFrameMouseup, true);
  970. window.removeEventListener('dragstart', handleDragstart, true);
  971. } else {
  972. // chrome.runtime.onMessage.removeListener(handleMessage);
  973. //window.removeEventListener('mousedown', handleMousedown, true);
  974. //window.removeEventListener('mousemove', handleMousemove, true);
  975. //window.removeEventListener('mouseup', handleMouseup, true);
  976. //window.removeEventListener('contextmenu', handleContextmenu, true);
  977. //window.removeEventListener('mouseout', handleMouseout, true);
  978. window.removeEventListener('dragstart', handleDragstart, true);
  979. // reset gesture array, internal state and target data
  980. directions = [];
  981. state = "passive";
  982. targetData = {};
  983. }
  984. };
  985.  
  986. // private variables and methods
  987.  
  988. // setting properties
  989. let mouseButton = 2,
  990. dragButton = 1,//MP
  991. suppressionKey = "",
  992. distanceThreshold = 2,
  993. distanceSensitivity = 10,
  994. timeoutActive = true, //超时取消动作 没取消轨迹
  995. timeoutDuration = 1;
  996.  
  997. // contains all gesture direction letters
  998. let directions = [];
  999.  
  1000. // internal state: passive, pending, active
  1001. let state = "passive";
  1002.  
  1003. // holds reference point to current point
  1004. let referencePoint = {
  1005. x: 0,
  1006. y: 0
  1007. };
  1008.  
  1009. // contains the timeout identifier
  1010. let timeout = null;
  1011.  
  1012. // contains relevant data of the target element
  1013. let targetData = {};
  1014.  
  1015. // holds all event callbacks added by on()
  1016. let events = {
  1017. 'start': [],
  1018. 'update': [],
  1019. 'change': [],
  1020. 'abort': [],
  1021. 'end': []
  1022. };
  1023.  
  1024. //-->initializes the gesture to the "pending" state, where it's unclear if the user is starting a gesture or not
  1025. //-->requires the current x and y coordinates
  1026. function init(x, y) {
  1027. // set the initial point
  1028. referencePoint.x = x;
  1029. referencePoint.y = y;
  1030.  
  1031. // change internal state
  1032. state = "pending";
  1033.  
  1034. // add gesture detection listeners
  1035. //window.addEventListener('mousemove', handleMousemove, true);
  1036. window.addEventListener('dragstart', handleDragstart, true);
  1037. window.addEventListener('drag', handleDrag, true);//MP
  1038. window.addEventListener('dragend', handleDragend, true);//MP
  1039. //window.addEventListener('contextmenu', handleContextmenu, true);
  1040. //window.addEventListener('mouseup', handleMouseup, true);
  1041. //window.addEventListener('mouseout', handleMouseout, true);
  1042. }
  1043.  
  1044. //-->Indicates the gesture start and should only be called once untill gesture end
  1045. function start() {
  1046. // dispatch all binded functions with the current x and y coordinates as parameter on start
  1047. events['start'].forEach((callback) => callback(referencePoint.x, referencePoint.y));
  1048.  
  1049. // change internal state
  1050. state = "active";
  1051. }
  1052.  
  1053. //-->Indicates the gesture change and should be called every time the cursor position changes
  1054. //-->requires the current x and y coordinates
  1055. function update(x, y, dragMark) {
  1056. // dispatch all binded functions with the current x and y coordinates as parameter on update
  1057. events['update'].forEach((callback) => callback(x, y));
  1058.  
  1059. // handle timeout
  1060. if (timeoutActive) {
  1061. // clear previous timeout if existing
  1062. if (timeout) window.clearTimeout(timeout);
  1063. timeout = window.setTimeout(() => {
  1064. // dispatch all binded functions on abort
  1065. events['abort'].forEach((callback) => callback());
  1066. state = "expired";
  1067. // clear directions
  1068. directions = [];
  1069. console.log("OK")
  1070. }, timeoutDuration * 1000);
  1071. }
  1072.  
  1073. let direction = getDirection(referencePoint.x, referencePoint.y, x, y);
  1074.  
  1075. if (directions[directions.length - 1] !== direction) {
  1076. // add new direction to gesture list
  1077. directions.push(direction);
  1078.  
  1079. // send message to background on gesture change
  1080. let message = runtime.sendMessage({
  1081. // subject: "gestureChange",
  1082. subject: dragMark ? "dragChange" : "gestureChange",//MP
  1083. data: Object.assign(//MP
  1084. targetData, {
  1085. gesture: directions.join("")
  1086. })
  1087. });
  1088. // on response (also fires on no response) dispatch all binded functions with the directions array and the action as parameter
  1089. message.then((response) => {
  1090. let action = response ? response.action : null;
  1091. events['change'].forEach((callback) => callback(directions, action));
  1092. });
  1093. }
  1094.  
  1095. // set new reference point
  1096. referencePoint.x = x;
  1097. referencePoint.y = y;
  1098. }
  1099.  
  1100. //-->Indicates the gesture end and should be called to terminate the gesture
  1101. function end(dragMark) {
  1102. // dispatch all binded functions on end
  1103. events['end'].forEach((callback) => callback(directions));
  1104.  
  1105. // send directions and target data to background if directions is not empty
  1106. if (directions.length) runtime.sendMessage({
  1107. // subject: "gestureEnd",
  1108. subject: dragMark ? "dragEnd" : "gestureEnd",
  1109. data: Object.assign(
  1110. targetData, {
  1111. gesture: directions.join("")
  1112. }
  1113. )
  1114. });
  1115.  
  1116. // reset gesture handler
  1117. reset();
  1118. }
  1119.  
  1120. //-->Resets the handler to its initial state
  1121. function reset() {
  1122. // remove gesture detection listeners
  1123. //window.removeEventListener('mousemove', handleMousemove, true);
  1124. //window.removeEventListener('mouseup', handleMouseup, true);
  1125. //window.removeEventListener('contextmenu', handleContextmenu, true);
  1126. //window.removeEventListener('mouseout', handleMouseout, true);
  1127. window.removeEventListener('dragstart', handleDragstart, true);
  1128. window.removeEventListener('drag', handleDrag, true);//MP
  1129. window.removeEventListener('dragend', handleDragend, true);//MP
  1130.  
  1131. // reset gesture array, internal state and target data
  1132. directions = [];
  1133. state = "passive";
  1134. targetData = {};
  1135.  
  1136. if (timeout) {
  1137. window.clearTimeout(timeout);
  1138. timeout = null;
  1139. }
  1140. }
  1141.  
  1142. //-->Handles iframe/background messages which will update the gesture
  1143. function handleMessage(message, sender, sendResponse) {
  1144.  
  1145. switch (message.subject) {
  1146. case "gestureFrameMousedown":
  1147. // init gesture
  1148. init(
  1149. Math.round(message.data.screenX / window.devicePixelRatio - window.mozInnerScreenX),
  1150. Math.round(message.data.screenY / window.devicePixelRatio - window.mozInnerScreenY)
  1151. );
  1152. // save target data
  1153. targetData = message.data;
  1154. break;
  1155.  
  1156. case "gestureFrameMousemove":
  1157. // calculate distance between the current point and the reference point
  1158. let distance = getDistance(referencePoint.x, referencePoint.y,
  1159. Math.round(message.data.screenX / window.devicePixelRatio - window.mozInnerScreenX),
  1160. Math.round(message.data.screenY / window.devicePixelRatio - window.mozInnerScreenY)
  1161. );
  1162. // induce gesture
  1163. if (state === "pending" && distance > distanceThreshold)
  1164. start();
  1165. // update gesture && mousebutton fix: right click on frames is sometimes captured by both event listeners which leads to problems
  1166. else if (state === "active" && distance > distanceSensitivity && mouseButton !== 2) update(
  1167. Math.round(message.data.screenX / window.devicePixelRatio - window.mozInnerScreenX),
  1168. Math.round(message.data.screenY / window.devicePixelRatio - window.mozInnerScreenY)
  1169. );
  1170. break;
  1171.  
  1172. case "gestureFrameMouseup":
  1173. if (state === "active" || state === "expired") end();
  1174. else if (state === "pending") reset();
  1175. break;
  1176. }
  1177. }
  1178.  
  1179. //-->Handles mousedown which will add the mousemove listener
  1180. function handleMousedown(event) {
  1181. // on mouse button and no supression key
  1182. if (event.isTrusted && (event.buttons === mouseButton || event.buttons === dragButton) && (!suppressionKey || (suppressionKey in event && !event[suppressionKey]))) {//MP
  1183. // init gesture
  1184. init(event.clientX, event.clientY);
  1185.  
  1186. // save target to global variable if exisiting
  1187. if (typeof TARGET !== 'undefined') TARGET = event.target;
  1188.  
  1189. // get and save target data
  1190. targetData = getTargetData(event.target);
  1191.  
  1192. // prevent and middle click scroll
  1193. if (mouseButton === 4) event.preventDefault();
  1194. }
  1195. }
  1196.  
  1197. //-->Handles mousemove which will either start the gesture or update it
  1198. function handleMousemove(event) {
  1199. if (event.isTrusted && event.buttons === mouseButton) {
  1200. // calculate distance between the current point and the reference point
  1201. let distance = getDistance(referencePoint.x, referencePoint.y, event.clientX, event.clientY);
  1202.  
  1203. // induce gesture
  1204. if (state === "pending" && distance > distanceThreshold)
  1205. start();
  1206.  
  1207. // update gesture
  1208. else if (state === "active" && distance > distanceSensitivity)
  1209. update(event.clientX, event.clientY);
  1210.  
  1211. // prevent text selection
  1212. if (mouseButton === 1) window.getSelection().removeAllRanges();
  1213. }
  1214. }
  1215.  
  1216. //-->Handles context menu popup and removes all added listeners
  1217. function handleContextmenu(event) {
  1218. if (event.isTrusted && mouseButton === 2) {
  1219. if (state === "active" || state === "expired") {
  1220. // prevent context menu
  1221. event.preventDefault();
  1222. end();
  1223. }
  1224. // reset if state is pending
  1225. else if (state === "pending")
  1226. reset();
  1227. }
  1228. }
  1229.  
  1230. //-->Handles mouseup and removes all added listeners
  1231. function handleMouseup(event) {
  1232. // only call on left and middle mouse click to terminate gesture
  1233. if (event.isTrusted && ((event.button === 0 && mouseButton === 1) || (event.button === 1 && mouseButton === 4))) {
  1234. if (state === "active" || state === "expired")
  1235. end();
  1236. // reset if state is pending
  1237. else if (state === "pending")
  1238. reset();
  1239. }
  1240. }
  1241.  
  1242. //-->Handles mouse out and removes all added listeners
  1243. function handleMouseout(event) {
  1244. // only call if cursor left the browser window
  1245. if (event.isTrusted && event.relatedTarget === null) {
  1246. if (state === "active" || state === "expired")
  1247. end();
  1248. // reset if state is pending
  1249. else if (state === "pending")
  1250. reset();
  1251. }
  1252. }
  1253.  
  1254. //-->Handles dragstart and prevents it if needed
  1255. function handleDragstart(event) {
  1256. // prevent drag if mouse button and no supression key is pressed
  1257. if (event.isTrusted && event.buttons === mouseButton && (!suppressionKey || (suppressionKey in event && !event[suppressionKey])))
  1258. event.preventDefault();
  1259. }
  1260.  
  1261. //-->Handles drag MP
  1262. function handleDrag(event) {
  1263. // prevent drag if mouse button and no supression key is pressed
  1264. if (event.isTrusted && event.buttons === dragButton && (!suppressionKey || (suppressionKey in event && !event[suppressionKey]))){
  1265. let distance = getDistance(referencePoint.x, referencePoint.y, event.clientX, event.clientY);
  1266.  
  1267. // induce gesture
  1268. if (state === "pending" && distance > distanceThreshold)
  1269. start();
  1270.  
  1271. // update gesture
  1272. else if (state === "active" && distance > distanceSensitivity)
  1273. update(event.clientX, event.clientY, 'dragMark');
  1274. }
  1275. }
  1276.  
  1277. //-->Handles dragsend MP
  1278. function handleDragend(event) {
  1279. if (event.isTrusted && ((event.button === 0 && mouseButton === 1) || (event.button === 1 && mouseButton === 4) || event.button === 0 && dragButton === 1)) {//MP
  1280. // if (event.isTrusted && ((event.button === 0 && gestureHandler.mouseButton === 1) || (event.button === 1 && gestureHandler.mouseButton === 4))) {
  1281. if (state === "active" || state === "expired")
  1282. end("dragMark");
  1283. // reset if state is pending
  1284. else if (state === "pending")
  1285. reset();
  1286. }
  1287. }
  1288.  
  1289. //-->Handles mousedown for frames; send message with target data and position
  1290. function handleFrameMousedown(event) {
  1291. // on mouse button and no supression key
  1292. if (event.isTrusted && event.buttons === mouseButton && (!suppressionKey || (suppressionKey in event && !event[suppressionKey]))) {
  1293. runtime.sendMessage({
  1294. subject: "gestureFrameMousedown",
  1295. data: Object.assign(
  1296. getTargetData(event.target), {
  1297. screenX: event.screenX,
  1298. screenY: event.screenY,
  1299. }
  1300. )
  1301. });
  1302. // save target to global variable if exisiting
  1303. if (typeof TARGET !== 'undefined') TARGET = event.target;
  1304. // prevent middle click scroll
  1305. if (mouseButton === 4) event.preventDefault();
  1306. }
  1307. }
  1308.  
  1309. //-->Handles mousemove for frames; send message with position
  1310. function handleFrameMousemove(event) {
  1311. // on mouse button and no supression key
  1312. if (event.isTrusted && event.buttons === mouseButton && (!suppressionKey || (suppressionKey in event && !event[suppressionKey]))) {
  1313. runtime.sendMessage({
  1314. subject: "gestureFrameMousemove",
  1315. data: {
  1316. screenX: event.screenX,
  1317. screenY: event.screenY
  1318. }
  1319. });
  1320. // prevent text selection
  1321. if (mouseButton === 1) window.getSelection().removeAllRanges();
  1322. }
  1323. }
  1324.  
  1325. //--> Handles mouseup for frames
  1326. function handleFrameMouseup(event) {
  1327. // only call on left, right and middle mouse click to terminate or reset gesture
  1328. if (event.isTrusted && ((event.button === 0 && mouseButton === 1) || (event.button === 1 && mouseButton === 4) || (event.button === 2 && mouseButton === 2)))
  1329. runtime.sendMessage({
  1330. subject: "gestureFrameMouseup",
  1331. data: {}
  1332. });
  1333. }
  1334.  
  1335. // due to modul pattern: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html
  1336. return modul;
  1337. })();
  1338.  
  1339. //========⑤Setting===================
  1340. const Ui = (function(){
  1341. let modul = {};
  1342. modul.init = function (){
  1343. addStyle(CSS, 'MPmanageStyle');
  1344.  
  1345. let node = document.createElement('div');
  1346. node.id = 'MPsetting';
  1347. node.innerHTML = menuHTML;
  1348. document.body.appendChild(node);
  1349.  
  1350. //#mg1
  1351. q('#mg1')[0].innerHTML = gestureAndDragHTML;
  1352. //#mg2
  1353. q('#mg2')[0].innerHTML = makeFunsList();
  1354. each(['gesture', 'text', 'link', 'image'],(item)=>{
  1355. q('#mg2')[0].innerHTML += makeDefinedFunsList(item);
  1356. });
  1357. //#mg3
  1358. q('#mg3')[0].innerHTML = aboutHTML;
  1359.  
  1360. //addEventListener
  1361. listen(q('#MPsetting')[0], 'click', click);
  1362. each(q('#mg1 input[type=text], #mg2 span[name="alias"]'),item=>{
  1363. listen(item, 'blur', updateConfigUi);
  1364. });
  1365. each(q('#MPsetting select, #MPsetting input[type=checkbox]'),item=>{
  1366. listen(item, 'change', updateConfigUi);
  1367. });
  1368. //show functions,hide others
  1369. q('li[name=mg2]')[0].click();
  1370. };
  1371. modul.closesetting = function (){
  1372. q('body')[0].removeChild(q('#MPsetting')[0]);
  1373. };
  1374. modul.captureGesture = function(gestureStr, operation){
  1375. try {
  1376. if(operation === "recorddingGesture"){
  1377. q('#recorddingGesture')[0].textContent = gestureStr;
  1378. return;
  1379. }
  1380. if(operation !== "cancelGesture") q('[data-flag=captureGesture]')[0].value = gestureStr;
  1381. document.body.removeChild(q('#MPMask')[0]);
  1382. runtime.captureGesture = false;
  1383. attr(q('#MPsetting')[0], "style", " ");
  1384. let tmp = q('[data-flag=captureGesture]')[0];
  1385. attr(tmp, "data-flag", " ");
  1386. updateFns(tmp.parentElement);
  1387. } catch(e) {
  1388. // console.log(e);
  1389. }
  1390. };
  1391.  
  1392. let
  1393. fnLocal = {
  1394. arg: {
  1395. userDefine:{
  1396. description:{zh:['自定义功能代码'], en:['User Define Function Code']},
  1397. arg:['textarea']
  1398. },
  1399. searchText:{
  1400. description:{zh:['搜索引擎', '后台打开', '右边插入'], en:['SearchingEnging', 'Load In Background', 'Insert After Current Tab']},
  1401. arg:['select:searchEnging', 'checkbox', 'checkbox']
  1402. },
  1403. searchImg:{
  1404. description:{zh:['图片搜索引擎', '后台打开', '右边插入'], en:['Image SearchingEnging', 'Load In Background', 'Insert After Current Tab']},
  1405. arg:['select:imgSearchEnging', 'checkbox', 'checkbox']
  1406. },
  1407. fkVip:{
  1408. description:{zh:['视频解析接口'], en:['Videos Parser API']},
  1409. arg:['select:vipAPI']
  1410. }
  1411. },
  1412. FunsListTitle: {
  1413. gesture: {zh:'手势', en:'Gesture'},
  1414. text: {zh:'拖拽文本', en:'Drag Text'},
  1415. link: {zh:'拖拽链接', en:'Drag Link'},
  1416. image: {zh:'拖拽图片', en:'Drag Image'}
  1417. },
  1418. addFunction: {zh:'增加一个功能', en:'Add Function'}
  1419. },
  1420. CSS = `
  1421. #MPsetting{z-index:999997!important;background:white!important;width:100%!important;height:100%!important;color:#032E58!important;font-family:"微软雅黑"!important;position:fixed!important;top:0!important;left:0!important;}
  1422. #MPmenu *,
  1423. .MPcontent *{border-radius:3px!important;font-size:16px!important;}
  1424. #MPlogo svg{background:white!important;box-shadow:inset 0 0 25px 15px #A2B7D2!important;width:80px!important;height:100px!important;margin:0!important;padding:0!important;}
  1425. #MPmenu{z-index:999999!important;height:100%!important;width:100px!important;background:#A2B7D2!important;color:white!important;text-align:center!important;}
  1426. #MPmenu li{list-style-type:none!important;border-top:1px dashed white!important;margin:10px 15px!important;cursor:pointer;}
  1427. .MPselected,#MPmenu li:hover{background:white!important;color:#A2B7D2!important;}
  1428. #MPmenu li span{display:block!important;width:40px!important;height:40px!important;font-size:35px!important;font-weight:bold!important;padding:0 15px!important;}
  1429. #MPmenu b{display:block!important;width:70px!important;text-align:center!important;margin-top:10px!important;}
  1430. .MPcontent{height:94%!important;width:100%!important;overflow-y:scroll!important;position:absolute!important;left:100px!important;top:0!important;z-index:999998!important;padding:20px!important;}
  1431. .MPcontent h1{display:block!important;width:800px!important;font-size:20px!important;float:left!important;top:0!important;left:90px!important;padding:3px 10px!important;margin:0 5px!important;border-left:5px solid #A2B7D2!important;background:#A2B7D259!important;}
  1432. .MPcontent > li{list-style-type:none!important;width:800px!important;height:auto!important;padding:10px 5px 0px 5px!important;margin:5px 20px!important;float:left!important;border-bottom:1px dashed #00000020!important;}
  1433. .MPcontent > li:hover{box-shadow:inset 1px 1px 1px 3px #A2B7D240!important;}
  1434. #mg1 >li span:nth-child(2),#mg2>li>input{max-height:28px!important;float:right!important;}
  1435. #mg1 input[type="text"],#mg1 select,#mg2 input[readonly="readonly"]{width:250px!important;height:26px!important;margin:0 10px!important;text-align:center!important;border:0!important;background:#0000000C!important;font-size:20px!important;}
  1436. .MPcontent input[type="checkbox"]{width:0!important;}
  1437. #FunsList{width:800px!important;border:0!important;overflow:hidden!important;}
  1438. .FunsListHide{height: 34px!important;border: 0!important;margin: 0!important;padding: 0!important;}
  1439. .FunsListShow{height:auto!important;}
  1440. #FunsList>li{display:inline-block!important;width:300px!important;height:30px!important;margin:5px!important;text-align:left!important;}
  1441. span.tag:before{color:white!important;background:#555555!important;margin:0!important;border:0!important;padding:3px!important;border-radius:4px 0 0 4px!important;font-size:14px!important;white-space:nowrap!important;font-weight:bold!important;}
  1442. span.tag{color:white!important;margin:0!important;border:0!important;padding:1px 7px 3px 0!important;border-radius:4px!important;}
  1443.  
  1444. #mg2 b{margin-left:30px;padding:0 20px;background:#00000000!important;}
  1445. #mg2 div.fnArgument{<!--display:none;-->margin-left:0;margin-right:10px;padding-top:20px!important;height:auto;}<!--显示搜索引擎 去除空白-->
  1446. #mg2 div.fnArgument textarea{width:100%;height:200px;}
  1447. #mg2 div.fnArgument span{width:auto;height:auto;}
  1448. #mg2 .yellow{background:#FFB400!important;}
  1449. #mg2 .yellow:before{content:"${fnLocal.FunsListTitle.gesture[cfg.language]}";}
  1450. #mg2 .blue:before{content:"${fnLocal.FunsListTitle.link[cfg.language]}";}
  1451. #mg2 .blue{background:#1182C2!important;}
  1452. #mg2 .green:before{content:"${fnLocal.FunsListTitle.text[cfg.language]}";}
  1453. #mg2 .green{background:#4DC71F!important;}
  1454. #mg2 .darkcyan:before{content:"${fnLocal.FunsListTitle.image[cfg.language]}";}
  1455. #mg2 .darkcyan{background:#B10DC9!important;}
  1456. #mg2 > li[data-type=gesture]>span:first-child{background:#FFB40030!important;color:#FFB400!important;}
  1457. #mg2 > li[data-type=text]>span:first-child{background:#4DC71F30!important;color:#4DC71F!important;}
  1458. #mg2 > li[data-type=link]>span:first-child{background:#1182C230!important;color:#1182C2!important;}
  1459. #mg2 > li[data-type=image]>span:first-child{background:#B10DC930!important;color:#B10DC9!important;}
  1460. #mg1 > li span:first-child,#mg2>li>span:first-child{text-align:left!important;font-size:16px!important;font-weight:bold!important;padding:2px 6px!important;width:auto!important;height:24px!important;float:left!important;border-left:5px solid!important;margin-right:20px!important;}
  1461. #mg2>li>span{margin-bottom:10px!important;}
  1462. #mg2>li>input {font-family: MParrow;}
  1463.  
  1464. #mg2 div input[type=text],#mg2 div select{background:#0000000c;padding:5px;margin:10px 5px;border: 0;}
  1465. #mg2 div input{width:80%;}
  1466. #mg2 div select{width:15%;}
  1467. #mg2 div label{margin-left:15px;margin-right:15px;}<!--margin:3px 0;-->
  1468.  
  1469. #mg3 *{height: auto;font-size: 30px!important;text-decoration: none;font-weight: bolder;padding: 20px; color:#3A3B74!important}
  1470.  
  1471. /*label 作为开关*/
  1472. label.switchOn{background:#3A3B7420!important;display:inline-block!important;color:#3A3B74!important;font-weight:bolder!important;min-width:40px!important;height:24px!important;padding:2px 5px!important;border-left:15px solid #3A3B74!important;border-radius:5px!important;}
  1473. label.switchOff{background:#33333370!important;display:inline-block!important;color:#333333a0!important;text-decoration:line-through!important;min-width:40px!important;height:24px!important;padding:2px 5px!important;border-right:15px solid #333333!important;border-radius:5px!important;}
  1474. input[type=checkbox].switch{width:0px!important;}
  1475.  
  1476. #MPMask{z-index:9999999;position:fixed;top:0;left:0;}
  1477. #recorddingGesture{position: fixed;width: 100%;top: 100%;margin-top: -50%;text-align: center;color: white;font-size: 40px;font-family: MParrow;word-wrap:break-word;}
  1478. `,
  1479. uiLocal = {
  1480. //gesture
  1481. gestureUi: {zh:'手势配置', en:'Gesture Config'},
  1482. mouseButton: {zh:'手势按键', en:'Gesture mouse button'},
  1483. leftButton: {zh:'左键', en:'Left Key'},
  1484. middleButton: {zh:'中键', en:'MIddle Key'},
  1485. rightButton: {zh:'右键', en:'Right Key'},
  1486. mouseButtonTitle: {zh:'触发鼠标手势的按键', en:'The mouse button which will trigger the gesture.'},
  1487.  
  1488. suppressionKey: {zh:'手势禁用键', en:'Gesture suppression key'},
  1489. suppressionKeyTitle: {zh:'按下禁用键,暂时禁用手势', en:'Disables the mouse gesture if the key is pressed.'},
  1490. distanceThreshold: {zh:'手势距离阈值', en:'Gesture distance threshold'},
  1491. distanceThresholdTitle: {zh:'激活鼠标手势的最短距离', en:'The minimum mouse distance until the Gesture gets activated.'},
  1492. distanceSensitivity: {zh:'手势灵敏度', en:'Gesture sensitivity'},
  1493. distanceSensitivityTitle: {zh:'认定为新方向的最短距离。这也影响轨迹平滑度', en:'The minimum mouse distance until a new direction gets recognized. This will also impact the trace smoothness.'},
  1494. timeout: {zh:'手势超时', en:'Gesture timeout'},
  1495. timeoutTitle: {zh:'鼠标不动指定时间后,取消手势', en:'Cancels the gesture after the mouse has not been moved for the specified time.'},
  1496. directions: {zh:'手势方向数', en:'Gesture directions'},
  1497. directionsTitle: {zh:'手势识别的方向个数', en:'Gesture diffrent directions.'},
  1498. language: {zh:'语言', en:'Language'},
  1499. languageTitle: {zh:'设定使用语言', en:'Set the language for using.'},
  1500. //hint
  1501. hintUi: {zh:'提示配置', en:'Hint Config'},
  1502. background: {zh:'提示背景颜色', en:'Hint background'},
  1503. backgroundTitle: {zh:'提示的文字的背景颜色', en:'Hint text background color'},
  1504. fontSize: {zh:'提示字体', en:'Hint font size'},
  1505. fontSizeTitle: {zh:'提示文字的字体大小,单位:"&quot;px"&quot;', en:'Hint text font size,unit:"&quot;px"&quot;'},
  1506. lineColor: {zh:'轨迹颜色', en:'Track line color'},
  1507. lineColorTitle: {zh:'显示轨迹的颜色,十六进制,可以使3/6/8位', en:'track line color, hex, 3/6/8 bit'},
  1508. minLineWidth: {zh:'最小宽度', en:'Track minimum width'},
  1509. minLineWidthTitle: {zh:'轨迹的最小宽度,单位:&quot;px"&quot;', en:'Track minimum width,unit:&quot;px"&quot;'},
  1510. maxLineWidth: {zh:'最大宽度', en:'Track maximum width'},
  1511. maxLineWidthTitle: {zh:'轨迹的最大宽度,单位:&quot;px"&quot;', en:'Track maximum width,unit:&quot;px&quot;'},
  1512. lineGrowth: {zh:'增长速度', en:'Track growth speed'},
  1513. lineGrowthTitle: {zh:'轨迹的增长速度,单位:&quot;px&quot;', en:'Track growth speed,unit:&quot;px&quot;'},
  1514. funNotDefine: {zh:'未定义提示', en:'Gesture not found hint'},
  1515. funNotDefineTitle: {zh:'手势或者功能未定义时的提示信息', en:'If gesture not found, hint this'},
  1516. //drag
  1517. dragSetting: {zh:'拖拽配置', en:'Drag Config'},
  1518. linktextAslink: {zh:'链接优先', en:'Link priority'},
  1519. linktextAslinkTitle: {zh:'链接文字识别为链接', en:'Text link drag as link'},
  1520. dragInTextarea: {zh:'文本框拖拽', en:'Enable drag in textarea'},
  1521. dragInTextareaTitle: {zh:'文本框中选中文字并且拖拽时候,使用拖拽的功能', en:'Enable drag in textarea or input'}
  1522. },
  1523.  
  1524. menuHTML = `
  1525. <div id="MPmenu">
  1526. <span id="MPlogo">
  1527. <svg width="80px" height="100px" viewbox="0 0 200 200">
  1528. <path d="M135 13 l13 13h-7v20h20v-7l13 13l-13 13v-7h-20v20h7l-13 13 l-13 -13h7v-20h-20v7l-13-13l13-13v7h20v-20h-7z" style="fill:#0074d9;stroke:none;"></path>
  1529. <path d="M0 190L20 10c3,-8 8,-4 10,0L100 130L160 80c8,-8 17,-8 20,0L200 180c-2 20 -24 20 -30 0L160 120L110 163c-6 6 -19 10 -25 0L30 40L10 195c-3 5 -8 5 -10 0z" style="stroke:none;fill:#0074d9;"></path>
  1530. </svg>
  1531. </span>
  1532. <li name="mg1"> <span>◧</span> <b>Config</b> </li>
  1533. <li name="mg2"> <span>↯</span> <b>Gesture</b> </li>
  1534. <li name="mg3"> <span>❓</span> <b>About</b> </li>
  1535. <li name="close"> <span>?</span> <b>Close</b> </li>
  1536. </div>
  1537. <div id="mg1" class="MPcontent">mg1</div>
  1538. <div id="mg2" class="MPcontent">mg2</div>
  1539. <div id="mg3" class="MPcontent">mg3</div>
  1540. `,
  1541. gestureAndDragHTML =
  1542. //======gestureAndDragHTML======
  1543. `
  1544. <h1>${uiLocal.gestureUi[cfg.language]}</h1>
  1545. <!-- 因为启用了左键作为拖拽,所以按钮选项要禁用
  1546. <li>
  1547. <span title="${uiLocal.mouseButtonTitle[cfg.language]}">${uiLocal.mouseButton[cfg.language]}</span>
  1548. <span>
  1549. <select name="mouseButton">
  1550. <option value="0" ${sel(cfg.Gesture.mouseButton, 0)}>${uiLocal.leftButton[cfg.language]}</option>
  1551. <option value="1" ${sel(cfg.Gesture.mouseButton, 1)}>${uiLocal.middleButton[cfg.language]}</option>
  1552. <option value="2" ${sel(cfg.Gesture.mouseButton, 2)}>${uiLocal.rightButton[cfg.language]}</option>
  1553. </select>
  1554. </span>
  1555. </li>
  1556. -->
  1557. <li>
  1558. <span title="${uiLocal.suppressionKeyTitle[cfg.language]}">${uiLocal.suppressionKey[cfg.language]}</span>
  1559. <span>
  1560. <select name="suppressionKey">
  1561. <option value="" ${sel(cfg.Gesture.suppressionKey, '')}>&nbsp;</option>
  1562. <option value="altKey" ${sel(cfg.Gesture.suppressionKey, 'altKey')}>Alt</option>
  1563. <option value="ctrlKey" ${sel(cfg.Gesture.suppressionKey, 'ctrlKey')}>Ctrl</option>
  1564. <option value="shiftKey" ${sel(cfg.Gesture.suppressionKey, 'shiftKey')}>Shift</option>
  1565. </select>
  1566. </span>
  1567. </li>
  1568. <li>
  1569. <span title="${uiLocal.distanceThresholdTitle[cfg.language]}">${uiLocal.distanceThreshold[cfg.language]}</span>
  1570. <span>
  1571. <input type="text" name="distanceThreshold" value="${cfg.Gesture.distanceThreshold}" data-mark="number">
  1572. </span>
  1573. </li>
  1574. <li>
  1575. <span title="${uiLocal.distanceSensitivityTitle[cfg.language]}">${uiLocal.distanceSensitivity[cfg.language]}</span>
  1576. <span>
  1577. <input type="text" name="distanceSensitivity" value="${cfg.Gesture.distanceSensitivity}" data-mark="number">
  1578. </span>
  1579. </li>
  1580. <li>
  1581. <span title="${uiLocal.timeoutTitle[cfg.language]}">${uiLocal.timeout[cfg.language]}</span>
  1582. <span>
  1583. <input type="text" name="timeout" value="${cfg.Gesture.Timeout.duration}" data-mark="number">
  1584. </span>
  1585. </li>
  1586. <li>
  1587. <span title="${uiLocal.directionsTitle[cfg.language]}">${uiLocal.directions[cfg.language]}</span>
  1588. <span>
  1589. <select name="directions">
  1590. <option value="4" ${sel(cfg.directions, 4)}> 4 </option>
  1591. <option value="8" ${sel(cfg.directions, 8)}> 8 </option>
  1592. </select>
  1593. </span>
  1594. </li>
  1595. <li>
  1596. <span title="${uiLocal.languageTitle[cfg.language]}">${uiLocal.language[cfg.language]}</span>
  1597. <span>
  1598. <select name="language">
  1599. <option value="zh" ${sel(cfg.language, 'zh')}>中文</option>
  1600. <option value="en" ${sel(cfg.language, 'en')}>English</option>
  1601. </select>
  1602. </span>
  1603. </li>
  1604. <h1>${uiLocal.hintUi[cfg.language]}</h1>
  1605. <li>
  1606. <span title="${uiLocal.backgroundTitle[cfg.language]}">${uiLocal.background[cfg.language]}</span>
  1607. <span>
  1608. <input type="text" name="background" value="${cfg.Hinter.background}" style="background:#${cfg.Hinter.background} !important;">
  1609. </span>
  1610. </li>
  1611. <li>
  1612. <span title="${uiLocal.fontSizeTitle[cfg.language]}">${uiLocal.fontSize[cfg.language]}</span>
  1613. <span>
  1614. <input type="text" name="fontSize" value="${cfg.Hinter.fontSize}" data-mark="number">
  1615. </span>
  1616. </li>
  1617. <li>
  1618. <span title="${uiLocal.lineColorTitle[cfg.language]}">${uiLocal.lineColor[cfg.language]}</span>
  1619. <span>
  1620. <input type="text" name="lineColor" value="${cfg.Hinter.lineColor}" style="background:#${cfg.Hinter.lineColor} !important;">
  1621. </span>
  1622. </li>
  1623. <li>
  1624. <span title="${uiLocal.minLineWidthTitle[cfg.language]}">${uiLocal.minLineWidth[cfg.language]}</span>
  1625. <span>
  1626. <input type="text" name="minLineWidth" value="${cfg.Hinter.minLineWidth}">
  1627. </span>
  1628. </li>
  1629. <li>
  1630. <span title="${uiLocal.maxLineWidthTitle[cfg.language]}">${uiLocal.maxLineWidth[cfg.language]}</span>
  1631. <span>
  1632. <input type="text" name="maxLineWidth" value="${cfg.Hinter.maxLineWidth}">
  1633. </span>
  1634. </li>
  1635. <li>
  1636. <span title="${uiLocal.lineGrowthTitle[cfg.language]}">${uiLocal.lineGrowth[cfg.language]}</span>
  1637. <span>
  1638. <input type="text" name="lineGrowth" value="${cfg.Hinter.lineGrowth}">
  1639. </span>
  1640. </li>
  1641. <li>
  1642. <span title="${uiLocal.funNotDefineTitle[cfg.language]}">${uiLocal.funNotDefine[cfg.language]}</span>
  1643. <span>
  1644. <input type="text" name="funNotDefine" value="${cfg.Hinter.funNotDefine}">
  1645. </span>
  1646. </li>
  1647.  
  1648. <h1>${uiLocal.dragSetting[cfg.language]}</h1>
  1649. <li>
  1650. <span title="${uiLocal.linktextAslinkTitle[cfg.language]}">${uiLocal.linktextAslink[cfg.language]}</span>
  1651. <span>
  1652. <input type="checkbox" id="linktextAslink" name="linktextAslink" checked="" class="switch">
  1653. <label for="linktextAslink" class="switchOn"></label>
  1654. </span>
  1655. </li>
  1656. <!-- 使用抑制键代替
  1657. <li>
  1658. <span title="${uiLocal.dragInTextareaTitle[cfg.language]}">${uiLocal.dragInTextarea[cfg.language]}</span>
  1659. <span>
  1660. <input type="checkbox" id="dragInTextarea" name="dragInTextarea" checked="" class="switch">
  1661. <label for="dragInTextarea" class="switchOn"></label>
  1662. </span>
  1663. </li>
  1664. -->
  1665. `,
  1666.  
  1667. //=======gestureAndDragHTML End=========
  1668. aboutHTML = `
  1669. <pre style="font-size:1.2em !important;">
  1670. About userDefine function:
  1671. there are one argument(Object:mpData) provided in userDefine function.
  1672. mpData is a object like this:
  1673. {
  1674. gesture:"646", //gesture code of last mouse gesure
  1675. link:{ //optional, the target is link/image link...
  1676. href: "https://www.baidu.com/",
  1677. title: null, textContent: ""
  1678. }
  1679. target:{
  1680. src: "https://www.baidu.com/img/baidu_jgylogo3.gif", //target element arrtibute: src
  1681. title: "到百度首页", //target element arrtibute: title
  1682. alt: "到百度首页", //target element arrtibute: alt
  1683. textContent: "", //target element's text content
  1684. nodeName: "IMG", //target element's node name
  1685. self:{} //target element itself
  1686. }
  1687. textSelection:""
  1688. }
  1689. So, code in textarea shuold be <em>function body.</em>
  1690. And, you can add some not frequently used function as "userDefine" function to MP
  1691. </pre>
  1692. <a href="https://github.com/woolition/greasyforks/blob/master/mouseGesture/HY-MouseGesture.md" >(● ̄(エ) ̄●)づ <br>Click Me to More(点我看更多介绍)! </a>
  1693. `,
  1694. options = {
  1695. imgSearchEnging: {// image searching
  1696. 默认: "mull",
  1697. Baidu: "https://graph.baidu.com/details?isfromtusoupc=1&tn=pc&carousel=0&promotion_name=pc_image_shituindex&extUiData%5bisLogoShow%5d=1&image=U-R-L",
  1698. Google: "https://www.google.com/searchbyimage?image_url=U-R-L",
  1699. TinEye: "https://www.tineye.com/search?url=U-R-L",
  1700. Yandex: "https://yandex.com/images/search?rpt=imageview&url=U-R-L"
  1701. },
  1702. searchEnging: {// text searching
  1703. 默认: "null",
  1704. Baidu: "https://www.baidu.com/s?wd=",
  1705. Google: "https://www.google.com/search?q=",
  1706. Bing: "https://www.bing.com/search?q=",
  1707. Yahoo: "https://search.yahoo.com/search?p=",
  1708. Wiki: "https://en.wikipedia.org/w/index.php?search=",
  1709. Taobao: "https://s.taobao.com/search?q=",
  1710. Amazon: "https://www.amazon.com/s/&field-keywords=",
  1711. Sogou: "https://www.sogou.com/web?query=",
  1712. s360: "https://www.haosou.com/s?q="
  1713. },
  1714. vipAPI:{
  1715. 疯狂: "http://goudidiao.com/?url=",
  1716. 噗噗: "http://pupudy.com/play?make=url&id="
  1717. }
  1718. };
  1719.  
  1720.  
  1721. function q(cssSelector){
  1722. return document.querySelectorAll(cssSelector);
  1723. }
  1724. function attr(element,attributeName, attributeValue){
  1725. try {
  1726. if(attributeValue) element.setAttribute(attributeName, attributeValue);
  1727. else return element.getAttribute(attributeName);
  1728. } catch(e) {}
  1729. }
  1730. function each(elementCollect,func){
  1731. try{
  1732. Array.prototype.forEach.call(elementCollect, (item)=>{func(item);});
  1733. }catch(e){}
  1734. }
  1735. function listen(element, eventType, func){
  1736. element.addEventListener(eventType, func, false);
  1737. }
  1738. function sel(val1, val2){
  1739. return val1 == val2 ? 'selected="selected"' : '';
  1740. }
  1741. function click(evt){
  1742. function getName(evt){
  1743. if(evt.target.getAttribute('name')){
  1744. return evt.target.getAttribute('name');
  1745. }else {
  1746. if(evt.target.parentElement.getAttribute('name'))
  1747. return evt.target.parentElement.getAttribute('name');
  1748. else
  1749. return evt.target.parentElement.parentElement.getAttribute('name');
  1750. }
  1751. }
  1752. let named = getName(evt);
  1753. switch (named) {
  1754. case 'mg1':
  1755. case 'mg2':
  1756. case 'mg3':
  1757. each(q('.MPcontent'),(item)=>{
  1758. attr(item, 'style', 'display:none;');
  1759. });
  1760. attr(q('#'+named)[0], 'style', 'display:block;');
  1761. each(q('#MPmenu li'),item=>{
  1762. attr(item, 'class', ' ');
  1763. });
  1764. attr(q('[name='+named+']')[0], 'class', 'MPselected');
  1765. break;
  1766. case 'close':
  1767. q('body')[0].removeChild(q('#MPsetting')[0]);
  1768. break;
  1769. case 'addFunction':
  1770. toggleFunsList();
  1771. break;
  1772. case 'addFunctionLi':
  1773. clickToMakeEle();
  1774. break;
  1775. case 'alias':
  1776. attr(evt.target, 'contentEditable', "true");
  1777. break;
  1778. case 'toggleArgument':
  1779.  
  1780. if(evt.target.textContent === "▲"){
  1781. evt.target.textContent = "▼";
  1782. try{attr(evt.target.parentElement.lastChild,"style","display:none;");}
  1783. catch(e){}
  1784. }else {
  1785. evt.target.textContent = "▲";
  1786. try{attr(evt.target.parentElement.lastChild,"style","display:block;");}
  1787. catch(e){}
  1788. }
  1789. break;
  1790. case 'clearGesture':
  1791. case 'cancelGesture':
  1792. modul.captureGesture("", named);
  1793. break;
  1794. default:
  1795. if(cfg.hasOwnProperty(attr(evt.target, 'data-mark')))
  1796. addMask();
  1797. break;
  1798. }
  1799. }
  1800. function arg2html(argument, type, trk){
  1801. let html ="",
  1802. argu, i,rand, trackTxt, name,
  1803. argValue = [],
  1804. agrDetail = [],
  1805. description,
  1806. selectName;
  1807. if(typeof argument === "object")
  1808. argu = argument;
  1809. else
  1810. argu = JSON.parse(argument);
  1811. trackTxt = trk || '';
  1812. name = argu.name;
  1813.  
  1814. html += `<span>${name}</span><span name="alias">${argu.alias ? argu.alias : local[type][name][cfg.language]}</span><b style="visibility:${argu.arg.length ? "visible" : "hidden"};" name="toggleArgument">▲</b><input type="text" name="${name}" value="${trackTxt}" data-mark="${type}" readonly="readonly"><br/><div class="fnArgument">`;
  1815. if(argu.arg.length > 0){
  1816. argValue = trackTxt ? argu.arg : [];
  1817. agrDetail = fnLocal.arg[name].arg;
  1818. description = fnLocal.arg[name].description[cfg.language];
  1819.  
  1820. for(i in agrDetail){
  1821. rand = Math.floor(Math.random()*1000);
  1822. switch (agrDetail[i].slice(0,5)) {
  1823. case 'texta':
  1824. html += `<span><textarea>${mpUnescape(argValue[i])}</textarea><i></i></span>`;
  1825. break;
  1826. case 'input':
  1827. html += '<span><input type="text"><i></i></span>';
  1828. break;
  1829. case 'check':
  1830. html += `<span><input type="checkbox" id="${name + rand}" value=${argValue[i] || false} ${argValue[i] ? "checked" : ''} class="switch" name="fnCheckbox"><label for="${name + rand}" ${argValue[i] ? 'class="switchOn"' : 'class="switchOff"'}>${description[i]}</label></span>`;
  1831. break;
  1832. case 'selec':
  1833. selectName = agrDetail[i].split(':').pop();
  1834. html += `<span><input type="text" value=${argValue[i] || ''}><select name="fnSelect">`;
  1835. for (let k in options[selectName]){
  1836. html += `<option value=${options[selectName][k]}>${k}</option>`;
  1837. }
  1838. html += '</select></span>';
  1839. break;
  1840. default:
  1841. html = `<span style="visibility:hidden;"></span>`;
  1842. break;
  1843. }
  1844. }
  1845. }
  1846. return html + "</div>";
  1847. }
  1848. function makeFunsList(){
  1849. let color = ['yellow', 'green', 'blue', 'darkcyan'],
  1850. html = '',
  1851. arg = null;
  1852. each(['gesture', 'text', 'link', 'image'], (type)=>{
  1853. each(Object.keys(local[type]), (fnName)=>{
  1854. if(fnLocal.arg.hasOwnProperty(fnName))
  1855. arg = Object.assign({name:fnName},fnLocal.arg[fnName]);
  1856. else
  1857. arg = {name:fnName,arg:[]};
  1858. html += `<li data-type="${type}" data-arg='${JSON.stringify(arg)}' title="${local[type][fnName][cfg.language]}" name="addFunctionLi">
  1859. <span class="tag ${color[['gesture', 'text', 'link', 'image'].indexOf(type)]}">
  1860. <!--<span>${fnLocal.FunsListTitle[type][cfg.language]}</span>-->
  1861. <!--<span>-->${fnName}<!--</span>-->
  1862. </span>
  1863. </li>`;
  1864. });
  1865. });
  1866. html = `<fieldset id="FunsList" class="FunsListHide">
  1867. <h1 name="addFunction">${fnLocal.addFunction[cfg.language]} </h1><br/>
  1868. ${html}
  1869. </fieldset>`;
  1870. return html;
  1871. }
  1872. function makeDefinedFunsList(type){
  1873. let html ='';
  1874. each(Object.keys(cfg[type]), item=>{
  1875. try {
  1876. html += `<li data-arg='${JSON.stringify(cfg[type][item])}' data-type='${type}'>${arg2html(cfg[type][item], type, item)}`;
  1877. } catch(e) {}
  1878. });
  1879. return html;
  1880. }
  1881. function clickToMakeEle(){
  1882. let tarEle = event.target.tagName === 'LI' ? event.target : (event.target.parentNode.tagName === "LI" ? event.target.parentNode : event.target.parentNode.parentNode);
  1883. let ele = document.createElement('li');
  1884. ele.setAttribute('data-arg', tarEle.dataset.arg);
  1885. ele.setAttribute('data-type', tarEle.dataset.type);
  1886. ele.innerHTML = arg2html(tarEle.dataset.arg, tarEle.dataset.type);
  1887. document.getElementById('mg2').insertBefore(ele, document.querySelector(`#mg2>li`));
  1888. listen(ele.childNodes[2].childNodes[0], 'blur', updateConfigUi);
  1889. //函数列表收缩, 回滚到顶部
  1890. toggleFunsList();
  1891. document.documentElement.scrollTo(0, 0);
  1892. }
  1893. function updateFns(ele){
  1894. // check Conflict
  1895. if(Object.keys(cfg[ele.dataset.type]).indexOf(ele.childNodes[3].value) > -1){
  1896. if(JSON.parse(ele.dataset.arg).name !== cfg[ele.dataset.type][ele.childNodes[3].value].name){
  1897. attr(ele, "style", "background:red!important;");
  1898. alert("Gesture Conflict (手势冲突) !!!");
  1899. return;
  1900. }
  1901. }
  1902. // setting gesture not null
  1903. if(JSON.parse(ele.dataset.arg).name === "setting" && !ele.childNodes[3].value){
  1904. attr(ele, "style", "background:red!important;");
  1905. alert("Setting Gesture Cannot Set Null (设置手势不能为空) !!!");
  1906. return;
  1907. }
  1908. attr(ele, "style", " ");
  1909.  
  1910. let typeObject = {};
  1911. each(q(`#mg2>li[data-type=${ele.dataset.type}]`), element=>updateItem(element));
  1912. function updateItem(item){
  1913. let childrens, trk, argValue=[], name, dataArgObject, alias, argumentNodes;
  1914. trk = item.childNodes[3].value;
  1915. alias = item.childNodes[1].textContent;
  1916. //if mouse track is not empty , update Fns
  1917. if(trk !== ''){
  1918. childrens = item.childNodes[5].childNodes;
  1919. dataArgObject = JSON.parse(item.dataset.arg);
  1920. each(childrens, item=>{
  1921. if(item.firstElementChild.value && item.firstElementChild.value !== "undefined"){
  1922. // console.log(item.firstElementChild.nodeName);
  1923. // console.log('updateItem..');
  1924. if(item.firstElementChild.nodeName === "TEXTAREA")
  1925. argValue.push(mpEscape(item.firstElementChild.value));
  1926. else
  1927. argValue.push(item.firstElementChild.value);
  1928. } else{
  1929. argValue.push(' ');
  1930. }
  1931. });
  1932. typeObject[trk] = {name: dataArgObject.name, arg: argValue, alias:alias};
  1933. }
  1934. }
  1935. // console.log(typeObject);
  1936. cfg[ele.dataset.type] = typeObject;
  1937. storage.set('cfg', cfg);
  1938. }
  1939. function updateConfigUi(e){
  1940. let name = attr(e.target, 'name');
  1941. switch (name) {
  1942. case 'mouseButton':
  1943. case 'suppressionKey':
  1944. cfg.Gesture[name] = e.target.value;
  1945. break;
  1946. case 'distanceThreshold':
  1947. case 'distanceSensitivity':
  1948. case 'timeout':
  1949. cfg.Gesture[name] = parseInt(e.target.value);
  1950. break;
  1951. case 'directions':
  1952. case 'language':
  1953. cfg[name] = e.target.value;
  1954. break;
  1955. case 'background':
  1956. case 'lineColor':
  1957. cfg.Hinter[name] = e.target.value;
  1958. attr(e.target, 'style', `background: #${e.target.value} !important;`);
  1959. break;
  1960. case 'fontSize':
  1961. case 'minLineWidth':
  1962. case 'maxLineWidth':
  1963. case 'lineGrowth':
  1964. cfg.Hinter[name] = parseFloat(parseFloat(e.target.value).toFixed(2));
  1965. break;
  1966. case 'funNotDefine':
  1967. cfg.Hinter[name] = e.target.value;
  1968. break;
  1969. case 'linktextAslink':
  1970. case 'dragInTextarea':
  1971. cfg.Drag[name] = e.target.checked;
  1972. onOff(e, e.target.checked);
  1973. break;
  1974. default:
  1975. if(name === "alias")
  1976. updateFns(e.target.parentElement);
  1977. else if(name === "fnCheckbox" || name==="fnSelect"){
  1978. formChange();
  1979. }
  1980. return;
  1981. }
  1982. storage.set('cfg', cfg);
  1983. }
  1984. function formChange(){
  1985. if(event.target.type === 'checkbox'){
  1986. event.target.value = event.target.checked;
  1987. onOff(event, event.target.checked);
  1988. updateFns(event.target.parentElement.parentElement.parentElement);
  1989. }
  1990. if(event.target.tagName === 'SELECT'){
  1991. event.target.previousElementSibling.value = event.target.value;
  1992. updateFns(event.target.parentElement.parentElement.parentElement);
  1993. }
  1994. }
  1995. function onOff(e, check) {
  1996. if (check) {
  1997. attr(e.target.nextElementSibling, 'class', 'switchOn');
  1998. } else {
  1999. attr(e.target.nextElementSibling, 'class', 'switchOff');
  2000. }
  2001. }
  2002. function addMask(){
  2003. let
  2004. w=window.innerWidth,
  2005. h=window.innerHeight,
  2006. px = 0.1*w,
  2007. string=`
  2008. <svg height="${h}" width="${w}" style="background:#00000080">
  2009. <path id="record" d="
  2010. M${50}, ${50+px} v-${px} h${px}
  2011. M${w-px-50},${50} h${px} v${px}
  2012. M${w-50}, ${h-px-50} v${px} h-${px}
  2013. M${50+px}, ${h-50} h-${px} v-${px}"
  2014. style="stroke:#fff;stroke-width:${w/50};fill:none;"></path>
  2015. <text name="clearGesture" x="100" y="${h-100}" style="font-size:${Math.floor(w/20)}px;stroke:none;fill:white;cursor:pointer;">Clear</text>
  2016. <text name="A" x="${w-w/2}" y="${h-h/2}" style="font-size:${Math.floor(w/20)}px;stroke:none;fill:white;cursor:pointer;">A</text>
  2017. <text name="cancelGesture" x="${w-100-w/6}" y="${h-100}" style="font-size:${Math.floor(w/20)}px;stroke:none;fill:white;cursor:pointer;">Cancle</text>
  2018. </svg>`;
  2019. let mask = document.createElement('div');
  2020. mask.id = "MPMask";
  2021. mask.innerHTML = string + '<div id="recorddingGesture"></div>';
  2022. document.body.appendChild(mask);
  2023. each(q('text[name=clearGesture], text[name=cancelGesture]'), item=>listen(item,"click",click));
  2024.  
  2025. attr(q('#MPsetting')[0], "style", "z-index:9999998 !important;");
  2026. attr(event.target, "data-flag", "captureGesture");
  2027. runtime.captureGesture = true;
  2028. }
  2029. function toggleFunsList(){
  2030. let a = q('#FunsList')[0];
  2031. if(attr(a, 'class') === "FunsListHide"){
  2032. attr(a, 'class', 'FunsListShow');
  2033. }else{
  2034. attr(a, 'class', 'FunsListHide');
  2035. }
  2036. }
  2037.  
  2038.  
  2039. return modul;
  2040. })();
  2041.  
  2042. //========⑥Run===================
  2043.  
  2044. //this addStyle is better than GM_addStyle,but not working in CSP tabs
  2045. // function addStyle(cssStr,id='MPStyle'){
  2046. // try {
  2047. // let node = document.createElement('style');
  2048. // node.id = id;
  2049. // node.textContent = cssStr;
  2050. // document.querySelector(':root').appendChild(node);
  2051. // } catch(e){}
  2052. // }
  2053. function addStyle(cssStr,id='MPStyle'){
  2054. GM_addStyle(cssStr);
  2055. }
  2056. addStyle(`
  2057. @font-face {
  2058. font-family: 'MParrow';
  2059. src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAQdAAoAAAAABPAAAQAAAAAAAAAAAAAAAAAAAAAECAAAABVPUy8yAAABYAAAAEQAAABgUc1dNGNtYXAAAAHEAAAARgAAAGAAcgFDZ2x5ZgAAAiAAAADwAAABNKukdSxoZWFkAAAA9AAAADQAAAA2DKcEFmhoZWEAAAEoAAAAHQAAACQEKQIaaG10eAAAAaQAAAAfAAAAJBGtAZVsb2NhAAACDAAAABQAAAAUATIBfm1heHAAAAFIAAAAFQAAACAACwAKbmFtZQAAAxAAAADnAAABe0DXvWtwb3N0AAAD+AAAABAAAAAgAAMAAXjaY2BkYGAA4gfLE97F89t8ZeBkYgCBq07amiD6mu+MRAaB/3cZXzFuAnI5GMDSAEgbC5142mNgZGBgYgACPSApwCDA+IqBkQEVcAIAGeEBSQAAAHjaY2BkYGDgBEIQzQAlkQAAAjsAFgAAAHjaY2Bm/MY4gYGVgYPRhzGNgYHBHUp/ZZBkaGFgYGJg5WSAAUYGJBCQ5poCpAwZLBkf/H/AoMeEpIaRAcpjAAAVNgmoeNpjYmBgYPzCYAbE3lBagImBQQzM/srgA6IBjAwITgB42i2KywmAQBQD57l+e9gCvAoieLd/7ShmnwZCmDBA4WslaLlMkdyzekdv0LFzSuaNQ9Kj+/ebUfNf0iv2YfA7Mb+pBQmvAAAAAAAAABQAJgA6AEwAXgByAIYAmnjaVY8hT8NAGIa/N0tzLJlgbY4LYmI0zekvTTmBuHomcGT9DXMkpD8Bwd+AhIo1wa8CVYfF4DCgm8wV7m6Gqc+8eZ7nI9AlRejwSCdERvAkYqHEQxljarv6zWIau0sEuv79xAtewy4tjJLpPH2q2rZqvtH3GAc6YiWaswlroQfPKLsaVzYe93ZXu90pneML94ElWRuWS/nhILO7qt2uG/K+M7f5OWxQsBJcLAtc9P04YLHeOu2xL1McJayMAtlx74W34YngW7n25tCe5VLoIp/nuAnxzz4eMwrO/zzDScZGG2xK393V74G7q/8AczlNtXjadY7BasJAEIb/mKgVSumh3ucBoiQetHjpod6K4MlLi7CROSzEBDaB0EfoC/hEvoLv0990G0Rwhtn99p9/hwHwiCMCXCLAsD0v0eP94DnEuNMjjDruY8rOHw/ofqcziEZUnvDhuccfn55D+v/1CC8d9/GFb88DPOO83hjnykbetuoqWxaSTpPkmmWlez1k6mQeyyxJF7HYwtbW5OI0V1OpHzHBGhsYOGaJBrJ7/TlhiS2USgVLtYAg5WoJ854uWLGzZx2QtR7BHDHPGbspFi1b/rGoWQY5347OnGU4UW82mfwCMzM4HQB42mNgZkAGjAxoAAAAjgAFSExQRAEARkMJAAAAUGF3J1oAAAAA) format('woff');
  2060. }
  2061. #MPcanvas{position:fixed;top:0;left:0;z-index:10000000;}
  2062. #MPtips{all:initial!important;position:fixed!important;z-index:9999996!important;top:50%!important;left:50%!important;transform:translate(-50%,-50%)!important;font-family:MParrow,"Arial",sans-serif!important;color:white!important;white-space:nowrap!important;line-height:normal!important;text-shadow:1px 1px 5px rgba(0,0,0,0.8)!important;text-align:center!important;padding:25px 20px 20px 20px!important;border-radius:5px!important;font-weight:bold!important; }
  2063. `);
  2064. //===========update any time=========
  2065. GM_addValueChangeListener('cfg', ()=>{
  2066. GestureHandler.applySettings(cfg);
  2067. Hinter.applySettings(cfg);
  2068. });
  2069. //when close a tab, save it's url, in order to reopen it: reopenTab
  2070. window.addEventListener('unload', function() {
  2071. //GM_setValue('latestTab', window.location.href);
  2072. }, false);
  2073. //used in func: closeOtherTabs
  2074. if(!GM_getValue('closeAll','')) GM_setValue('closeAll', Date());
  2075. GM_addValueChangeListener('closeAll',function(name, old_value, new_value, remote){if(remote)window.close();});
  2076. //===========update any time end=========
  2077.  
  2078. GestureHandler.applySettings(cfg);
  2079. Hinter.applySettings(cfg);
  2080. GestureHandler.enable();
  2081. Hinter.enable();
  2082.  
  2083. //========Remind===================
  2084. var timercon;
  2085. function showclipboard(text) {
  2086. server.containerDestroy();// 销毁内容面板
  2087. // 新建内容面板
  2088. var container = server.container();
  2089. container.style.top = 0 + 'px';
  2090. //if (ev.pageX + 350 <= document.body.clientWidth)// container 面板css最大宽度为250px
  2091. container.style.right = 0 + 'px';
  2092. //container.style.position = 'absolute';
  2093. container.style.position = 'fixed';
  2094. //else
  2095. //container.style.left = document.body.clientWidth - 350 + 'px';
  2096. document.body.appendChild(container);
  2097. server.rendered.push(container);
  2098.  
  2099. displaycontainer(text, container);
  2100.  
  2101. clearTimeout(timercon);
  2102. timercon = window.setTimeout(function(){ container.style.display = "none";}, 6000);
  2103. }
  2104.  
  2105.  
  2106. let ev = null;
  2107. document.addEventListener('mouseclick', function (e) {
  2108. ev = e;//划词鼠标结束位置
  2109. });
  2110.  
  2111.  
  2112. function displaycontainer(text, element) {
  2113. element.innerHTML = text;
  2114. element.style.display = 'block';// 显示结果
  2115. //trans = text;
  2116. //任何结果复制到剪切板
  2117. //GM_setClipboard(text);
  2118. }
  2119.  
  2120.  
  2121.  
  2122. // 翻译server
  2123. var server = {
  2124. // 存放已经生成的内容面板(销毁的时候用)
  2125. rendered: [],
  2126. // 销毁已经生成的内容面板
  2127. containerDestroy: function () {
  2128. for (var i = this.rendered.length - 1; i >= 0; i--) {
  2129. if (this.rendered[i] && this.rendered[i].parentNode) {
  2130. this.rendered[i].parentNode.removeChild(this.rendered[i]);
  2131. }
  2132. }
  2133. },
  2134. // 面板 DOM (此时还未添加到页面)
  2135. container: function () {
  2136. var div = document.createElement('div');
  2137. div.setAttribute('style', '' +
  2138. 'display:none!important;' +
  2139. 'position:absolute!important;' +
  2140. 'font-size:4px!important;' +
  2141. 'overflow:auto!important;' +
  2142. //'background:#fff!important;' +
  2143. 'background-color:rgba(255,255,255,0.3)!important;' +
  2144. 'font-family:sans-serif,Arial!important;' +
  2145. 'font-weight:normal!important;' +
  2146. 'text-align:left!important;' +
  2147. 'color:#000!important;' +
  2148. 'padding:0.5em 1em!important;' +
  2149. //'line-height:1.5em!important;' +
  2150. 'border-radius:3px!important;' +
  2151. 'border:1px solid #ccc!important;' +
  2152. //'box-shadow:4px 4px 8px #888!important;' +
  2153. 'max-width:350px!important;' +
  2154. 'max-height:1216px!important;' +
  2155. 'z-index:2147483647!important;' +
  2156. '');
  2157. return div;
  2158. }
  2159. };// server结束
  2160.  
  2161.  
  2162.  
  2163. })();

QingJ © 2025

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