MouseGesture--HY

HY's mouse gesture script,supports ringt-key draw track functions and left-key drag functions.Drag target can be [Text] & [Links] & [Image] Customizenable → Right click to draw ⇄(left,right) to setting

目前為 2017-12-31 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         MouseGesture--HY
// @name:zh-CN     鼠标手势--就是这么拽!
// @namespace      https://greasyfork.org/users/104201
// @description    HY's mouse gesture script,supports ringt-key draw track functions and left-key drag functions.Drag target can be [Text] & [Links] & [Image]  Customizenable → Right click to draw ⇄(left,right) to setting
// @description:zh-CN  鼠标手势脚本,就是这么拽:支持右键轨迹手势和左键拖拽功能.可以拖拽[文本],[链接]和[图片],支持自定义设置:鼠标画➡⬅(右左)路径,进入设置
// @version      1.7
// @include      *
// @noframes
// @run-at       document-end
// @grant        GM_openInTab
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_setClipboard
// @grant        GM_download
// @grant        GM_addValueChangeListener
// @grant        GM_notification
// @grant        window.close
// @grant        GM_getResourceText
// @grant        GM_xmlhttpRequest
// Thanks to: Peer Zeng's script:  https://greasyfork.org/zh-CN/scripts/4776-my-mouse-gestures [no License] [for right click gesture handle]
// Thanks to: crxMouse Chrome™ Gestures [chrome crxID:jlgkpaicikihijadgifklkbpdajbkhjo] [for: drag processing]
// Thanks to: Robbendebiene's project Gesturefy [https://github.com/Robbendebiene/Gesturefy] [for canvas line style]
// Thanks to: Jim Lin's userscript 有道划词翻译 [https://greasyfork.org/zh-CN/scripts/15844] [License MIT][for 划词翻译]
// ==/UserScript==
/* jshint esversion: 6 */

