您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Sanskrit Language Tools - Quick access to Sanskrit dictionary, thesarus, news and other tools, on Firefox and Chrome browsers.
// ==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.9 // @license MIT // ==/UserScript== /* * This script does three things: * On the sanskrit dictionary site: * It adds a link (a triangle icon) to each result row, that when * pressed, takes you to the definition of the word in that row. * It adds a (Sanskrit sa) icon to the bottom right of the page. * Clicking the icon sorts the dictionary entries. * On the grammar site: * It fixes some styles to make it look a tad less garish. * On other sites: * It adds a (Sanskrit sa) icon to the bottom right of the page. * Clicking the icon brings up a toolbar at the top of the page. * The toolbar contains some useful Sanskrit-related links. * If the auto-dictionary is checked in the toolbar, * double-clicking a word launches the Sanskrit dictionary in * another window/tab with the selected word. */ (() => { let $j = jQuery.noConflict(); let DEBUG = false; let SANSKRIT_SITE_OLD = 'spokensanskrit.org'; let SANSKRIT_SITE_NEW = 'learnsanskrit.cc'; // === Dictionary site stuff === let SANSKRIT_SITES = [SANSKRIT_SITE_OLD,SANSKRIT_SITE_NEW]; let ALLOW_ANCHORS = [ 'sanskrit.uohyd.ernet.in/cgi-bin/scl/SHMT/generate.cgi', ]; 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 dictCheck() { for (let i = 0; i < SANSKRIT_SITES.length; ++i) { let s = SANSKRIT_SITES[i]; if (document.URL.indexOf(s) != -1) return true; } } function dictInit() { dictTable = $j('#results'); _dictObserve(dictTable, (m) => { let allRows = $j('tr.normalrow,tr.redrow'); let firstRow = allRows.first(); _debug('observer called'); if (firstRow.hasClass('processed') === false) { _debug('observer processing'); firstRow.addClass('processed'); _dictSetupSorting(allRows); _dictAddGrammarLinks(allRows); } }); } function _dictObserve(ele, cb) { let observer = new MutationObserver(function(mutations) { setTimeout(cb(mutations), 100); }); observer.observe(ele[0], { childList: true, }); } function _dictSetupSorting(rows) { dictTableRows = rows; dictTableRows.wrapAll('<tbody id="resultsbody">'); 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 _dictToggleSorted() { let rows = tableSorted ? dictTableRows : dictTableRowsSorted; let rb = $j('#resultsbody'); $j.each(rows, function(index, row) { rb.append(row); }); tableSorted = !tableSorted; } function dictFixSuggestBox() { let ans = $j('#cont_answer'); ans.css({ 'top':'500px', 'left':'50%', 'background': 'transparent', }); } function _dictAddGrammarLinks(rows) { let line = 1; rows.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 (_dictMatchVerb(sansText, grammarInfo, transText, links) || _dictMatchNoun(sansText, grammarInfo, transText, links)) { _dictMakeURLs(row, links); } _debug('-----'); }); } function _dictMatchVerb(sansText, grammarInfo, transText, links) { // Grammar is of the form: verb N _debug('verb: matching ' + grammarInfo + ' with verb'); let a = grammarInfo.match(verbMatch); if (a && a[1] == 'verb') { // transText is of the form xlit_word (xlit_root). // We want the root. _debug('verb: matching ' + transText + ' with verbroot 1'); 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 2'); 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: '▸', target: 'l_grammar', }); } return true; } return false; } function _dictMatchNoun(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 1'); let b = transText.match(nounRootMatch); if (!b || !b[1]) return false; b[1] = b[1].trim().replace(/[\s-]/g, "") _debug('noun: matching ' + transText + ' with nounroot 2'); 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: '▸', target: 'l_grammar', }); } return true; } return false; } function _dictMakeURLs(row, links) { let ltd = row.children().first().children('#word0').first(); ltd.attr('valign','top'); ltd.attr('align', 'left'); let html = ''; for (let i in links) { l = links[i]; 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.before('<div style="float:left; padding-right:3px">'+html+'</div>'); return true; } // === Grammar site stuff === function grammarCheck() { return (document.URL.indexOf('sanskrit.inria.fr') != -1); } function grammarFixStyles() { $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 === // Sites to ignore (we won't add the toolbar here). let IGNORES = [ 'mail.yahoo.com', 'groups.yahoo.com', SANSKRIT_SITE_OLD, SANSKRIT_SITE_NEW, ]; // Toolbar items to add. Format: // [HK-encoded/English name, URL, target_window, devanagari name] let TOOLBAR_ITEMS = [ [ 'vArtAvaliH', 'https://www.youtube.com/playlist?list=PLxx0m3vtiqMZGmsUEVeTAuWIXqc9fTMHy', 'l_news', 'वार्तावलिः', 'Indian Sanskrit Program YouTube Channel'], [ 'samprati vArtAH', 'http://samprativartah.in/', 'l_mag2', 'सम्प्रतिवार्ताः', 'Indian Daily Sanskrit News'], [ 'sudharmA', 'http://epapersudharmasanskritdaily.in/', 'l_mag3', 'सुधर्मा', 'Sanskrit Magazine'], [ 'sambhASaNa sandezaH', 'http://www.sambhashanasandesha.in/', 'l_mag1', 'सम्भाषण सन्देशः', 'Sanskrit Magazine'], [ 'mAhezvarasUtrANi', 'https://www.themathesontrust.org/library/shiva-sutras', 'l_msutra', 'माहेश्वरसूत्राणि', ''], [ 'sandhiH', 'http://sanskrit.jnu.ac.in/sandhi/viccheda.jsp', 'l_sandhi', 'सन्धिः', 'Sandhi Splitter'], [ 'Noun/Verb', 'http://sanskrit.inria.fr/DICO/grammar.fr.html', 'l_inria', 'शब्द-/धातु-रूपावली', 'Sanskrit Grammar Lookup' ], [ 'Books', 'http://www.sanskrit.nic.in/ebooks.php', 'l_books', 'पुस्तकानि', 'Sanskrit Books'], [ 'Wikipedia', 'http://sa.wikipedia.org', 'l_wiki', 'विकिपीडिया', 'Wikipedia in Sanskrit'], ]; // Template for the toolbar. let TOOLBAR_TEMPLATE = '\ <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_CSS = `#s_icon { cursor:pointer; float:right; padding: 0px 15px 25px; font-weight:bold; background-color: transparent; color:red; position:fixed; right:0; bottom: 0; height:10px; width:10px; zIndex:9999; }`; let icon; let visible = {}; let numClicks = 0; let vdiv = null; let allowAnchor = false; let selectedText = null; function toolbarCheck() { for (let i in IGNORES) { if (document.URL.indexOf(IGNORES[i]) != -1) { return false; } } return true; } function toolbarInit() { for (let i in ALLOW_ANCHORS) { if (document.URL.indexOf(ALLOW_ANCHORS[i]) != -1) { allowAnchor = true; break; } } } function toolbarBuild() { $j(`<style> #s_toolbar { font-family: sans-serif; position: fixed; top: 0; margin: 0; width: 100%; z-index: 2999999999; background-color: white; float: left; display:none; line-height: 20px; } .st_lastcol { border: solid 1px #aaa;, padding: 0; } .st_li { text-align: center; border: solid 1px #aaa; line-height: 1.5em; } .st_space' { margin-left:20px; } .st_common { float: left; border: 0; margin: 0; padding: 0; font-weight: normal; vertical-align: middle; color: black; } .st_link { text-decoration: none; margin-left:5px; padding:2px; cursor: pointer; font-size: large; color: black; } .st_label { margin-left: 5px; } .st_option { display: inline-block; margin: 5px; } .st_link::hover { color:orange !important; } .st_checkbox { margin: 5px; } .st_menutrigger { position: relative; } .st_menu' { background-color:#eee; display:none; listStyle: none; position:absolute; width:120px; top: 50px; box-shadow: 5px 5px 5px #888888; z-index:999; } .st_menu li { width:100px; list-style: none inside; } ${ICON_CSS} #s_icon { cursor:pointer; float:right; padding: 0px 15px 25px; font-weight:bold; background-color: transparent; color:red; position:fixed; right:0; bottom: 0; height:10px; width:10px; zIndex:9999; } </style>` ).appendTo('head'); let item_html = ''; for (let i in TOOLBAR_ITEMS) { let item = TOOLBAR_ITEMS[i]; item_html += '<td class="st_li">' + '<a class="st_common st_link" href="'+item[1]+'" title="'+item[4]+'" target="'+item[2]+'">'+item[3]+'<br/>'+item[0]+'</a>'+ '</td>' } place(TOOLBAR_TEMPLATE.replace('%LINKS%', item_html)); $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); } function place(html) { $j('body').prepend(html); } 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', 'https://'+SANSKRIT_SITE_NEW+'/translate?dir=au&search='+text); }); a.get(0).click(); } function hideDict() { if (vdiv) { vdiv.close(); vdiv = null; } } // =========== Common stuff. =========== function buildIcon(isDictionary) { $j(`<style>${ICON_CSS}</style>`).appendTo('head'); place(ICON_HTML); 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) { e.preventDefault(); e.stopPropagation(); if (isDictionary) { _dictToggleSorted(); } else { let tb = $j('#s_toolbar'); let v = tb.css('display'); if (v == 'none') { tb.css({ 'display':'table'}); $j('body').css('marginTop', '50px'); } else { tb.css({'display':'none'}); $j('body').css('marginTop', 0); } } }); } function _debug(s) { if (DEBUG) console.log(s); } // =========== Main =========== if (window.top != window.self) return; if (dictCheck()) { dictInit(); buildIcon(true); dictFixSuggestBox(); } else if (grammarCheck()) { grammarFixStyles(); } else if (toolbarCheck()) { toolbarInit(); buildIcon(false); toolbarBuild(); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址