Greasy Fork is available in English.

鼠标拖拽

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

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