Sanskrit Tools - Toolbar

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

目前为 2016-03-21 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Sanskrit Tools - Toolbar
  3. // @namespace stgeorge
  4. // @description Sanskrit Language Tools - Quick access to Sanskrit dictionary, thesarus, news and other tools, on Firefox and Chrome browsers.
  5. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
  6. // @grant GM_setValue
  7. // @grant GM_getValue
  8. // @grant GM_getResourceText
  9. // @version 2.5
  10. // @resource lookup http://sanskrit.inria.fr/DICO/grammar.fr.html
  11. // ==/UserScript==
  12.  
  13. (function() {
  14.  
  15. // ===============================================================
  16. // Grammar stuff.
  17. // ===============================================================
  18.  
  19. var SANSKRIT_SITE = 'spokensanskrit.de';
  20.  
  21. // Options.
  22. // Set to the level number. 0 -> no logging; higher numbers -> more
  23. // verbose.
  24. var OPTION_DEBUG_LEVEL = 0;
  25.  
  26. // Set to true true to change word completion list
  27. // to show up below the input field instead of on the side.
  28. var OPTION_IN_PLACE_MATCH = true;
  29.  
  30. // Set to true if we want to assume verbs with no family
  31. // number to be family 1.
  32. // NOTE: Use this with caution. Often results in errors.
  33. var OPTION_DEF_GANA_1 = false;
  34.  
  35. // Set to true to enable Amarakosha lookup.
  36. var OPT_AMARAKOSHA = false;
  37. // Set to true if we want to use split panes.
  38. var OPT_SPLIT_PANE = false;
  39.  
  40. var verbMatch = /(verb)\s*(.*)/;
  41. var verbRootMatch = /{\s*(.*)\s*}/;
  42. var verbClassMatch = /\s*([0-9]+)\s*/g;
  43. var nounMatch = /\b([fmn](?=\.))/g;
  44. var nounRootMatch = /^\s*(.*)\s*$/;
  45. var vurl = 'http://sanskrit.inria.fr/cgi-bin/SKT/sktconjug?lex=SH%V%&q=%Q%&t=KH&c=%C%&font=deva';
  46. var nurl = 'http://sanskrit.inria.fr/cgi-bin/SKT/sktdeclin?lex=SH%V%&q=%Q%&t=KH&g=%G%&font=deva';
  47. var surl = 'http://sanskrit.uohyd.ernet.in/cgi-bin/scl/SHMT/generate.cgi?dic=amara&word=%Q%';
  48. var genders = { f: 'Fem', n: 'Neu', m: 'Mas' };
  49. var gender_names = { f: 'feminine', n: 'neuter', m: 'masculine' };
  50.  
  51. var initDone = false;
  52. var paneSplit = false;
  53. var paneHeight;
  54.  
  55. function isGrammarSupported() {
  56. if (document.URL.indexOf(SANSKRIT_SITE) == -1)
  57. return false;
  58. if (!initDone) {
  59. doc = $(GM_getResourceText('lookup'));
  60. v = $(GM_getResourceText('lookup')).find('[name="v"]:first').val();
  61. if (v) {
  62. v = '&v='+v;
  63. } else {
  64. v = '';
  65. }
  66. vurl = vurl.replace('%V%', v);
  67. nurl = nurl.replace('%V%', v);
  68. _debug(1, 'grammar code=' + v);
  69. _debug(1, 'vurl=' + vurl);
  70. _debug(1, 'nurl=' + nurl);
  71. initDone = true;
  72. }
  73. return true;
  74. }
  75.  
  76. function initGrammarData() {
  77. }
  78.  
  79. function buildGrammarUI() {
  80. fixSuggestBox();
  81. splitPane();
  82. setHandlers();
  83. }
  84.  
  85. function fixSuggestBox() {
  86. if (OPTION_IN_PLACE_MATCH) {
  87. var ans = $('#answer');
  88. ans.bind('DOMSubtreeModified', function() {
  89. ans.children().first().attr('align', 'center');
  90. });
  91. ans.appendTo($('#tinput').parent());
  92. }
  93. }
  94.  
  95. function splitPane() {
  96. if (!OPT_SPLIT_PANE)
  97. return;
  98. if (paneSplit) return;
  99. var body = $('body');
  100. var t = body.children('table').first();
  101. paneHeight = t.outerHeight(true);
  102. var t = t.detach();
  103. $('<div id="lp"></div><div id="rp"></div>').prependTo(body);
  104. $('#lp,#rp').css({
  105. 'float': 'left',
  106. overflow: 'auto',
  107. height: paneHeight + 'px',
  108. });
  109. $('#lp').css({
  110. width: '45%',
  111. });
  112. $('#rp').css({
  113. marginLeft: '10px',
  114. width: '54%',
  115. });
  116. t.appendTo($('#lp'));
  117. paneSplit = true;
  118. }
  119.  
  120. function setHandlers() {
  121. $('tr.bgcol2,tr.bgcol7,tr.highlight').each(function() {
  122. var tr = $(this);
  123. var ltd = tr.children().first();
  124. // Each line is of the form:
  125. // sans_text translit_text grammar_info meaning
  126. var sans = ltd.next();
  127. var xlit = sans.next();
  128. var grmr = xlit.next();
  129. var links = [];
  130. // grammar, in turn, can be of the forms:
  131. // m./f./n./adj. etc (for nouns)
  132. // verb N (for verbs)
  133. var a = grmr.text().match(verbMatch);
  134. var prefix = sans.text() + ';' + xlit.text() + ';' + grmr.text() + ': ';
  135. if (a && a[1] == 'verb') {
  136. // For verbs, xlit is of the form xlit_word (xlit_root).
  137. // We want the root.
  138. var b = xlit.text().match(verbRootMatch);
  139. if (!b || !b[1]) return true;
  140. b[1] = b[1].trim();
  141. if (b[1].match(/[^A-Za-z]/))
  142. return true;
  143. var n;
  144. // For verbs, see if grammar_info has the gaNA info.
  145. if (a[2])
  146. n = a[2].trim().match(verbClassMatch);
  147. if (!(n && n[0])) {
  148. // Use a default gaNa if opted.
  149. if (OPTION_DEF_GANA_1)
  150. n = ['1'];
  151. else
  152. return true;
  153. }
  154. var s = sans.text().match(verbRootMatch);
  155. // At this point, b[1] is the transliterated verb root,
  156. // s[1] is the devangari verb root, and n the gaNa.
  157. _debug(2, prefix);
  158. _debug(2, 'verb');
  159. _debug(2, b[1]);
  160. _debug(2, n);
  161. for (var i = 0; i < n.length; ++i) {
  162. links.push({
  163. tooltip: 'Inflections for ' + a[1] + '(' + n[i] + ') ' + s[1],
  164. url: vurl.replace('%Q%', b[1]).replace('%C%', n[i].trim()),
  165. sym: '&rtrif;',
  166. target: 'l_grammar',
  167. });
  168. }
  169. } else {
  170. a = grmr.text().match(nounMatch);
  171. if (!(a && a[0]))
  172. return true;
  173. var b = xlit.text().match(nounRootMatch);
  174. if (!b || !b[1]) return true;
  175. b[1] = b[1].trim();
  176. if (b[1].match(/[^A-Za-z]/))
  177. return true;
  178. s = sans.text().match(nounRootMatch);
  179. // At this point, b[1] is the xlit noun, s[1] is the
  180. // devanagari noun, and a is one or more lingas.
  181. _debug(2, prefix);
  182. _debug(2, 'noun=');
  183. _debug(2, b[1]);
  184. _debug(2, a);
  185. if (a.length > 0) {
  186. if (OPT_AMARAKOSHA) {
  187. links.push({
  188. url: surl.replace('%Q%', sans.text()),
  189. tooltip: 'Synonyms for ' + b[1] + '. (The thesarus may not have synonyms for all words.)',
  190. sym: '&lowast;',
  191. target: 'l_thes',
  192. });
  193. }
  194. for (var i = 0; i < a.length; ++i) {
  195. links.push({
  196. url: nurl.replace('%Q%', b[1]).replace('%G%', genders[a[i]]),
  197. tooltip: 'Inflections for ' + ' noun ' + s[1],
  198. sym: '&rtrif;',
  199. target: 'l_grammar',
  200. });
  201. }
  202. }
  203. }
  204. var html;
  205. if (links[0]) {
  206. html = '';
  207. for (var i in links) {
  208. l = links[i];
  209. ltd.attr('valign','top');
  210. html +=
  211. '<a data-id="' +i+
  212. '" class="def stil4" style="#96290e;font-weight:bold;font-size:x-large;" href="' +
  213. l.url + '" title="' + l.tooltip + '">'+l.sym+'</a>';
  214. }
  215. ltd.html(html);
  216. ltd.attr('align', 'left');
  217. if (OPT_SPLIT_PANE) {
  218. ltd.children('a').each(function(k,v) {
  219. $(this).on('click', function(e) {
  220. e.preventDefault();
  221. var url = $(this).attr('href');
  222. $('#rp').html('<iframe width="100%" border="none" frameborder="0" height="'+paneHeight+'px" src="' + url + '"></iframe>');
  223. });
  224. });
  225. }
  226. }
  227. return true;
  228. });
  229. }
  230.  
  231. // ===============================================================
  232. // Toolbar stuff.
  233. // ===============================================================
  234.  
  235. var IGNORES = [
  236. 'mail.yahoo.com',
  237. 'groups.yahoo.com',
  238. 'spokensanskrit.de',
  239. ];
  240. var ALLOW_ANCHORS = [
  241. 'sanskrit.uohyd.ernet.in/cgi-bin/scl/SHMT/generate.cgi',
  242. ];
  243. var TOOLBAR_HTML = '\
  244. <div id="s_toolbar">\
  245. <div style="float:left; display:inline-block">\
  246. <ul style="list-style:none;margin:0;padding:0">\
  247. <li class="st_li">\
  248. <a title="Doordarshan Sanskrit News/Magazine" class="st_common st_link" href="http://www.youtube.com/user/sanskritanews/videos" target="l_news">\
  249. &#2357;&#2366;&#2352;&#2381;&#2340;&#2366;&#2307;</a>\
  250. </li>\
  251. <li class="st_li">\
  252. <a title="\'Sambhaashana Sandesha\' Magazine" class="st_common st_link" href="http://www.sambhashanasandesha.in/" target="l_mag1">&#2360;&#2350;&#2381;&#2349;&#2366;&#2359;&#2339; &#2360;&#2344;&#2381;&#2342;&#2375;&#2358;&#2307;</a>\
  253. </li>\
  254. <li class="st_li">\
  255. <a title="\'Vishva Vani\' Magazine" class="st_common st_link" href="http://www.speaksanskrit.org/vishvavani.shtml" target="l_mag2">&#2357;&#2367;&#2358;&#2381;&#2357;&#2357;&#2366;&#2339;&#2368;</a>\
  256. </li>\
  257. <li class="st_li">\
  258. <a title="Books" class="st_common st_link" href="http://www.sanskrit.nic.in/ebook.htm" target="l_books">&#2346;&#2369;&#2360;&#2381;&#2340;&#2325;&#2366;&#2344;&#2367;</a>\
  259. </li>\
  260. <li class="st_li">\
  261. <a title="Wikipedia" class="st_common st_link" href="http://sa.wikipedia.org" target="l_wiki">\
  262. &#2357;&#2367;&#2325;&#2367;&#2346;&#2368;&#2337;&#2367;&#2351;&#2366</a>\
  263. </li>\
  264. <li class="st_li">\
  265. <a id="l_word" title="Show a random verb" class="st_common st_link" target="l_word">\&#2351;&#2342;&#2371;&#2330;&#2381;&#2331;&#2367;&#2325;&#2346;&#2342;&#2350;&#2381;</a>\
  266. </li>\
  267. <li class="st_li st_space">\
  268. </li>\
  269. <li class="st_li">\
  270. <a title="Maheshwara Sutras" class="st_common st_link" href="http://en.wikipedia.org/wiki/Siva_Sutra#Text" target="l_msutra">\
  271. &#2350;&#2366;&#2361;&#2375;&#2358;&#2381;&#2357;&#2352;&#2360;&#2370;&#2340;&#2381;&#2352;&#2366;&#2339;&#2367;</a>\
  272. </li>\
  273. <li class="st_li">\
  274. <a title="Noun/Verb Expansion" class="st_common st_link" href="http://sanskrit.inria.fr/DICO/grammar.fr.html" target="l_inria">\
  275. &#2358;&#2349;&#2381;&#2342;, &#2343;&#2366;&#2340;&#2369;&#2352;&#2370;&#2346;&#2366;&#2357;&#2354;&#2368;</a>\
  276. </li>\
  277. <li class="st_li">\
  278. <a title="Sandhi splitter" class="st_common st_link" href="http://tdil-dc.in/san/sandhi_splitter/index_dit.html" target="l_sandhi">\
  279. &#2360;&#2344;&#2381;&#2343;&#2367;&#2307;</a>\
  280. </li>\
  281. <li class="st_li st_space">\
  282. </li>\
  283. <li class="st_li">\
  284. <div title="Double-clicking a word will automatically launch the dictionary" class="st_common st_option">\
  285. <input type="checkbox" id="o_auto" class="st_common st_checkbox" title="Double-clicking a word will automatically launch the dictionary"/>\
  286. <label for="o_auto" class="st_label">Auto-dictionary</label>\
  287. </div>\
  288. </li>\
  289. <li class="st_li st_space">\
  290. </li>\
  291. </ul>\
  292. </div>\
  293. </div>\
  294. <a id="a_dict" style="display:none" href="" target="l_dict"></a>\
  295. </div>';
  296. var ICON_HTML = '\
  297. <div id="icon" title="Click to show/hide Sanskrit Toolbar">\u0938\
  298. </div>';
  299. var VERBS = [
  300. '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'
  301. ];
  302.  
  303. var icon;
  304. var cbs = {
  305. l_word : function(id) {
  306. showDict(VERBS[Math.floor(Math.random() * VERBS.length)],
  307. '&direction=ES'
  308. );
  309. }
  310. };
  311. var visible = {};
  312. var numClicks = 0;
  313. var vdiv = null;
  314. var allowAnchor = false;
  315. var selectedText = null;
  316.  
  317. function isToolbarSupported() {
  318. for (var i in IGNORES) {
  319. if (document.URL.indexOf(IGNORES[i]) != -1) {
  320. return false;
  321. }
  322. }
  323. return true;
  324. }
  325.  
  326. function initToolbarData() {
  327. for (var i in ALLOW_ANCHORS) {
  328. if (document.URL.indexOf(ALLOW_ANCHORS[i]) != -1) {
  329. allowAnchor = true;
  330. break;
  331. }
  332. }
  333. }
  334.  
  335. function buildToolbarUI() {
  336. place('s_toolbar', TOOLBAR_HTML, {
  337. position: 'fixed',
  338. 'top': 0,
  339. margin: 0,
  340. // minHeight: '30px',
  341. width: '100%',
  342. zIndex: 2999999999,
  343. paddingTop: '3px',
  344. paddingBottom: '3px',
  345. backgroundColor: 'white',
  346. borderBottom: '1px solid orange',
  347. float: 'left',
  348. display:'none'
  349. });
  350. for (var i in cbs) {
  351. (function(p) {
  352. $('#'+p).on('click', function(e) {
  353. e.preventDefault();
  354. e.stopPropagation();
  355. var cb = cbs[p];
  356. cb($(this).attr('id'));
  357. });
  358. })(i);
  359. }
  360. $('.st_li').css({
  361. background: 'none',
  362. border: 0,
  363. display:'inline',
  364. padding: 0,
  365. });
  366. $('.st_space').css({
  367. marginLeft:'20px',
  368. });
  369. $('.st_common').css({
  370. float: 'left',
  371. border: 0,
  372. margin: 0,
  373. padding: 0,
  374. // height: '30px',
  375. fontSize: '15px',
  376. verticalAlign:'middle',
  377. });
  378. $('.st_link').css({
  379. textDecoration: 'none',
  380. fontWeight: 'bolder',
  381. marginLeft:'5px',
  382. padding:'5px',
  383. cursor: 'pointer',
  384. backgroundColor: '#eeeeee',
  385. color: 'black',
  386. });
  387. $('.st_label').css({
  388. marginLeft: '5px',
  389. });
  390. $('.st_option').css({
  391. display: 'inline-block',
  392. margin: '5px'
  393. });
  394. $('.st_link').hover(function() {
  395. $(this).css({color:'orange'});
  396. }, function() {
  397. $(this).css({color:'black'});
  398. });
  399. $('.st_checkbox').css({
  400. margin: '5px'
  401. });
  402. $('.st_menutrigger').css({
  403. position: 'relative'
  404. });
  405. $('.st_menu').css({
  406. backgroundColor:'#eee',
  407. display:'none',
  408. listStyle: 'none',
  409. position:'absolute',
  410. width:'120px',
  411. // left:'50px',
  412. 'top': '50px',
  413. boxShadow: '5px 5px 5px #888888',
  414. zIndex:'999',
  415. });
  416. $('.st_menu li').css({
  417. width:'100px',
  418. listStyle: 'none inside',
  419. });
  420. place('icon', ICON_HTML, {
  421. cursor:'pointer',
  422. 'float':'right',
  423. padding: '0px 15px 18px',
  424. fontWeight:'bold',
  425. backgroundColor: 'transparent',
  426. color:'red',
  427. position:'fixed',
  428. right:0,
  429. bottom: 0,
  430. height:'10px',
  431. width:'10px',
  432. zIndex:9999
  433. });
  434. icon = $('#icon').get(0);
  435.  
  436. $('#icon').on('click', function(e) {
  437. var tb = $('#s_toolbar');
  438. var v = tb.css('display');
  439. if (v == 'none') {
  440. tb.css({
  441. 'display':'block',
  442. });
  443. $('body').css('marginTop', '50px');
  444. GM_setValue('status', 1);
  445. } else {
  446. tb.css({
  447. 'display':'none',
  448. });
  449. $('body').css('marginTop', 0);
  450. GM_setValue('status', 0);
  451. }
  452. });
  453. $('#o_auto').on('change', function(e) {
  454. GM_setValue('auto', $(this).prop('checked'));
  455. });
  456. $('.st_menutrigger').on('click', function(e) {
  457. e.preventDefault();
  458. e.stopPropagation();
  459. var trigger = $(this);
  460. var tgt = trigger.attr('data-menu');
  461. var v = visible[tgt];
  462. if (v)
  463. $(tgt).css('display', 'none');
  464. else
  465. $(tgt).css('display', 'block');
  466. visible[tgt] = !v;
  467. });
  468. $(document).on('click', function(e) {
  469. $('.st_menu').css('display', 'none');
  470. for (var i in visible) {
  471. visible[i] = false;
  472. }
  473. });
  474. document.addEventListener('mouseup', function(e) {
  475. var node = (e.target || e.srcElement);
  476. if (e.button != 0 || (node.nodeName == 'A' && !allowAnchor)
  477. || node.nodeName == 'INPUT') {
  478. return;
  479. }
  480. var n = node;
  481. while (n) {
  482. if (n == icon) {
  483. return;
  484. }
  485. if (n.getAttribute) {
  486. var ce = n.getAttribute('contenteditable');
  487. if (ce) {
  488. return;
  489. }
  490. }
  491. n = n.parentNode;
  492. }
  493. if (++numClicks == 1) {
  494. window.setTimeout(function() {
  495. selectedText = getSelectedText(true);
  496. if (selectedText != null && selectedText.length > 0) {
  497. if (selectedText.indexOf(' ') != -1) {
  498. selectedText = null;
  499. return;
  500. }
  501. if ($('#o_auto').prop('checked')) {
  502. showDict(selectedText);
  503. }
  504. } else {
  505. hideDict();
  506. }
  507. numClicks = 0;
  508. }, 300);
  509. }
  510. }, false);
  511.  
  512. if (GM_getValue('status', 0))
  513. show();
  514. }
  515.  
  516. function place(id, html, css) {
  517. $('body').prepend(html);
  518. $('#'+id).css(css);
  519. }
  520.  
  521. function getSelectedText(trim) {
  522. var text =
  523. (window.getSelection) ? window.getSelection().toString() :
  524. (document.getSelection) ? document.getSelection().toString() :
  525. (document.selection) ? document.selection.createRange().text : null;
  526. if (trim && text != null)
  527. text = text.trim();
  528. return text;
  529. }
  530.  
  531. function showDict(text) {
  532. hideDict();
  533. var a = $('#a_dict');
  534. a.on('click', function(e) {
  535. a.attr('href',
  536. 'http://spokensanskrit.de/index.php?trans=Translate&tinput='+text);
  537. });
  538. a.get(0).click();
  539. }
  540. function hideDict() {
  541. if (vdiv) {
  542. vdiv.close();
  543. vdiv = null;
  544. }
  545. }
  546.  
  547. // ===============================================================
  548. // General stuff.
  549. // ===============================================================
  550.  
  551. function _debug(level, s) {
  552. if (level < OPTION_DEBUG_LEVEL)
  553. console.log(s);
  554. }
  555.  
  556. function isMainWindow() {
  557. return (window.top == window.self);
  558. }
  559.  
  560. // Main:
  561. if (!isMainWindow())
  562. return;
  563. if (isGrammarSupported()) {
  564. initGrammarData();
  565. buildGrammarUI();
  566. }
  567. if (isToolbarSupported()) {
  568. initToolbarData();
  569. buildToolbarUI();
  570. }
  571. })();