Greasy Fork

Greasy Fork is available in English.

Sanskrit Tools - Toolbar

Sanskrit Language Tools - Quick access to Sanskrit dictionary, thesarus, news and other tools, on Firefox and Chrome browsers.

当前为 2021-09-19 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name           Sanskrit Tools - Toolbar
// @namespace      stgeorge
// @description    Sanskrit Language Tools - Quick access to Sanskrit dictionary, thesarus, news and other tools, on Firefox and Chrome browsers.
// @require        http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @match          *://*/*
// @version        3.4.13
// ==/UserScript==


(function() {
  let $j = jQuery.noConflict();
  // ====================================================================
  // Options. Modify as needed.
  // TODO: Expose these options via GM. Some day ...

  let OPTION_DEBUG = false;

  // When on spokensanskrit.org site, Set to true to change word completion list
  // to show up below the input field instead of on the side.
  let OPTION_IN_PLACE_MATCH = true;

  // Remove extraneous elements.
  let OPTION_TRIM = true;

  // End options. Don't change anything below this.
  // ====================================================================
  
  // Grammar stuff.

  let SANSKRIT_SITE_OLD = 'spokensanskrit.org';
  let SANSKRIT_SITE_NEW = 'learnsanskrit.cc';
  let SANSKRIT_SITES = [SANSKRIT_SITE_OLD,SANSKRIT_SITE_NEW];

  let verbMatch = /(verb)\s*(.*)/;
  let verbRootMatch = /{\s*(.*)\s*}/;
  let verbClassMatch = /\s*([0-9]+)\s*/g;
  let nounMatch = /\b([fmn](?=\.))/g;
  let nounRootMatch = /^\s*(.*)\s*$/;
  let vurl = 'http://sanskrit.inria.fr/cgi-bin/SKT/sktconjug.cgi?lex=SH&q=%Q%&t=KH&c=%C%&font=deva';
  let nurl = 'http://sanskrit.inria.fr/cgi-bin/SKT/sktdeclin.cgi?lex=SH&q=%Q%&t=KH&g=%G%&font=deva';
  let genders = { f: 'Fem', n: 'Neu', m: 'Mas' };
  let gender_names = { f: 'feminine', n: 'neuter', m: 'masculine' };

  let dictTable = null;
  let dictTableRows = null;
  let dictTableRowsSorted = null;

  let tableSorted = false;

  function isDictionarySite() {
    for (let i = 0; i < SANSKRIT_SITES.length; ++i) {
      let s = SANSKRIT_SITES[i];
      if (document.URL.indexOf(s) != -1)
        return true;
    }
  }

  function isGrammarSite() {
    return (document.URL.indexOf('sanskrit.inria.fr') != -1);
  }

  function buildGrammarUI() {
    if (OPTION_TRIM)
      trimFat();
    fixSuggestBox();
    addGrammarLinks();
  }

  function trimFat() {
    $j('.table0').not('.bgcolor2').not('.bgcolor0').remove();
  }

  function fixSuggestBox() {
    let ans = $j('#answer2');
    if (OPTION_IN_PLACE_MATCH) {
      let target = $j('input[name="tran_input"]').closest('form');
      ans.detach();
      target.after(ans);
      ans.attr('align', 'center');
      ans.css({'position':'relative', 'top':'-12em'});
    }
    observe(ans);
  }

  function observe(ele) {
    let observer = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        let newNodes = mutation.addedNodes;
        if(newNodes !== null) {
          $j(newNodes).each(function() {
            if (this.nodeName == 'BR')
              $j(this).remove();
          });
        }
      });    
    });
    observer.observe(ele[0], { 
      attributes: true, 
      childList: true, 
      characterData: true 
    });
  }

  function initSorted() {
    if (dictTable === null) {
      dictTable = $j('tr.bgcolor2').first().closest('table');
      dictTableRows = dictTable.find('tbody >tr:has(td)').get();
      dictTableRowsSorted = $j.extend([], dictTableRows);
      dictTableRowsSorted.sort(function(a, b) {
        let val1 = $j(a).children('td').first().text();
        let val2 = $j(b).children('td').first().text();
        return val1.localeCompare(val2);
      });
    }
  }

  function sortTable() {
    let rows = tableSorted ? dictTableRows : dictTableRowsSorted;
    let tb = dictTable.children('tbody').first();
    tb.empty();
    $j.each(rows, function(index, row) {
      tb.append(row);
    });
    tableSorted = !tableSorted;
  }

  function addGrammarLinks() {
    let line = 1;
    $j('tr.bgcolor2,tr.bgcolor0,tr.highlight').each(function() {
      let row = $j(this);
      // Each row is of the form:
      // sans_text grammar_info translit_text meaning
      let col = row.children().first(); let sansText = col.text().trim();
      col = col.next(); let grammarInfo = col.text().trim();
      col = col.next(); let transText = col.text().trim();
      _debug("line " + (line++) + "='" + sansText + "' '" + grammarInfo + "' '" + transText + "'");
      let links = [];
      if (matchVerb(sansText, grammarInfo, transText, links) || matchNoun(sansText, grammarInfo, transText, links)) {
        makeURLs(row, links);
      }
      _debug('-----');
    });
  }

  function matchVerb(sansText, grammarInfo, transText, links) {
    // Grammar is of the form: verb N 
    let a = grammarInfo.match(verbMatch);
    if (a && a[1] == 'verb') {
      // transText is of the form xlit_word (xlit_root).
      // We want the root.
      let b = transText.match(verbRootMatch);
      if (!b || !b[1]) return false;
      b[1] = b[1].trim().replace(/[\s-]/g, "")
      _debug('verb: matching ' + transText + ' with verbroot');
      if (b[1].match(/[^A-Za-z]/)) return false;
      let n;
      // For verbs, see if grammar_info has the gaNA info.
      if (a[2])
        n = a[2].trim().match(verbClassMatch);
      if (!(n && n[0])) {
        return false;
      }
      // At this point, b[1] is the transliterated verb root,
      // sansText is the devangari verb root, and n the gaNa.
      _debug('verb=' + b[1]);
      _debug('ganas=' + n);
      for (let i = 0; i < n.length; ++i) {
        links.push({
          tooltip: 'Inflections for ' + a[1] + '(' + n[i].trim() + ') ' + sansText,
          url: vurl.replace('%Q%', b[1]).replace('%C%', n[i].trim()),
          sym: '&rtrif;',
          target: 'l_grammar',
        });
      }
      return true;
    }
    return false;
  }

  function matchNoun(sansText, grammarInfo, transText, links) {
    // grammar, in turn, is of the forms: m./f./n./adj. etc (for nouns)
    _debug('noun: matching ' + grammarInfo + ' with noun');
    let a = grammarInfo.match(nounMatch);
    if (!(a && a[0])) return false;
    _debug('noun: matching ' + transText + ' with nounroot');
    let b = transText.match(nounRootMatch);
    if (!b || !b[1]) return false;
    b[1] = b[1].trim();
    if (b[1].match(/[^A-Za-z]/)) return false;
    // At this point, b[1] is the xlit noun, sansText is the
    // devanagari noun, and a is one or more lingas.
    _debug('noun=' + b[1]);
    _debug('lingams=' + a);
    if (a.length > 0) {
      for (let i = 0; i < a.length; ++i) {
        links.push({
          url: nurl.replace('%Q%', b[1]).replace('%G%', genders[a[i]]),
          tooltip: 'Inflections for ' + gender_names[a[i]] + ' noun ' + sansText,
          sym: '&rtrif;',
          target: 'l_grammar',
        });
      }
      return true;
    }
    return false;
  }

  function makeURLs(row, links) {
    let ltd = row.children().first();
    let html;
    html = '';
    for (let i in links) {
      l = links[i];
      ltd.attr('valign','top');
      html +=
        '<a data-id="' +i+
          '" target=_new class="def stil4" style="text-decoration:none;color: #96290e;font-weight:bold;" href="' +
          l.url + '" title="' + l.tooltip + '">'+l.sym+'</a>';
    }
    _debug("link: " + l.url + " --> " + l.tooltip);
    ltd.html(html + ' ' + ltd.html());
    ltd.attr('align', 'left');
    return true;
  }

  function fixGrammarStyles() {
    $j(['.bandeau','.cyan_cent','.deep_sky_cent']).each(function(k,v) {
      $j(v).css({'background':'#eeeeff'});
    });
    $j(['.chamois_back','.inflexion']).each(function(k,v) {
      $j(v).css({'background':'white'});
    });
    $j('.devared').css({'color':'black'});
    $j('.red').css({'color':'mediumblue'});
  }

  // ===============================================================
  // Toolbar stuff.
  // ===============================================================

  let IGNORES = [
    'mail.yahoo.com',
    'groups.yahoo.com',
    SANSKRIT_SITE_OLD,
    SANSKRIT_SITE_NEW,
  ];
  let ALLOW_ANCHORS = [
    'sanskrit.uohyd.ernet.in/cgi-bin/scl/SHMT/generate.cgi',
  ];

  let TOOLBAR_LINKS = [
    [ "vArtAvaliH", "https://www.youtube.com/playlist?list=PLxx0m3vtiqMZGmsUEVeTAuWIXqc9fTMHy", "l_news",
      "&#2357;&#2366;&#2352;&#2381;&#2340;&#2366;&#2357;&#2354;&#2367;&#2307;" ],
    [ "samprati vArtAH", "http://samprativartah.in/", "l_mag2",
      "&#2360;&#2350;&#2381;&#2346;&#2381;&#2352;&#2340;&#2367;&#2357;&#2366;&#2352;&#2381;&#2340;&#2366;&#2307;" ],
    [ "sudharmA", "http://epapersudharmasanskritdaily.in/", "l_mag3",
      "&#2360;&#2369;&#2343;&#2352;&#2381;&#2350;&#2366;" ],
    [ "sambhASaNa sandezaH", "http://www.sambhashanasandesha.in/", "l_mag1",
      "&#2360;&#2350;&#2381;&#2349;&#2366;&#2359;&#2339; &#2360;&#2344;&#2381;&#2342;&#2375;&#2358;&#2307;" ],
    [ "mAhezvarasUtrANi", "http://en.wikipedia.org/wiki/Siva_Sutra#Text", "l_msutra",
      "&#2350;&#2366;&#2361;&#2375;&#2358;&#2381;&#2357;&#2352;&#2360;&#2370;&#2340;&#2381;&#2352;&#2366;&#2339;&#2367;" ],
    [ "sandhiH", "http://sanskrit.jnu.ac.in/sandhi/viccheda.jsp", "l_sandhi",
      "&#2360;&#2344;&#2381;&#2343;&#2367;&#2307;" ],
    [ "Noun/Verb", "http://sanskrit.inria.fr/DICO/grammar.fr.html", "l_inria",
      "&#2358;&#2348;&#2381;&#2342;-/&#2343;&#2366;&#2340;&#2369;-&#2352;&#2370;&#2346;&#2366;&#2357;&#2354;&#2368;" ],
    [ "Books", "http://www.sanskrit.nic.in/ebooks.php", "l_books",
      "&#2346;&#2369;&#2360;&#2381;&#2340;&#2325;&#2366;&#2344;&#2367;" ],
    [ "Wikipedia", "http://sa.wikipedia.org", "l_wiki",
      "&#2357;&#2367;&#2325;&#2367;&#2346;&#2368;&#2337;&#2367;&#2351;&#2366;" ],
  ];

  let TOOLBAR_HTML = '\
    <table id="s_toolbar">\
      <tr>\
        %LINKS%\
        <td class="st_lastcol">\
          <div title="When enabled, double-clicking a word will automatically launch the dictionary" class="st_link st_common st_option">\
            <input type="checkbox" id="o_auto" class="st_link st_checkbox" title="When enabled, double-clicking a word will automatically launch the dictionary"/>\
            <label for="o_auto" class="st_link st_label">Auto-dictionary</label>\
          </div>\
        </td>\
      </tr>\
    </table>\
    <a id="a_dict" style="display:none" href="" target="l_dict"></a>\
  </div>';
  let ICON_HTML = '<div id="s_icon">\u0938</div>';
  let icon;
  let visible = {};
  let numClicks = 0;
  let vdiv = null;
  let allowAnchor = false;
  let selectedText = null;

  function isToolbarSupported() {
    for (let i in IGNORES) {
      if (document.URL.indexOf(IGNORES[i]) != -1) {
        return false;
      }
    }
    return true;
  }

  function initToolbarData() {
    for (let i in ALLOW_ANCHORS) {
      if (document.URL.indexOf(ALLOW_ANCHORS[i]) != -1) {
        allowAnchor = true;
        break;
      }
    }
  }

  function buildToolbarUI() {
    let link_html = '';
    for (let i in TOOLBAR_LINKS) {
      let link = TOOLBAR_LINKS[i];
        link_html +=
          '<td class="st_li">' +
            '<a class="st_common st_link" href="'+link[1]+'" target="'+link[2]+'">'+link[3]+'<br/>'+link[0]+'</a>'+
          '</td>'
    }
    place('s_toolbar', TOOLBAR_HTML.replace('%LINKS%', link_html), {
      fontFamily: 'sans-serif',
      position: 'fixed',
      'top': 0,
      margin: 0,
      width: '100%',
      zIndex: 2999999999,
      backgroundColor: 'white',
      'float': 'left',
      display:'none',
      lineHeight: '20px',
    });
    $j('.st_lastcol').css({
      backgroundColor: '#ffd',
      border: 'solid 1px #aaa',
      padding: 0
    });
    $j('.st_li').css({
      backgroundColor: '#ffd',
      padding: '0px',
      textAlign:'center',
      border: 'solid 1px #aaa',
      lineHeight: '1.5em'
    });
    $j('.st_space').css({
      marginLeft:'20px',
    });
    $j('.st_common').css({
      'float': 'left',
      border: 0,
      margin: 0,
      padding: 0,
      // fontFamily: '"Lucida Sans Unicode", "Lucida Grande", sans-serif',
      // fontSize: '10px',
      fontWeight: 'normal',
      verticalAlign:'middle',
      color: 'black'
    });
    $j('.st_link').css({
      textDecoration: 'none',
      marginLeft:'5px',
      padding:'2px',
      cursor: 'pointer'
    });
    $j('.st_label').css({
      marginLeft: '5px',
      verticalAlign: 'text-top'
    });
    $j('.st_option').css({
      display: 'inline-block',
      margin: '5px'
    });
    $j('.st_link').hover(function() {
      $j(this).css({color:'orange'});
    }, function() {
      $j(this).css({color:'black'});
    });
    $j('.st_checkbox').css({
      margin: '5px'
    });
    $j('.st_menutrigger').css({
      position: 'relative'
    });
    $j('.st_menu').css({
      backgroundColor:'#eee',
      display:'none',
      listStyle: 'none',
      position:'absolute',
      width:'120px',
      'top': '50px',
      boxShadow: '5px 5px 5px #888888',
      zIndex:'999',
    });
    $j('.st_menu li').css({
      width:'100px',
      listStyle: 'none inside',
    });
    $j('#o_auto').on('change', function(e) {
      setValue('auto', $j(this).prop('checked'));
    });
    $j('.st_menutrigger').on('click', function(e) {
      e.preventDefault();
      e.stopPropagation();
      let trigger = $j(this);
      let tgt = trigger.attr('data-menu');
      let v = visible[tgt];
      if (v)
        $j(tgt).css('display', 'none');
      else
        $j(tgt).css('display', 'block');
      visible[tgt] = !v;
    });
    $j(document).on('click', function(e) {
      $j('.st_menu').css('display', 'none');
      for (let i in visible) {
        visible[i] = false;
      }
    });
    document.addEventListener('mouseup', function(e) {
      let node = (e.target || e.srcElement);
      if (e.button != 0 || (node.nodeName == 'A' && !allowAnchor)
        || node.nodeName == 'INPUT') {
        return;
      }
      let n = node;
      while (n) {
        if (n == icon) {
          return;
        }
        if (n.getAttribute) {
          let ce = n.getAttribute('contenteditable');
          if (ce) {
            return;
          }
        }
        n = n.parentNode;
      }
      if (++numClicks == 1) {
        window.setTimeout(function() {
          selectedText = getSelectedText(true);
          if (selectedText != null && selectedText.length > 0) {
            if (selectedText.indexOf(' ') != -1) {
              selectedText = null;
              return;
            }
            if ($j('#o_auto').prop('checked')) {
              showDict(selectedText);
            }
          } else {
            hideDict();
          }
          numClicks = 0;
        }, 300);
      }
    }, false);

    if (getValue('status', 0))
      show();
  }

  function buildIcon(isDictionary) {
    place('s_icon', ICON_HTML, {
      cursor:'pointer',
      'float':'right',
      padding: '0px 15px 25px',
      fontWeight:'bold',
      backgroundColor: 'transparent',
      color:'red',
      position:'fixed',
      right:0,
      bottom: 0,
      height:'10px',
      width:'10px',
      zIndex:9999
    });
    icon = $j('#s_icon').get(0);
    $j('#s_icon').attr('title', isDictionary ? 'Click to sort dictionary' : 'Click to show/hide Sanskrit Toolbar');

    $j('#s_icon').on('click', function(e) {
      if (isDictionary) {
        sortTable();
      } else {
        let tb = $j('#s_toolbar');
        let v = tb.css('display');
        if (v == 'none') {
          tb.css({
            'display':'table',
          });
          $j('body').css('marginTop', '50px');
          setValue('status', 1);
        } else {
          tb.css({
            'display':'none',
          });
          $j('body').css('marginTop', 0);
          setValue('status', 0);
        }
      }
    });
  }

  function place(id, html, css) {
    $j('body').prepend(html);
    $j('#'+id).css(css);
  }

  function getSelectedText(trim) {
    let text =
      (window.getSelection) ? window.getSelection().toString() :
      (document.getSelection) ? document.getSelection().toString() :
      (document.selection) ? document.selection.createRange().text : null;
    if (trim && text != null)
      text = text.trim();
    return text;
  }

  function showDict(text) {
    hideDict();
    let a = $j('#a_dict');
    a.on('click', function(e) {
      a.attr('href',
        'http://'+SANSKRIT_SITE_NEW+'/index.php?mode=3&direct=au&tran_input='+text);
    });
    a.get(0).click();
  }
  
  function hideDict() {
    if (vdiv) {
      vdiv.close();
      vdiv = null;
    }
  }

  function getValue(key, defval) {
    return defval;
  }

  function setValue(key, defval) {
  }

  // ===============================================================
  // General stuff.
  // ===============================================================

  function _debug(s) {
    if (OPTION_DEBUG)
      console.log(s);
  }

  if (window.top != window.self)
    return;
  if (isDictionarySite()) {
    initSorted();
    buildIcon(true);
    buildGrammarUI();
  } else if (isGrammarSite()) {
    fixGrammarStyles();
  } else if (isToolbarSupported()) {
    initToolbarData();
    buildIcon(false);
    buildToolbarUI();
  }
})();