const MouseGesture = (function() {
  let arrowCss = `@font-face {
    font-family: 'MParrow';
    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');
    }
    #MPcanvas{position:fixed;top:0;left:0;z-index:9999999;}
    #MPtips{all:initial!important;position:fixed!important;z-index:9999998!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; }
    `;
  GM_addStyle(arrowCss);
  let dObj = {};// the Object Element being draged
  let x, y, startX, startY, screenX, screenY, canvas, tips, ctx,
  direction = '', track = '';
  //_*:  default cfg values
  let _cfg = {
    t2n:{           // t2n: track <==> function name
      "2":  {name:"toTop",    arg:[]},
      "8":  {name:"toBottom", arg:[]},
      "4":  {name:"back",     arg:[]},
      "6":  {name:"forward",  arg:[]},
      "86": {name:"close",    arg:[]},
      "42": {name:"reopenTab",arg:[]},
      "64": {name:"setting",  arg:[]}
    },
    dt2n: {         //dt2n: dragText <==> function name
      "8":  {name:"copyText", arg:[]},
      "6":  {
              name:"searchText",
              arg:["http://www.baidu.com/s?wd=", true, true]
            }
    },
    dl2n: {         //dl2n: drag link <==> function name
      "6": {name:"openLink",   arg:[]},
      "8": {name:"copyLink",   arg:[]}
    },
    di2n: {         //li2n: drag image <==> function
      "8": {name:"saveImg",    arg:[]},
      "6": {
              name:"searchImg",
              arg:['https://image.baidu.com/n/pc_search?queryImageUrl=%URL&uptype=urlsearch', true, true]
            },
      "2": {name:"copyImgURL", arg:[]},
      "4": {name:"selectImg",  arg:[]}
    },
    directions:        4,              // 4 or 8 directions
    minLineWidth:      1,               //canvas setting
    lineGrowth:        0.6,
    maxLineWidth:      10,
    lineColor:         '00AAA0',

    fontSize:          50,             //tips font size
    tipsBackground:    "00000055",     //div background
    funNotDefine:      "  (◔ ‸◔)?",  //function not define tips

    language:          1,              //language 0:Chinese 1:English
    sensitivity:       10,             // minLength
    translateTo:      'zh-CHS',
    translateTimeout: 5,
    zoom:             2,

    dragType:         "",
    dragtext:         true,
    draginput:        true,
    draglink:         true,
    dragimage:        true,
    imgfirst:         false,
    imgfirstcheck:    true,
    setdragurl:       true
  };
  //function name <==> tips
  let fn = {
    t2n: {
      stopLoading:     ['停止加载',         'StopLoading'],
      reload:          ['刷新',             'Refresh'],
      reloadNoCache:   ['清缓存刷新',       'Refresh Without Cache'],
      close:           ['关闭',             'Close'],
      back:            ['后退',             'Back'],
      forward:         ['前进',             'Forward'],
      toTop:           ['到顶部',           'Scroll to Top'],
      toBottom:        ['到底部',           'Scroll to Bottom'],
      reopenTab:       ['打开最近关闭窗口', 'Reopen Latest Closed Window'],
      setting:         ['设置',             'Settings'],
      URLLevelUp:      ['网址向上一层',     'URL hierarchy up'],
      cloneTab:        ['克隆标签页',       'Duplicate This Tab'],
      openBlankTab:    ['打开空白页',       'Open New Blank Tab'],
      translate:       ['翻译网页',         'Translate This Page'],
      fkVip:           ['破解VIP视频',      'Crack to Watch VIP Video'],
      closeOtherTabs:  ['关闭其他标签',     'Close Other Tabs'],
      translateSelect: ['开启划词翻译',     'Turn on Select And Translate'],
      //开发者功能
      contentEditable: ['元素内容可编辑',   'Element Content Editable']
    },
    dt2n: {
      searchText:      ['搜索选中文本',     'Search Selected Text'],
      copyText:        ['复制选中文本',     'Copy Selected Text']
    },
    dl2n: {
      openLink:        ['打开链接',         'Open Link'],
      copyLink:        ['复制链接',         'Copy Link'],
      copyLinkText:    ['复制链接文字',     'Copy Link Text']
    },
    di2n: {
      saveImg:         ['保存图片',         'Save Image'],
      searchImg:       ['搜索图片',         'Search Image'],
      copyImage:       ['复制图片',         'Copy Image to ClickBoard'],
      copyImgURL:      ['复制图片链接',     'Copy ImageURL'],
      openImgNewTab:   ['新标签打开图片',   'Open Image in New Tab'],
      image2DataURL:   ['复制图片为DataURL','Copy Image as DataURL'],
      selectImg:       ['选中图片',         'Select This Image']
    }
  };
  //function name <==> function declaration  ==> execute it
  let Fn = {
    stopLoading: function() {
      window.stop();
    },
    reload: function(arr) {
      history.go(0);
      //window.location.reload();
    },
    reloadNoCache: function() {
      window.location.reload(true);
    },
    close: function() {
      window.close();
    },
    back: function() {
      history.back();
    },
    forward: function() {
      history.forward();
    },
    toTop: function() {
      document.documentElement.scrollTo(0, 0);
    },
    toBottom: function() {
      document.documentElement.scrollTo(0, 9999999);
    },
    reopenTab: function() {
      //GreasyMonkdy:
      // GM_openInTab(GM_getValue('latestTab'),false);
      //TamperMonkey:
      GM_openInTab(GM_getValue('latestTab', 'about:blank'), {
        active: true
      });
    },
    URLLevelUp: function() {
      //当前网址的层次结构向上一层
      if (window.location.href[window.location.href.length - 1] === "/")
        window.location.href = "../";
      else
        window.location.href = "./";
    },
    //clone curren tab ,background
    cloneTab: function() {
      GM_openInTab(location.href, {
        active: false
      });
    },
    //open new blank tab
    openBlankTab: function() {
      window.open('about:blank');
    },

    //use MicrosoftTranslator to translate the page
    translate: function(arr) {

      if (typeof Microsoft === 'undefined' || typeof Microsoft.Translator === 'undefined') {
        let d = document.createElement('div');
        d.id = "MicrosoftTranslatorWidget";
        d.style.cssText = 'visibility:hidden;';
        d.setAttribute('class', 'Lignt');
        let s = document.createElement('script');
        s.type = 'text/javascript';
        s.charset = 'UTF-8';
        s.src = ((location && location.href && location.href.indexOf('https') == 0) ? 'https://ssl.microsofttranslator.com' : 'http://www.microsofttranslator.com') + '/ajax/v3/WidgetV3.ashx?siteData=ueOIGRSKkd965FeEGM5JtQ**&ctf=False&ui=true&settings=Manual&from=';
        let p = document.getElementsByTagName('head')[0] || document.documentElement;
        p.insertBefore(s, p.firstChild);
        document.body.appendChild(d);
      }
      let onComplete, onProgress, onError;
      onError = function(){
        GM_notification({
          title: 'MouseGesture:',
          text: cfg.language ? "出了问题,无法完成翻译" : "Oops,Something wrong Hapend...",
          timoeout: 2000
        });
        tips.parentNode.removeChild(tips);
      };
      onComplete = function() {
        tips.parentNode.removeChild(tips);
      };
      onProgress = function() {
        document.documentElement.appendChild(tips);
        tips.innerHTML = cfg.language ? "翻译中..." : "Translating...";
      };
      let doTranslate = function() {
        if (typeof Microsoft === 'undefined' || typeof Microsoft.Translator === 'undefined') return;
        clearInterval(loadTranslatorTimer);
        Microsoft.Translator.Widget.Translate('', arr[0], onProgress, onError, onComplete, () => {}, (cfg.translateTimeout) * 1000);
      };
      loadTranslatorTimer = setInterval(doTranslate, 200);
      setTimeout(() => clearTimeout(loadTranslatorTimer), (cfg.translateTimeout) * 1000);
    },
    fkVip: function() {
      GM_openInTab((cfg.vipApi)+location.href, {active:true});
    },
    closeOtherTabs: function() {
      GM_setValue('closeAll', Date());
    },
    translateSelect: function() {
      window.document.body.addEventListener('mouseup', translate, false);
      var context = new AudioContext();
      function translate(e) {
        var previous = document.querySelector('.youdaoPopup');
        if (previous) {
          document.body.removeChild(previous);
        }
        var selectObj = document.getSelection();
        if (selectObj.anchorNode.nodeType == 3) {
          var word = selectObj.toString();
          if (word == '') {
            return;
          }
          word = word.replace('-\n', '');
          word = word.replace('\n', ' ');
          var ts = new Date().getTime();
          var x = e.clientX;
          var y = e.clientY;
          translate(word, ts);
        }
        function popup(x, y, result) {
          var youdaoWindow = document.createElement('div');
          youdaoWindow.classList.toggle('youdaoPopup');
          var dict = JSON.parse(result);
          var query = dict.query;
          var errorCode = dict.errorCode;
          if (dict.basic) {
            word();
          } else {
            sentence();
          }
          youdaoWindow.style.cssText = `z-index:999999;display:block;position:fixed;color:black;text-align:left;word-wrap:break-word;background:lightBlue;border-radius:5px;box-shadow:0 0 5px 0;opacity:1;width:200px;left:${x+10}px;padding:5px`;
          if (x + 200 + 10 >= window.innerWidth) {
            youdaoWindow.style.left = parseInt(youdaoWindow.style.left) - 200 + 'px';
          }
          if (y + youdaoWindow.offsetHeight + 10 >= window.innerHeight) {
            youdaoWindow.style.bottom = '20px';
          } else {
            youdaoWindow.style.top = y + 10 + 'px';
          }
          document.body.appendChild(youdaoWindow);
          function word() {
            var basic = dict.basic;
            var header = document.createElement('p');
            var span = document.createElement('span');
            span.innerHTML = query;
            header.appendChild(span);
            var phonetic = basic.phonetic;
            if (phonetic) {
              var phoneticNode = document.createElement('span');
              phoneticNode.innerHTML = '[' + phonetic + ']';
              phoneticNode.style.cursor = 'pointer';
              header.appendChild(phoneticNode);
              phoneticNode.addEventListener('mouseup', function(e) {
                e.stopPropagation();
              }, false);
              var soundUrl = 'https://dict.youdao.com/dictvoice?type=2&audio={}'.replace('{}', query);
              var promise = new Promise(function() {
                GM_xmlhttpRequest({
                  method: 'GET',
                  url: soundUrl,
                  responseType: 'arraybuffer',
                  onload: function(res) {
                    try {
                      context.decodeAudioData(res.response, function(buffer) {
                        phoneticNode.addEventListener('mouseup', function() {
                          var source = context.createBufferSource();
                          source.buffer = buffer;
                          source.connect(context.destination);
                          source.start(0);
                        }, false);
                        header.appendChild(document.createTextNode('✓'));
                      });
                    } catch (e) {}
                  }
                });
              });
              promise.then();
            }
            header.style.color = 'darkBlue';
            header.style.margin = '0';
            header.style.padding = '0';
            span.style.color = 'black';
            youdaoWindow.appendChild(header);
            var hr = document.createElement('hr');
            hr.style.margin = '0';
            hr.style.padding = '0';
            youdaoWindow.appendChild(hr);
            var ul = document.createElement('ul');
            ul.style.margin = '0';
            ul.style.padding = '0';
            basic.explains.map(function(trans) {
              var li = document.createElement('li');
              li.style.listStyle = 'none';
              li.style.margin = '0';
              li.style.padding = '0';
              li.appendChild(document.createTextNode(trans));
              ul.appendChild(li);
            });
            youdaoWindow.appendChild(ul);
          }
          function sentence() {
            var ul = document.createElement('ul');
            ul.style.margin = '0';
            ul.style.padding = '0';
            dict.translation.map(function(trans) {
              var li = document.createElement('li');
              li.style.listStyle = 'none';
              li.style.margin = '0';
              li.style.padding = '0';
              li.appendChild(document.createTextNode(trans));
              ul.appendChild(li);
            });
            youdaoWindow.appendChild(ul);
          }
        }
        function translate(word, ts) {
          var reqUrl = 'http://fanyi.youdao.com/openapi.do?type=data&doctype=json&version=1.1&relatedUrl=' +
            escape('http://fanyi.youdao.com/#') +
            '&keyfrom=fanyiweb&key=null&translate=on' +
            '&q={}'.replace('{}', word) +
            '&ts={}'.replace('{}', ts);
          GM_xmlhttpRequest({
            method: 'GET',
            url: reqUrl,
            onload: function(res) {
              popup(x, y, res.response);
            }
          });
        }
      }
    },
    contentEditable: function(){
      console.log('x:'+startX+' y:'+startY);
      document.elementFromPoint(startX, startY).setAttribute('contenteditable', 'true');
      document.elementFromPoint(startX, startY).setAttribute('data-mp', '1');
    },
    /*
    //not torking
    zoomIn: function(){
       setTimeout(zoomer, 200);
      function zoomer(evt){
        let a, b,isZoom = true;
        a = document.elementFromPoint(evt.clientX,evt.clientY).style.zoom=cfg.zoom;
        a.setAttribute('data-zoom', 'true');
        [].every.forEach(document.querySelectorAll('*[data-zoom=true]'), function(item){
          if (item !== a) item.style.zoom = null;
        });
      }
    },*/

    searchText: function(evt, arr) {
      //get text
      let txt = window.getSelection().toString();
      txt = encodeURIComponent(txt);
      //get search enging
      openURL = arr[0] + txt;
      GM_openInTab(openURL, {
        active: arr[1],
        insert: arr[2],
        setParent: true   //makes the browser re-focus the current tab on close.
      });
    },
    copyText: function() {
      GM_setClipboard(dObj.text, "text");
    },
    openLink: function() {
      //TamperMonkey
      GM_openInTab(dObj.link, {
        active: true
      });
    },
    copyLink: function() {
      GM_setClipboard(dObj.link, "text");
    },
    copyLinkText: function() {
      GM_setClipboard(dObj.text, "text");
    },
    saveImg: function() {
      //TamperMonkey
      let arr = dObj.img.split('/');
      let name = arr[arr.length - 1];
      GM_download(dObj.img, name);
      //method 2
      /*
      let a = document.createElement('a');
      a.href = dObj.img; a.setAttribute('download', dObj.img.split('/').pop());
      document.documentElement.appendChild(a);
      a.click();
      a.parentElement.remove(a);
      */
      /* //jQuery:
      $("<a>").attr("href", actionFn.request.selimg).attr("download", actionFn.request.selimg.split('/').pop()).appendTo("body");
      a[0].click();
      a.remove();
      */
    },
    searchImg: function(event,arr) {
      //TamperMonkey
      GM_openInTab(arr[0].replace(/%URL/, dObj.img), {
        active: arr[1],
        insert: arr[2],
        setParent: true   //not working
      });
    },
    selectImg: function() {
      // it may not working on some browsers [develping standard]
      //TamperMonkey
      document.execCommand('selectAll');
      let sel = document.getSelection();
      sel.collapse(dObj.target, 0);
      sel.modify("extend", "forward", "character");
    },
    //not working:
    copyImage: function(e) {
      let canvas = canvasDrawTheImage(e);
      // get image as blob
      canvas.canvas.toBlob((blob) => {
        GM_setClipboard(blob, {
          type: canvas.type,
          mimetype: canvas.mime
        });
      }, canvas.mime);
    },
    image2DataURL: function(e) {
      //canvas绘制图片,由于浏览器的安全考虑:
      //如果在使用canvas绘图的过程中,使用到了外域的图片资源,那么在toDataURL()时会抛出安全异常:
      let canvas = canvasDrawTheImage(e).canvas;
      let dataURL = canvas.toDataURL();
      GM_setClipboard(dataURL, "text");
    },
    copyImgURL: function() {
      //TamperMonkey
      GM_setClipboard(dObj.img, "text");
    },
    openImgNewTab: function() {
      //TamperMonkey
      GM_openInTab(dObj.img, {
        active: true
      });
    },
    setting: function() {
      if (document.getElementById('HYetting')) {
        return;
      }
      makeSettingUi();
    }
  };
  let flag = {
    actionType:'',
    isDrag:    false,      //if drag ,isDrag = true
    isPress:   false,     //if mouse right key is press,ispress = true
    hascanvas: false,   //if document has <canvas> hascanvas = true
    isZoom:    false       //zoom mode
  };
  //============ supportive functions ==> used by Fn{}'s function
  //check if string is an url
  function isURL(string) {
    try {
      new URL(string);
    } catch (e) {
      return false;
    }
    return true;
  }
  function isObject (item) {
    return (item && typeof item === 'object' && !Array.isArray(item) && item !== null);
  }
  /**
   * deep merge two objects into a new one
   * from https://stackoverflow.com/a/37164538/3771196
   **/
  function mergeDeep (target, source) {
    let output = Object.assign({}, target);
    if (isObject(target) && isObject(source)) {
    Object.keys(source).forEach(key => {
      if (isObject(source[key])) {
      if (!(key in target))
        Object.assign(output, { [key]: source[key] });
      else
        output[key] = mergeDeep(target[key], source[key]);
      }
      else Object.assign(output, { [key]: source[key] });
    });
    }
    return output;
  }
  let cfg = mergeDeep(_cfg,GM_getValue('cfg', _cfg));
  //return: {canvas:canvas,type:fileType,mime:mimeType}
  function canvasDrawTheImage(e) {
    // let img = e.target,
    let img = dObj.target,
      fileType = img.src.split('/').pop().split('.').pop().toLowerCase(),
      mimeType = 'image/' + fileType,
      canvas = document.createElement('canvas');
    canvas.width = getNaturalSize(img).width;
    canvas.height = getNaturalSize(img).height;
    canvas.getContext('2d', {
      alpha: true
    }).drawImage(img, 0, 0);
    return {
      canvas: canvas,
      type: fileType,
      mime: mimeType
    };
  }
  // function canvasDrawTheImage(e) {
  //   // let img = e.target,
  //   var img=new Image;
  //   img.onload=function(){
  //     var canvas=document.createElement("canvas");
  //     canvas.width = getNaturalSize(img).width;
  //     canvas.height = getNaturalSize(img).height;
  //     var g=canvas.getContext("2d",{alpha:true});
  //     g.drawImage(img,0,0);
  //     console.log(canvas.toDataURL());
  //   };
  //   img.crossOrigin="anonymous"; //关键
  //   img.src=dObj.img;
  //   return {
  //     canvas: canvas,
  //     type: 'png',
  //     // type: fileType,
  //     mime: 'image/png'
  //     // mime: mimeType
  //   };
  // }
  // get image natural width and height
  function getNaturalSize(ele) {
    let i, w, h;
    if (typeof ele.naturalWidth == 'undefined') { // IE 6/7/8
      i = new Image();
      i.src = ele.src;
      w = i.width;
      h = i.height;
    } else { // HTML5 browsers
      w = ele.naturalWidth;
      h = ele.naturalHeight;
    }
    return {
      width: w,
      height: h
    };
  }
  //============ function for all
  //show Tips
  function showTips(){
    if (cfg[cfg.dragType][track] !== undefined) {
      tips.innerHTML = track + '<br/>' + fn[cfg.dragType][cfg[cfg.dragType][track].name][cfg.language];
    } else {
      tips.innerHTML = track + '<br/>' + (cfg.funNotDefine);
    }
  }
  function drawTrack(e){
    if (flag.hascanvas) {
      ctx.lineWidth = Math.min(cfg.maxLineWidth, ctx.lineWidth += cfg.lineGrowth);
      ctx.beginPath();
      ctx.moveTo(x, y);
      ctx.lineTo(e.clientX, e.clientY);
      ctx.stroke();
      ctx.closePath();
    }
  }
  function getDirection(cx, cy){
    /*=================
    |                 |
    | 1↖   2↑   3↗ |
    |                 |
    | 4←    5    6→ |
    |                 |
    | 7↙   8↓   9↘ |
    |                 |
    |=================*/
    let d, t;
    if(cfg.directions === 4){   //4 directions
      if (dx < dy) {
        d = cy > y ? "8" : "2";
      } else {
        d = cx > x ? "6" : "4";
      }
    }else{  //8 directions
      t = (cy-y)/(cx-x);
      if(-0.4142<= t && t < 0.4142) d = cx > x ? '6' : "4";
      else if(2.4142 <= t || t< -2.4142) d = cy > y ? '8' : '2';
      else if(0.4142 <= t && t < 2.4142) d= cx > x ? '9' : '1';
      else d = cy > y ? '7' : '3';
    }
    return d;
  }
  //draw track & show tips
  function tracer(e) {
   // const tracer = function(e) {
    let cx = e.clientX,
      cy = e.clientY;
      dx = Math.abs(cx - x),
      dy = Math.abs(cy - y);
      distance = dx * dx + dy * dy;
    if (distance < cfg.sensitivity * cfg.sensitivity) {
      return;
    }
    //if mouse right key is press and document has no <canvas>,then creaet <canvas> and append it
    //到里面才添加元素是为了避免 鼠标一按下,还没有移动就已经图层了
    //这个图层有两方面作用,①画出轨迹 ②支持拖拽功能, 因为作用②,所以不能移到 drawTrack 函数里面
    if (flag.isPress && !flag.hascanvas) addCanvas(e);
    let direction = getDirection(cx,cy);
    if (track.charAt(track.length - 1) !== direction) {
      track += direction;
      showTips();     //show action tips
    }
    drawTrack(e);      //draw track on canvas
    // update (x,y)
    x = cx;
    y = cy;
  }
  //<canvas> & tips<div> is ready, when mousemove or drag, append to show track & tips
  function addCanvas(e) {
    document.documentElement.appendChild(tips);     //append tips <div>
    document.documentElement.appendChild(canvas);   //append <canvas>
    canvas.width = window.innerWidth;               //set canvas attribute to clear content
    canvas.height = window.innerHeight;
    ctx.lineCap = "round";
    ctx.lineJoin = "round";
    if(cfg.lineColor.length>6)canvas.style.opacity = parseInt(cfg.lineColor.slice(6),16)/255;
    ctx.lineWidth = cfg.minLineWidth;
    ctx.strokeStyle = '#' + cfg.lineColor.slice(0,6); //like delicious link color//line color
    flag.hascanvas = true;
  }
  //remove <canvas> and tips<div>,set flags to false
  function reset() {
    if (flag.hascanvas) {
      document.documentElement.removeChild(canvas);
      document.documentElement.removeChild(tips);
    }
    flag.isPress = false;
    flag.hascanvas = false;
  }
  function createCanvaTips(){
    //create <canvas>
    canvas = document.createElement("canvas");
    canvas.id = 'MPcanvas';
    ctx = canvas.getContext("2d");
    //create tips<div>
    tips = document.createElement('div');
    tips.id = 'MPtips';
    tips.style.cssText = `background:#${cfg.tipsBackground} !important;  font-size: ${cfg.fontSize}px !important;`;
  }
  createCanvaTips();

  //=========== event processing
  //right click ==> gesture
  window.addEventListener('mousedown', function(e) {
    // 3 : mouse.right ; 1:mouse.left
    if (e.which === 3) {
      startX = x = e.clientX;
      startY = y = e.clientY;
      track = "";
      flag.isPress = true;
      // flag.actionType = "common";
      cfg.dragType = "t2n";
      window.addEventListener('mousemove', tracer, false);
    }
  }, false);
  window.addEventListener('contextmenu', function(e) {
    reset();
    window.removeEventListener('mousemove', tracer, false);
    if (track !== "") {
      e.preventDefault();
      if (cfg.t2n.hasOwnProperty(track)) {
        Fn[cfg.t2n[track].name](cfg.t2n[track].arg);
      }
    }
  }, false);

  //left click ==> drag
  window.addEventListener('dragstart', function(e) {
    startX = x = e.clientX;
    startY = y = e.clientY;
    track = '';
    flag.isPress = true;
    flag.isDrag = true;
    flag.actionType = "drag";
    processDrag(e);
    window.addEventListener('drag', tracer, false);
    //避免释放鼠标时候,坐标跑到(0,0) window.allowDrop
    this.allowDrop = function(event) {
      event.preventDefault();
    };
    tips.addEventListener("dragover", allowDrop, false);
    canvas.addEventListener("dragover", allowDrop, false);
  }, false);
  window.addEventListener('dragend', function(e) {
    window.removeEventListener('drag', tracer, false);
    tips.removeEventListener("dragover", allowDrop, false);
    canvas.removeEventListener("dragover", allowDrop, false);
    reset();
    isDrag = false;
    if (track !== "" && cfg[cfg.dragType].hasOwnProperty(track)) {
      // dragType + track => function
      console.log(cfg[cfg.dragType][track].arg);
      Fn[cfg[cfg.dragType][track].name](event,cfg[cfg.dragType][track].arg);
    }
  }, false);

  function processDrag(e) {
    //========这部分借鉴 crxMouse Chrome™ Gestures, crxID:jlgkpaicikihijadgifklkbpdajbkhjo===========
    dObj.target = e.target;
    let nodetype = e.target.nodeType;
    //confirm dragType
    if (nodetype === 3) {
      let isLink = e.target.parentNode.href;
      if (cfg.dragtext && !isLink) {
        // cfg.dragType = "text";
        cfg.dragType = "dt2n";
      } else if (isLink) { //use regular express to match?
        e = e.target.parentNode;
        cfg.dragType = "dl2n";
        // cfg.dragType = "link";
      }
    }
    if (nodetype === 1) {
      if (e.target.value && cfg.dragtext && cfg.draginput) {
        cfg.dragType = "dt2n";
        // cfg.dragType = "text";
      } else if (e.target.href) {
        if (window.getSelection().toString() == "" || e.target.textContent.length > window.getSelection().toString().lenght) {
          if (cfg.draglink) {
            cfg.dragType = "dl2n";
            // cfg.dragType = "link";
          }
        } else {
          if (cfg.dragtext) {
            cfg.dragType = "dt2n";
            // cfg.dragType = "text";
          }
        }
        if (!cfg.dragtext && cfg.draglink) {
          cfg.dragType = "dl2n";
          // cfg.dragType = "link";
        }
      } else if (e.target.src) {
        if (e.target.parentNode.href) {
          if (cfg.dragimage && (e[cfg.imgfirst + "Key"] || cfg.imgfirstcheck)) {
            cfg.dragType = "di2n";
            // cfg.dragType = "image";
          } else if (cfg.draglink) {
            cfg.dragType = "dl2n";
            // cfg.dragType = "link";
            e = e.target.parentNode;
          }

        } else if (cfg.dragimage) {
          cfg.dragType = "di2n";
          // cfg.dragType = "image";
        }
      }

    }


    if (!cfg.dragType) {
      flag.isDrag = false;
      return;
    }
    dObj.text = window.getSelection().toString() || e.target.innerHTML;
    dObj.link = e.href || e.target.href;
    dObj.img = e.target.src;
    if (cfg.setdragurl && cfg.dragType == "dt2n") {
      var tolink;
      if (dObj.text.indexOf("http://") != 0 && dObj.text.indexOf("https://") != 0 && dObj.text.indexOf("ftp://") != 0 && dObj.text.indexOf("rtsp://") != 0 && dObj.text.indexOf("mms://") != 0 && dObj.text.indexOf("chrome-extension://") != 0 && dObj.text.indexOf("chrome://") != 0) {
        tolink = "http://" + dObj.text;
      } else {
        tolink = dObj.text;
      }
      var urlreg = /^((chrome|chrome-extension|ftp|http(s)?):\/\/)([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/;
      if (urlreg.test(tolink)) {
        cfg.dragType = "dl2n";
        dObj.link = tolink;
      }
    }
    //========== crxID:jlgkpaicikihijadgifklkbpdajbkhjo END===========
    return dObj;
  }

  //when close a tab, save it's url, in order to reopen it: reopenTab
  window.addEventListener('unload', function() {
    GM_setValue('latestTab', window.location.href);
  }, false);
  //used in func: closeOtherTabs
  if(!GM_getValue('closeAll','')) GM_setValue('closeAll', Date());
  GM_addValueChangeListener('closeAll',function(name, old_value, new_value, remote){if(remote)window.close();});
  //update all tabs MG's config
  if(!GM_getValue('configChanged','')) GM_setValue('configChanged', Date());
  GM_addValueChangeListener('configChanged',function(name, old_value, new_value, remote){
    if(remote) cfg = GM_getValue('cfg', _cfg);
    createCanvaTips();
  });

  //========== Setting UI
  let makeSettingUi = function(){
    let CSS = `
      #MPsetting{z-index:999997!important;background:white!important;width:100%!important;height:100%!important;font-family:"微软雅黑"!important;position:fixed!important;top:0!important;left:0!important;}
      #MPmenu *,
      .MPcontent *{border-radius:5px!important;font-size:16px!important;}
      #MPlogo{background:white!important;box-shadow:inset 0 0 25px 15px yellowgreen!important;width:80px!important;height:80px!important;padding:0 10px 30px 10px!important;display:block!important;font-size:80px!important;color:cyan!important;text-shadow:6px 5px 15px black!important;}
      #MPmenu{z-index:999999!important;height:100%!important;width:100px!important;background:yellowgreen!important;color:white!important;text-align:center!important;}
      #MPmenu li{list-style-type:none!important;border-top:1px dashed white!important;margin:10px 15px!important;}
      .MPselected{box-shadow:inset 2px 2px 1px 4px rgba(16,12,12,0.6)!important;}
      #MPmenu li:hover{background:#05FDE7!important;color:#FF841D!important;}
      #MPmenu li span{display:block!important;width:40px!important;height:40px!important;font-size:35px!important;font-weight:bold!important;padding:0 15px!important;}
      #MPmenu b{display:block!important;width:70px!important;text-align:center!important;margin-top:10px!important;}
      .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;}
      .MPcontent h1,
      #FunsList legend{display:block!important;width:800px!important;font-size:30px!important;float:left!important;top:0!important;left:90px!important;padding:5px 12px!important;margin:0 10px!important;border-left:5px solid yellowgreen!important;background:#9acd3259!important;}
      .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;}
      .MPcontent > li:hover{box-shadow:inset 1px 1px 1px 3px #9acd32de!important;}
      .MPcontent >li span:nth-child(2){background:#00000010!important;text-align:left!important;padding:4px 10px!important;height:20px!important;width:auto!important;float:left!important;}
      .MPcontent >li span:nth-child(3){max-height:28px!important;float:right!important;}
      .MPcontent input[type="text"]{width:250px!important;height:26px!important;margin:0 10px!important;text-align:center!important;border:0!important;background:#0000000C!important;font-size:20px!important;}
      .MPcontent input[type="checkbox"]{width:0!important;}
      .MPcontent select{width:100%!important;height:100%!important;}
      #FunsList{width:800px!important;border:0!important;overflow:hidden!important;}
      .FunsListHide{height:40px!important;}
      .FunsListShow{height:auto!important;}
      #FunsList>li{display:inline-block!important;width:300px!important;height:30px!important;margin:5px!important;text-align:left!important;}
      span.tag{margin:2px 7px!important;padding:0!important;border:0!important;font-size:11px!important;white-space:nowrap!important;font-weight:bold!important;}
      span.tag span:first-child{color:white!important;background:#555!important;margin:0!important;padding:3px 3px 3px 7px!important;border:0!important;border-radius:4px 0 0 4px!important;}
      span.tag span:last-child{color:white!important;margin:0!important;border:0!important;padding:3px 7px 3px 3px!important;border-radius:0 4px 4px 0!important;}
      span.tag.yellow span:last-child{background:#FFB400!important;}
      span.tag.blue span:last-child{background:#1182C2!important;}
      span.tag.green span:last-child{background:#4DC71F!important;}
      span.tag.darkcyan span:last-child{background:#4DB798!important;}
      .MPcontent > li[data-type=t2n] span:first-child{background:#FFB40030!important;color:#FFB400!important;}
      .MPcontent > li[data-type=dt2n] span:first-child{background:#4DC71F30!important;color:#4DC71F!important;}
      .MPcontent > li[data-type=dl2n] span:first-child{background:#1182C230!important;color:#1182C2!important;}
      .MPcontent > li[data-type=di2n] span:first-child{background:#4DB79830!important;color:#4DB798!important;}
      .MPcontent > li span:first-child{text-align:left!important;font-size:18px!important;font-weight:bold!important;padding:2px 10px!important;width:auto!important;height:24px!important;float:left!important;border-left:10px solid!important;margin-right:20px!important;}
      #mg2>li>span{margin-bottom:10px!important;}
      #mg2>li>span:nth-child(3)>input {font-family: MParrow;}
      #mg2 > li span:nth-child(5),
      .MPcontent > li span:nth-child(6),
      .MPcontent > li span:nth-child(7){max-height:30px!important;margin-bottom:100px!important;white-space:nowrap!important;}
      .MPcontent > li span:nth-child(5) select{width:auto!important;height:26px!important;}

      /*label 作为开关*/
      label.switchOn{background:#4dc71f20!important;display:inline-block!important;color:#4DC71F!important;font-weight:bolder!important;min-width:40px!important;height:24px!important;padding:2px 5px!important;border-left:15px solid #4DC71F!important;border-radius:5px!important;}
      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;}
      input[type=checkbox].switch{width:0px!important;}
    `;
    let span = '', isOn = '', isChecked = '', settingDiv, settingParent,
      //菜单栏HTML
      txt = `<div id="MPmenu"><span id="MPlogo">☈</span><li data-target="mg1"><span>◧</span><b>Config</b></li><li data-target="mg2"><span>↯</span><b>Gesture</b></li><li data-target="mg3"><span>❓</span><b>About</b></li><li id="close"><span>?</span><b>Close</b></li></div>`;
    let setting = {
      mg1Start:         {eletype: '1',  id: 'mg1'},
      mg1title1:        {eletype: '2'},
      maxLineWidth:     {type: 'input',    name: 'maxLineWidth',     more: 'num'},
      lineGrowth:       {type: 'input',    name: 'lineGrowth',       more: 'num'},
      fontSize:         {type: 'input',    name: 'fontSize',         more: ''},
      lineColor:        {type: 'input',    name: 'lineColor',        more: 'color'},
      funNotDefine:     {type: 'input',    name: 'funNotDefine',     more: ''},
      language:         {type: 'input',    name: 'language',         more: 'num'},
      sensitivity:      {type: 'input',    name: 'sensitivity',      more: 'num'},
      tipsBackground:   {type: 'input',    name: 'tipsBackground',   more: 'color'},
      translateTimeout: {type: 'input',    name: 'translateTimeout', more: ''},
      mg1title2:        {eletype: '2'},
      dragtext:         {type: 'checkbox', name: 'dragtext',         more: ''},
      draginput:        {type: 'checkbox', name: 'draginput',        more: ''},
      draglink:         {type: 'checkbox', name: 'draglink',         more: ''},
      dragimage:        {type: 'checkbox', name: 'dragimage',        more: ''},
      //imgfirst:       {imgfirstcheck: {type: 'checkbox', name: 'imgfirstcheck', more: ''},
      setdragurl:       {type: 'checkbox', name: 'setdragurl',       more: ''},
      mg1end:           {eletype: '3'}
    };
    let selectobjs = {
      //languages
      translateTo: {"Afrikaans":"af","Haitian Creole":"ht","Querétaro Otomi":"otq","Arabic":"ar","Hebrew":"he","Romanian":"ro","Bangla":"bn","Hindi":"hi","Russian":"ru","Bosnian (Latin)":"bs-Latn","Hmong Daw":"mww","Samoan":"sm","Bulgarian":"bg","Hungarian":"hu","Serbian (Cyrillic)":"sr-Cyrl","Cantonese (Traditional)":"yue","Indonesian":"id","Serbian (Latin)":"sr-Latn","Catalan":"ca","Italian":"it","Slovak":"sk","Chinese Simplified":"zh-CHS","Japanese":"ja","Slovenian":"sl","Chinese Traditional":"zh-CHT","Kiswahili":"sw","Spanish":"es","Croatian":"hr","Klingon":"tlh","Swedish":"sv","Czech":"cs","Korean":"ko","Tahitian":"ty","Danish":"da","Latvian":"lv","Tamil":"ta","Dutch":"nl","Lithuanian":"lt","Thai":"th","English":"en","Malagasy":"mg","Tongan":"to","Estonian":"et","Malay":"ms","Turkish":"tr","Fijian":"fj","Maltese":"mt","Ukrainian":"uk","Filipino":"fil","Norwegian Bokmål":"no","Urdu":"ur","Finnish":"fi","Persian":"fa","Vietnamese":"vi","French":"fr","Polish":"pl","Welsh":"cy","German":"de","Portuguese":"pt","Yucatec Maya":"yua","Greek":"el"},
      imgSearchEnging: {    // image searching
        BaiduImage:  "https://image.baidu.com/n/pc_search?queryImageUrl=%URL&uptype=urlsearch",
        GoogleImage: "https://www.google.com/searchbyimage?image_url=%URL",
        TinEye:      "http://www.tineye.com/search?url=%URL"
      },
      searchEnging: {       // text searching
        google:  "http://www.google.com/search?q=",
        baidu:   "http://www.baidu.com/s?wd=",
        yandex:  "http://www.yandex.com/yandsearch?text=",
        Bing:    "http://www.bing.com/search?q=",
        yahoo:   "http://search.yahoo.com/search?p=",
        wiki:    "http://en.wikipedia.org/w/index.php?search=",
        taobao:  "http://s.taobao.com/search?q=",
        amazon:  "http://www.amazon.com/s/&field-keywords=",
        sogou:   "https://www.sogou.com/web?query=",
        s360:    "http://www.haosou.com/s?q="
      },
      vipAPI:{
        疯狂:    "http://goudidiao.com/?url=",
        噗噗:    "http://pupudy.com/play?make=url&id="
      }
    };
    let local = {
      arg: {
        searchText:{
          description:[['搜索引擎', '后台打开', '右边插入'], ['SearchingEnging', 'Load In Background', 'Insert After Current Tab']],
          arg:['select:searchEnging', 'checkbox', 'checkbox']
        },
        searchImg:{
          description:[['图片搜索引擎', '后台打开', '右边插入'], ['Image SearchingEnging', 'Load In Background', 'Insert After Current Tab']],
          arg:['select:imgSearchEnging', 'checkbox', 'checkbox']
        },
        translate:{
          description:[['目标语言'], ['Translate To']],
          arg:['select:translateTo']
        },
        fkVip:{
          description:[['视频解析接口'], ['Videos Parser API']],
          arg:['select:vipAPI']
        }
      },
      FunsListTitle: {
        t2n: ['手势', 'Gesture'],
        dt2n: ['拖拽文本', 'Drag Text'],
        dl2n: ['拖拽链接', 'Drag Link'],
        di2n: ['拖拽图片', 'Drag Image']
      },
      tips: ['说明', 'Description'],
      addFunction: ['增加一个功能', 'Add Function'],
      //setting prefix: SET => SET + functionName + Item
      mg1title1ITEM:       ['界面',                           'UI'],
      maxLineWidthITEM:    ['轨迹宽度',                       'Line Width'],
      maxLineWidthDESC:    ['鼠标轨迹最大宽度,单位"px"',      'Mouse Track Max. Line Width'],
      lineGrowthITEM:      ['轨迹增长',                       'Line Grow'],
      lineGrowthDESC:      ['轨迹增长速度,单位"px"',          'Track Growing Speed, Unit "px"'],
      fontSizeITEM:        ['提示字体大小',                   'Tips Font Size'],
      fontSizeDESC:        ['功能提示字体的大小,单位"px"',    'Function Tips Font Size, Unit "px"'],
      lineColorITEM:       ['轨迹颜色',                       'Line Color'],
      lineColorDESC:       ['3|6|8位16进制值,如 0f0 ,00ff00, 00ff0080','3|6|8 Hexadecimal Value, eg. 0f0,00ff00,00ff0080'],
      funNotDefineITEM:    ['未定义提示',                     'Not Define Tips'],
      funNotDefineDESC:    ['手势或者功能未定义时的提示信息', 'Undefined Function Tips'],
      languageITEM:        ['语言',                           'Language'],
      languageDESC:        ['0 表示中文 1 表示英语',          '0 for Chinese, 1 for English'],
      sensitivityITEM:     ['识别距离',                       'Sensitivigy'],
      sensitivityDESC:     ['方向变化计算距离',               'Min Direction Change Distance'],
      tipsBackgroundITEM:  ['提示文字背景颜色',               'Tis Background Color'],
      tipsBackgroundDESC:  ['提示文字的背景颜色',             'Tips Background Color'],
      vipApiITEM:          ['破解视频接口',                   'Parse Video API'],
      vipApiDESC:          ['VIP视频及杰解析接口',            'VIP Videos Parser API'],
      translateTimeoutITEM:['等待时间',                       'Timeout'],
      translateTimeoutDESC:['翻译等待时间,超时作废',          'Translation Timeout'],
      mg1title2ITEM:       ['设定',                           'Setting'],
      dragtextITEM:        ['启用拖拽文字',                   'Enable Drag Text'],
      dragtextDESC:        ['选中文字并且拖拽时候的功能',     'Enable Drag Text'],
      draginputITEM:       ['启用拖拽文本框文字',             'Enable Drag Text-in-Inputbox'],
      draginputDESC:       ['文本框中选中文字并且拖拽时候,使用拖拽的功能','Enable Drag Text-in-Inputbox'],
      draglinkITEM:        ['启用拖拽链接',                   'Enable Drag Link'],
      draglinkDESC:        ['拖拽链接时候的功能',             'Enable Drag Link'],
      dragimageITEM:       ['启用拖拽图片',                   'Enable Drag Image'],
      dragimageDESC:       ['拖拽图片时候的功能',             'Enable Drag Image'],
      imgfirstcheckITEM:   ['图片链接识别为图片',             'Drag ImageLink as Drag Image'],
      imgfirstcheckDESC:   ['拖拽图片链接时候,识别为拖拽图片的功能','Drag Image-Link, Treat as Drag Image'],
      setdragurlITEM:      ['拖拽文本链接',                   'Drag LinkText as Drag Link'],
      setdragurlDESC:      ['拖拽文本为链接时候,识别为拖拽链接','Drag Link-Text, Treat as Drag Link']
    };
    let arg2html = function(argument, type, trk){
      let html ="", argu, i,rand, trackTxt, name, argValue = [], agrDetail = [], description;
      typeof argument === "object" ? argu = argument : argu = JSON.parse(argument);
      trackTxt = trk || '';
      name = argu.name;
      html += `<span>${name}</span><span>${fn[type][name][cfg.language]}</span><span><input type="text" name="${name}" value="${trackTxt}" data-mark="${type}"></span><br/>`;
      if(argu.arg.length > 0){
        argValue = trackTxt ? argu.arg : [];
        agrDetail = local.arg[name].arg;
        description = local.arg[name].description[cfg.language];
        for(i in agrDetail){
          rand = Math.floor(Math.random()*1000);
          switch (agrDetail[i].slice(0,5)) {
            case 'input':
              html += '<span><input type="text"></span>';
              break;
            case 'check':
              html += `<span><input type="checkbox" id="${name + rand}" value=${argValue[i] || false} ${argValue[i] ? "checked" : ''} class="switch"><label for="${name + rand}" ${argValue[i] ? 'class="switchOn"' : 'class="switchOff"'}>${description[i]}</label></span>`;
              break;
            case 'selec':
              selectName = agrDetail[i].split(':').pop();
              html += `<span><input type="text" value=${argValue[i] || ''}><select>`;
              for (let k in selectobjs[selectName]){
                html += `<option value=${selectobjs[selectName][k]}>${k}</option>`;
              }
              html += '</select></span>';
              break;
            default:
               html = `<span style="visibility:hidden;"><span></span></span>`;
              break;
          }
        }
      }
      return html;
    },
    makeFunsList = function(){
      let html = '',i=0,j,hasArgument,item2,arg,color=['yellow', 'green', 'blue', 'darkcyan'];
      ['t2n','dt2n','dl2n','di2n'].forEach((item1) => {
        for( item2 in fn[item1]){
          local.arg.hasOwnProperty(item2) ? arg = Object.assign({name:item2},local.arg[item2]) : arg = {name:item2,arg:[]};
          html +=`
          <li  data-arg='${JSON.stringify(arg)}' data-type="${item1}" title="${fn[item1][item2][cfg.language]}"><span class="tag ${color[i]}"><span>${local.FunsListTitle[item1][cfg.language]}</span><span>${item2}</span></span></li>
          `;
        }
        i += 1;
      });
      html = `<fieldset id="FunsList" class="FunsListHide"><h1>${local.addFunction[cfg.language]} ➕ </h1><br/>${html}</fieldset>`;

      return html;
    },
    makeDefinedFunsList = function(type){
      let i, html ='';
       for(i in cfg[type]){
        html += `<li data-arg='${JSON.stringify(cfg[type][i])}' data-type='${type}'>${arg2html(cfg[type][i], type, i)}`;
      }
       return html;
    },
    clickToMakeEle = function(){
      let tarEle = event.target.tagName === 'LI' ? event.target : (event.target.parentNode.tagName === "LI" ? event.target.parentNode : event.target.parentNode.parentNode);
      let ele = document.createElement('li');
      ele.setAttribute('data-arg', tarEle.dataset.arg);
      ele.setAttribute('data-type', tarEle.dataset.type);
      ele.innerHTML = arg2html(tarEle.dataset.arg, tarEle.dataset.type);
      document.getElementById('mg2').insertBefore(ele, document.querySelector(`#mg2>li`));
      try {
        if(ele.children[4]) ele.children[4].children[1].addEventListener('change', formChange, false);
        if(ele.children[5]) {
          ele.children[5].firstElementChild.addEventListener('change', formChange, false);
          ele.children[5].firstElementChild.addEventListener('change', onOff, false);
        }
        if(ele.children[6]) {
          ele.children[6].firstElementChild.addEventListener('change', formChange, false);
          ele.children[6].firstElementChild.addEventListener('change', onOff, false);
        }
      } catch(e) {
      }
      //轨迹框 失去焦点 更新设置
      ele.children[2].firstElementChild.addEventListener('blur', updateFns, false);
      ele.children[2].firstElementChild.addEventListener('keyup', function(event) {
        event.target.value = letter2arrow(event.target.value);
      }, false);
      //函数列表收缩, 回滚到顶部
      toggleFunsList();
      document.documentElement.scrollTo(0, 0);
    },
    updateFns = function(){
      var typeObject = {},
      tarEle = event.target;
      tarEle.tagName === "LI" ? null : (tarEle.parentNode.tagName === "LI" ? tarEle = tarEle.parentNode : tarEle = tarEle.parentNode.parentNode);
      [].forEach.call(document.querySelectorAll(`#mg2>li[data-type=${tarEle.dataset.type}]`), function(element, index) {
        updateItem(element);
      });
      function updateItem(item){
        let childrens, trk, argValue=[], name, dataArgObject;
        trk = item.children[2].firstElementChild.value;
        //if mouse track is not empty , update Fns
        if(trk !== ''){
          childrens = item.children;
          dataArgObject = JSON.parse(item.dataset.arg);
          if(childrens[4]) {
            if(childrens[4].firstElementChild.value && childrens[4].firstElementChild.value !== "undefined"){
              argValue[0] = childrens[4].firstElementChild.value;
            } else{
              argValue[0] = '';
            }
          }
          if(childrens[5]) {
            if(childrens[5].firstElementChild.value && childrens[5].firstElementChild.value !== "undefined"){
              argValue[1] = childrens[5].firstElementChild.value;
            } else{
              argValue[1] = '';
            }
          }
          if(childrens[6]) {
            if(childrens[6].firstElementChild.value && childrens[6].firstElementChild.value !== "undefined"){
              argValue[2] = childrens[6].firstElementChild.value;
            } else{
              argValue[2] = '';
            }
          }
          typeObject[trk] = {name: dataArgObject.name, arg: argValue};
        }

      }
      cfg[tarEle.dataset.type] = typeObject;
      GM_setValue('cfg', cfg);
      GM_setValue('configChanged', Date());
    },
    updateCfgUsr = function(e){
      switch (e.target.dataset.mark) {
        case 'color':
          cfg[e.target.name] = e.target.value;
          e.target.setAttribute('style', `background: #${e.target.value} !important;`);
          break;
        case 'num':
          let b;
          switch (e.target.name) {
            case 'language':
              b = (e.target.value == 1 || e.target.value == 0) ? e.target.value : cfg[e.target.name];
              break;
            case 'sensitivity':
            case 'fontSize':
              b = parseInt(e.target.value);
              break;
            default:
              b = parseFloat(parseFloat(e.target.value).toFixed(2));
              break;
          }
          cfg[e.target.name] = b;
          break;
        case 'select':
        case 'normal':
          cfg[e.target.name] = e.target.value;
          break;
        default:
          // cfg[e.target.id] = updateFns(`input[data-mark="${e.target.dataset.mark}"]`);
          break;
      }
      GM_setValue('cfg', cfg);
      GM_setValue('configChanged', Date());
    },
    formChange = function(){
      if(event.target.type === 'checkbox'){
        event.target.value = event.target.checked;
        updateFns();
      }
      if(event.target.tagName === 'SELECT'){
        event.target.previousElementSibling.value = event.target.value;
        updateFns();
      }
    },
    letter2arrow = function(str){
      return str.replace(/[^uUdDlLrR4682]/g, '').replace(/[lL]/g, '4').replace(/[rR]/g, '6').replace(/[dD]/g, '8').replace(/[uU]/g, '2');
    },
    onOff = function(e) {
      cfg[e.target.id] = e.target.checked;
      if (cfg[e.target.id]) {
        e.target.nextElementSibling.setAttribute('class', 'switchOn');
      } else {
        e.target.nextElementSibling.setAttribute('class', 'switchOff');
      }
      //GM***
    },
    toggleFunsList = function(){
      let a = document.getElementById('FunsList');
      if(a.getAttribute('class') === "FunsListHide"){
        a.setAttribute('class', 'FunsListShow');
      }else{
        a.setAttribute('class', 'FunsListHide');
      }
    },
    selected = function(e) {
      let tar;
      if (e.target.tagName === "LI") {
        tar = e.target;
      } else {
        tar = e.target.parentNode;
      }
      [].forEach.call(document.querySelectorAll('#MPmenu li'), function(item) {
        item.setAttribute('class', '');
      });
      tar.setAttribute('class', 'MPselected');
      [].forEach.call(document.querySelectorAll('.MPcontent'), function(item) {
        item.style.display = "none";
      });
      document.getElementById(tar.dataset.target).setAttribute('style', 'display:block;');
    };

    GM_addStyle(CSS);
    //#mg1 config
    for (let i in setting) {
      if (setting[i].eletype) {
        switch (setting[i].eletype) {
          case '1':
            txt += `<div id="${setting[i].id}" class="MPcontent">`;
            break;
          case '2':
            txt += `<h1>${local[i+'ITEM'][cfg.language]}</h1>`;
            break;
          case 1:
            txt += `<div id="${setting[i].id}" class="MPcontent">`;
            break;
          default:
            txt += `</div>`;
            break;
        }
      } else {
        if (setting[i].type === 'input') {
          if (setting[i].more === 'color') {
            span = `<input type="text" name="${setting[i].name}" value="${cfg[setting[i].name]}" style="background:#${cfg[setting[i].name]};"  data-mark="color">`;
          } else if (setting[i].more === 'num') {
            span = `<input type="text" name="${setting[i].name}" value="${cfg[setting[i].name]}" data-mark="num">`;
          } else {
            span = `<input type="text" name="${setting[i].name}" value="${cfg[setting[i].name]}" data-mark="normal">`;
          }
        } else {
          isChecked = cfg[setting[i].name] ? 'checked' : '';
          isOn = cfg[setting[i].name] ? 'class="switchOn"' : 'class="switchOff"';
          span = `<input type="checkbox" id="${setting[i].name}" name="${setting[i].name}" ${isChecked} class="switch"><label for="${setting[i].name}" ${isOn}></label>`;

        }
        txt += `<li><span>${local[i+'ITEM'][cfg.language]}</span><span title='${local[i+'DESC'][cfg.language]}'>${local.tips[cfg.language]}</span><span>${span}</span></li>`;
      }
    }

    //#mg2 Defined FunsList htms Gesture/Darg funcs
    txt +='<div id="mg2" class="MPcontent">';
    txt += makeFunsList();    //#mg2 FunsList html
    txt += makeDefinedFunsList('t2n');
    txt += makeDefinedFunsList('dt2n');
    txt += makeDefinedFunsList('dl2n');
    txt += makeDefinedFunsList('di2n');
    txt += '</div>';  //#mg2 end
    //#mg3
    txt += '<div id="mg3" class="MPcontent"><a href="https://github.com/woolition/greasyforks/blob/master/mouseGesture/HY-MouseGesture.md" style="display:block;width: 90%;height: auto;font-family:MParrow;font-size: 40px!important;text-decoration: none;font-weight: bolder;padding: 30px 30px; color:yellowgreen;">手势输入:<br>u or U: 2<br>r or R: 6<br> d or D: 8<br> l or L: 4<br><br>(● ̄(エ) ̄●)づ <br>点我看更多介绍! </a></div>';

    settingDiv = document.createElement('div');
    settingDiv.id = "MPsetting";
    settingDiv.innerHTML = txt;
    settingParent = document.body || document.documentElement;
    settingParent.appendChild(settingDiv);

    [document.querySelectorAll('#MPmenu li')[0],document.querySelectorAll('#MPmenu li')[1],document.querySelectorAll('#MPmenu li')[2]].forEach(function(item) {
      item.addEventListener('click', selected, false);
    });
    [].forEach.call(document.querySelectorAll('#mg1 input[type=text]'), function(item) {
      item.addEventListener('blur', updateCfgUsr, false);
    });
    [].forEach.call(document.querySelectorAll('#mg1 input[type=checkbox], #mg2 input[type=checkbox]'), function(item) {
      item.addEventListener('change', onOff, false);
      if(item.parentNode.parentNode.parentNode.id === 'mg1'){
        item.addEventListener('change',updateCfgUsr,false);
      }
    });
    [].forEach.call(document.querySelectorAll('#FunsList li'),(item)=>{
      item.addEventListener('click', clickToMakeEle, false);
    });
    [].forEach.call(document.querySelectorAll('#mg2 input[type=text]'), function(item) {
      item.addEventListener('blur', updateFns, false);
    });
    [].forEach.call(document.querySelectorAll('#mg2 select, #mg2 input[type=checkbox]'), function(item) {
      item.addEventListener('change', formChange, false);
    });
    [].forEach.call(document.querySelectorAll('#mg2>li'), function(item) {
      item.children[2].firstElementChild.addEventListener('keyup', function(event) {
        let a = event.target.value;
        a = letter2arrow(a);
        if(a.charAt(a.length -1) === a.charAt(a.length-2)) a = a.slice(0,-1);
        event.target.value = a;
      }, false);
    });
    //init
    [].forEach.call(document.querySelectorAll('.MPcontent'), function(item) {
      item.style.display = "none";
    });
    document.querySelector('#FunsList h1').addEventListener('click', toggleFunsList, false);
    document.getElementById('mg1').style.display = 'block';
    document.getElementById('close').addEventListener('click', function(e) {
      try {
        document.documentElement.removeChild(document.getElementById("MPsetting"));
      } catch(event) {
        document.body.removeChild(document.getElementById("MPsetting"));
      }

    }, false);
  };
  // return;

})();