// ==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
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_getResourceText
// @version 2.5
// @resource lookup http://sanskrit.inria.fr/DICO/grammar.fr.html
// ==/UserScript==
(function() {
// ===============================================================
// Grammar stuff.
// ===============================================================
var SANSKRIT_SITE = 'spokensanskrit.de';
// Options.
// Set to the level number. 0 -> no logging; higher numbers -> more
// verbose.
var OPTION_DEBUG_LEVEL = 0;
// Set to true true to change word completion list
// to show up below the input field instead of on the side.
var OPTION_IN_PLACE_MATCH = true;
// Set to true if we want to assume verbs with no family
// number to be family 1.
// NOTE: Use this with caution. Often results in errors.
var OPTION_DEF_GANA_1 = false;
// Set to true to enable Amarakosha lookup.
var OPT_AMARAKOSHA = false;
// Set to true if we want to use split panes.
var OPT_SPLIT_PANE = false;
var verbMatch = /(verb)\s*(.*)/;
var verbRootMatch = /{\s*(.*)\s*}/;
var verbClassMatch = /\s*([0-9]+)\s*/g;
var nounMatch = /\b([fmn](?=\.))/g;
var nounRootMatch = /^\s*(.*)\s*$/;
var vurl = 'http://sanskrit.inria.fr/cgi-bin/SKT/sktconjug?lex=SH%V%&q=%Q%&t=KH&c=%C%&font=deva';
var nurl = 'http://sanskrit.inria.fr/cgi-bin/SKT/sktdeclin?lex=SH%V%&q=%Q%&t=KH&g=%G%&font=deva';
var surl = 'http://sanskrit.uohyd.ernet.in/cgi-bin/scl/SHMT/generate.cgi?dic=amara&word=%Q%';
var genders = { f: 'Fem', n: 'Neu', m: 'Mas' };
var gender_names = { f: 'feminine', n: 'neuter', m: 'masculine' };
var initDone = false;
var paneSplit = false;
var paneHeight;
function isGrammarSupported() {
if (document.URL.indexOf(SANSKRIT_SITE) == -1)
return false;
if (!initDone) {
doc = $(GM_getResourceText('lookup'));
v = $(GM_getResourceText('lookup')).find('[name="v"]:first').val();
if (v) {
v = '&v='+v;
} else {
v = '';
}
vurl = vurl.replace('%V%', v);
nurl = nurl.replace('%V%', v);
_debug(1, 'grammar code=' + v);
_debug(1, 'vurl=' + vurl);
_debug(1, 'nurl=' + nurl);
initDone = true;
}
return true;
}
function initGrammarData() {
}
function buildGrammarUI() {
fixSuggestBox();
splitPane();
setHandlers();
}
function fixSuggestBox() {
if (OPTION_IN_PLACE_MATCH) {
var ans = $('#answer');
ans.bind('DOMSubtreeModified', function() {
ans.children().first().attr('align', 'center');
});
ans.appendTo($('#tinput').parent());
}
}
function splitPane() {
if (!OPT_SPLIT_PANE)
return;
if (paneSplit) return;
var body = $('body');
var t = body.children('table').first();
paneHeight = t.outerHeight(true);
var t = t.detach();
$('<div id="lp"></div><div id="rp"></div>').prependTo(body);
$('#lp,#rp').css({
'float': 'left',
overflow: 'auto',
height: paneHeight + 'px',
});
$('#lp').css({
width: '45%',
});
$('#rp').css({
marginLeft: '10px',
width: '54%',
});
t.appendTo($('#lp'));
paneSplit = true;
}
function setHandlers() {
$('tr.bgcol2,tr.bgcol7,tr.highlight').each(function() {
var tr = $(this);
var ltd = tr.children().first();
// Each line is of the form:
// sans_text translit_text grammar_info meaning
var sans = ltd.next();
var xlit = sans.next();
var grmr = xlit.next();
var links = [];
// grammar, in turn, can be of the forms:
// m./f./n./adj. etc (for nouns)
// verb N (for verbs)
var a = grmr.text().match(verbMatch);
var prefix = sans.text() + ';' + xlit.text() + ';' + grmr.text() + ': ';
if (a && a[1] == 'verb') {
// For verbs, xlit is of the form xlit_word (xlit_root).
// We want the root.
var b = xlit.text().match(verbRootMatch);
if (!b || !b[1]) return true;
b[1] = b[1].trim();
if (b[1].match(/[^A-Za-z]/))
return true;
var n;
// For verbs, see if grammar_info has the gaNA info.
if (a[2])
n = a[2].trim().match(verbClassMatch);
if (!(n && n[0])) {
// Use a default gaNa if opted.
if (OPTION_DEF_GANA_1)
n = ['1'];
else
return true;
}
var s = sans.text().match(verbRootMatch);
// At this point, b[1] is the transliterated verb root,
// s[1] is the devangari verb root, and n the gaNa.
_debug(2, prefix);
_debug(2, 'verb');
_debug(2, b[1]);
_debug(2, n);
for (var i = 0; i < n.length; ++i) {
links.push({
tooltip: 'Inflections for ' + a[1] + '(' + n[i] + ') ' + s[1],
url: vurl.replace('%Q%', b[1]).replace('%C%', n[i].trim()),
sym: '▸',
target: 'l_grammar',
});
}
} else {
a = grmr.text().match(nounMatch);
if (!(a && a[0]))
return true;
var b = xlit.text().match(nounRootMatch);
if (!b || !b[1]) return true;
b[1] = b[1].trim();
if (b[1].match(/[^A-Za-z]/))
return true;
s = sans.text().match(nounRootMatch);
// At this point, b[1] is the xlit noun, s[1] is the
// devanagari noun, and a is one or more lingas.
_debug(2, prefix);
_debug(2, 'noun=');
_debug(2, b[1]);
_debug(2, a);
if (a.length > 0) {
if (OPT_AMARAKOSHA) {
links.push({
url: surl.replace('%Q%', sans.text()),
tooltip: 'Synonyms for ' + b[1] + '. (The thesarus may not have synonyms for all words.)',
sym: '∗',
target: 'l_thes',
});
}
for (var i = 0; i < a.length; ++i) {
links.push({
url: nurl.replace('%Q%', b[1]).replace('%G%', genders[a[i]]),
tooltip: 'Inflections for ' + ' noun ' + s[1],
sym: '▸',
target: 'l_grammar',
});
}
}
}
var html;
if (links[0]) {
html = '';
for (var i in links) {
l = links[i];
ltd.attr('valign','top');
html +=
'<a data-id="' +i+
'" class="def stil4" style="#96290e;font-weight:bold;font-size:x-large;" href="' +
l.url + '" title="' + l.tooltip + '">'+l.sym+'</a>';
}
ltd.html(html);
ltd.attr('align', 'left');
if (OPT_SPLIT_PANE) {
ltd.children('a').each(function(k,v) {
$(this).on('click', function(e) {
e.preventDefault();
var url = $(this).attr('href');
$('#rp').html('<iframe width="100%" border="none" frameborder="0" height="'+paneHeight+'px" src="' + url + '"></iframe>');
});
});
}
}
return true;
});
}
// ===============================================================
// Toolbar stuff.
// ===============================================================
var IGNORES = [
'mail.yahoo.com',
'groups.yahoo.com',
'spokensanskrit.de',
];
var ALLOW_ANCHORS = [
'sanskrit.uohyd.ernet.in/cgi-bin/scl/SHMT/generate.cgi',
];
var TOOLBAR_HTML = '\
<div id="s_toolbar">\
<div style="float:left; display:inline-block">\
<ul style="list-style:none;margin:0;padding:0">\
<li class="st_li">\
<a title="Doordarshan Sanskrit News/Magazine" class="st_common st_link" href="http://www.youtube.com/user/sanskritanews/videos" target="l_news">\
वार्ताः</a>\
</li>\
<li class="st_li">\
<a title="\'Sambhaashana Sandesha\' Magazine" class="st_common st_link" href="http://www.sambhashanasandesha.in/" target="l_mag1">सम्भाषण सन्देशः</a>\
</li>\
<li class="st_li">\
<a title="\'Vishva Vani\' Magazine" class="st_common st_link" href="http://www.speaksanskrit.org/vishvavani.shtml" target="l_mag2">विश्ववाणी</a>\
</li>\
<li class="st_li">\
<a title="Books" class="st_common st_link" href="http://www.sanskrit.nic.in/ebook.htm" target="l_books">पुस्तकानि</a>\
</li>\
<li class="st_li">\
<a title="Wikipedia" class="st_common st_link" href="http://sa.wikipedia.org" target="l_wiki">\
विकिपीडिया</a>\
</li>\
<li class="st_li">\
<a id="l_word" title="Show a random verb" class="st_common st_link" target="l_word">\यदृच्छिकपदम्</a>\
</li>\
<li class="st_li st_space">\
</li>\
<li class="st_li">\
<a title="Maheshwara Sutras" class="st_common st_link" href="http://en.wikipedia.org/wiki/Siva_Sutra#Text" target="l_msutra">\
माहेश्वरसूत्राणि</a>\
</li>\
<li class="st_li">\
<a title="Noun/Verb Expansion" class="st_common st_link" href="http://sanskrit.inria.fr/DICO/grammar.fr.html" target="l_inria">\
शभ्द, धातुरूपावली</a>\
</li>\
<li class="st_li">\
<a title="Sandhi splitter" class="st_common st_link" href="http://tdil-dc.in/san/sandhi_splitter/index_dit.html" target="l_sandhi">\
सन्धिः</a>\
</li>\
<li class="st_li st_space">\
</li>\
<li class="st_li">\
<div title="Double-clicking a word will automatically launch the dictionary" class="st_common st_option">\
<input type="checkbox" id="o_auto" class="st_common st_checkbox" title="Double-clicking a word will automatically launch the dictionary"/>\
<label for="o_auto" class="st_label">Auto-dictionary</label>\
</div>\
</li>\
<li class="st_li st_space">\
</li>\
</ul>\
</div>\
</div>\
<a id="a_dict" style="display:none" href="" target="l_dict"></a>\
</div>';
var ICON_HTML = '\
<div id="icon" title="Click to show/hide Sanskrit Toolbar">\u0938\
</div>';
var VERBS = [
'accept','account','achieve','act','add','admit','affect','afford','agree','aim','allow','answer','appear','apply','argue','arrange','arrive','ask','attack','avoid','base','be','beat','become','begin','believe','belong','break','build','burn','buy','call','can','care','carry','catch','cause','change','charge','check','choose','claim','clean','clear','climb','close','collect','come','commit','compare','complain','complete','concern','confirm','connect','consider','consist','contact','contain','continue','contribute','control','cook','copy','correct','cost','count','cover','create','cross','cry','cut','damage','dance','deal','decide','deliver','demand','deny','depend','describe','design','destroy','develop','die','disappear','discover','discuss','divide','do','draw','dress','drink','drive','drop','eat','enable','encourage','end','enjoy','examine','exist','expect','experience','explain','express','extend','face','fail','fall','fasten','feed','feel','fight','fill','find','finish','fit','fly','fold','follow','force','forget','forgive','form','found','gain','get','give','go','grow','handle','happen','hate','have','head','hear','help','hide','hit','hold','hope','hurt','identify','imagine','improve','include','increase','indicate','influence','inform','intend','introduce','invite','involve','join','jump','keep','kick','kill','knock','know','last','laugh','lay','lead','learn','leave','lend','let','lie','like','limit','link','listen','live','look','lose','love','make','manage','mark','matter','mean','measure','meet','mention','mind','miss','move','need','notice','obtain','occur','offer','open','order','own','pass','pay','perform','pick','place','plan','play','point','prefer','prepare','present','press','prevent','produce','promise','protect','prove','provide','publish','pull','push','put','raise','reach','read','realize','receive','recognize','record','reduce','refer','reflect','refuse','regard','relate','release','remain','remember','remove','repeat','replace','reply','report','represent','require','rest','result','return','reveal','ring','rise','roll','run','save','say','see','seem','sell','send','separate','serve','set','settle','shake','share','shoot','shout','show','shut','sing','sit','sleep','smile','sort','sound','speak','stand','start','state','stay','stick','stop','study','succeed','suffer','suggest','suit','supply','support','suppose','survive','take','talk','teach','tell','tend','test','thank','think','throw','touch','train','travel','treat','try','turn','understand','use','visit','vote','wait','walk','want','warn','wash','watch','wear','win','wish','wonder','work','worry','write'
];
var icon;
var cbs = {
l_word : function(id) {
showDict(VERBS[Math.floor(Math.random() * VERBS.length)],
'&direction=ES'
);
}
};
var visible = {};
var numClicks = 0;
var vdiv = null;
var allowAnchor = false;
var selectedText = null;
function isToolbarSupported() {
for (var i in IGNORES) {
if (document.URL.indexOf(IGNORES[i]) != -1) {
return false;
}
}
return true;
}
function initToolbarData() {
for (var i in ALLOW_ANCHORS) {
if (document.URL.indexOf(ALLOW_ANCHORS[i]) != -1) {
allowAnchor = true;
break;
}
}
}
function buildToolbarUI() {
place('s_toolbar', TOOLBAR_HTML, {
position: 'fixed',
'top': 0,
margin: 0,
// minHeight: '30px',
width: '100%',
zIndex: 2999999999,
paddingTop: '3px',
paddingBottom: '3px',
backgroundColor: 'white',
borderBottom: '1px solid orange',
float: 'left',
display:'none'
});
for (var i in cbs) {
(function(p) {
$('#'+p).on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var cb = cbs[p];
cb($(this).attr('id'));
});
})(i);
}
$('.st_li').css({
background: 'none',
border: 0,
display:'inline',
padding: 0,
});
$('.st_space').css({
marginLeft:'20px',
});
$('.st_common').css({
float: 'left',
border: 0,
margin: 0,
padding: 0,
// height: '30px',
fontSize: '15px',
verticalAlign:'middle',
});
$('.st_link').css({
textDecoration: 'none',
fontWeight: 'bolder',
marginLeft:'5px',
padding:'5px',
cursor: 'pointer',
backgroundColor: '#eeeeee',
color: 'black',
});
$('.st_label').css({
marginLeft: '5px',
});
$('.st_option').css({
display: 'inline-block',
margin: '5px'
});
$('.st_link').hover(function() {
$(this).css({color:'orange'});
}, function() {
$(this).css({color:'black'});
});
$('.st_checkbox').css({
margin: '5px'
});
$('.st_menutrigger').css({
position: 'relative'
});
$('.st_menu').css({
backgroundColor:'#eee',
display:'none',
listStyle: 'none',
position:'absolute',
width:'120px',
// left:'50px',
'top': '50px',
boxShadow: '5px 5px 5px #888888',
zIndex:'999',
});
$('.st_menu li').css({
width:'100px',
listStyle: 'none inside',
});
place('icon', ICON_HTML, {
cursor:'pointer',
'float':'right',
padding: '0px 15px 18px',
fontWeight:'bold',
backgroundColor: 'transparent',
color:'red',
position:'fixed',
right:0,
bottom: 0,
height:'10px',
width:'10px',
zIndex:9999
});
icon = $('#icon').get(0);
$('#icon').on('click', function(e) {
var tb = $('#s_toolbar');
var v = tb.css('display');
if (v == 'none') {
tb.css({
'display':'block',
});
$('body').css('marginTop', '50px');
GM_setValue('status', 1);
} else {
tb.css({
'display':'none',
});
$('body').css('marginTop', 0);
GM_setValue('status', 0);
}
});
$('#o_auto').on('change', function(e) {
GM_setValue('auto', $(this).prop('checked'));
});
$('.st_menutrigger').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
var trigger = $(this);
var tgt = trigger.attr('data-menu');
var v = visible[tgt];
if (v)
$(tgt).css('display', 'none');
else
$(tgt).css('display', 'block');
visible[tgt] = !v;
});
$(document).on('click', function(e) {
$('.st_menu').css('display', 'none');
for (var i in visible) {
visible[i] = false;
}
});
document.addEventListener('mouseup', function(e) {
var node = (e.target || e.srcElement);
if (e.button != 0 || (node.nodeName == 'A' && !allowAnchor)
|| node.nodeName == 'INPUT') {
return;
}
var n = node;
while (n) {
if (n == icon) {
return;
}
if (n.getAttribute) {
var 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 ($('#o_auto').prop('checked')) {
showDict(selectedText);
}
} else {
hideDict();
}
numClicks = 0;
}, 300);
}
}, false);
if (GM_getValue('status', 0))
show();
}
function place(id, html, css) {
$('body').prepend(html);
$('#'+id).css(css);
}
function getSelectedText(trim) {
var 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();
var a = $('#a_dict');
a.on('click', function(e) {
a.attr('href',
'http://spokensanskrit.de/index.php?trans=Translate&tinput='+text);
});
a.get(0).click();
}
function hideDict() {
if (vdiv) {
vdiv.close();
vdiv = null;
}
}
// ===============================================================
// General stuff.
// ===============================================================
function _debug(level, s) {
if (level < OPTION_DEBUG_LEVEL)
console.log(s);
}
function isMainWindow() {
return (window.top == window.self);
}
// Main:
if (!isMainWindow())
return;
if (isGrammarSupported()) {
initGrammarData();
buildGrammarUI();
}
if (isToolbarSupported()) {
initToolbarData();
buildToolbarUI();
}
})();