Indic Transliterate

Transliterate from latin encodings and other Indic Unicode to Indic Unicode

  1. // ==UserScript==
  2. // @name Indic Transliterate
  3. // @namespace itranslit
  4. // @description Transliterate from latin encodings and other Indic Unicode to Indic Unicode
  5. // @match *://*/*
  6. // @exclude *://spokensanskrit.org/*
  7. // @grant GM_getValue
  8. // @grant GM_setValue
  9. // @noframes
  10. // @version 2.0.1
  11. // ==/UserScript==
  12.  
  13. // NOTE:
  14. // This used to be three files: itranslist_data.js (that contained
  15. // functions for specific scripts - tamil, devanagari, etc.),
  16. // itranslit.js (that contained data common to all Indic languages
  17. // and functions to map to and from latin to Indic Unicode), and
  18. // itmain.user.js (the actual userscript that @require'd the
  19. // first two).
  20. // Tampermonkey seems to having problems processing @require,
  21. // so all the three files have merged into one.
  22.  
  23. (function() {
  24.  
  25. // BEGIN itranslit_data.js.
  26.  
  27. // To add support for a script xxx, do:
  28. // 1 Add a pp_xxx (postprocess) function for the script. The function
  29. // is called with the Indic Unicode text (and the encoding, if the input is
  30. // latin) as parameters, and should fix any
  31. // unconventional/sloppy characters with the correct ones and return
  32. // the postprocessed text. See the pp_? functions below for examples.
  33. // 2 Add a line about the script in the _Scripts map (defined below
  34. // the pp_xxx functions).
  35.  
  36. // Fix character sequences unique to Tamil.
  37. function _pp_tamil(text, from_encoding) {
  38. // R -> ru, RR -> roo.
  39. text = text.replace(/\u0b8b/g, '\u0bb0\u0bc1');
  40. text = text.replace(/\u0be0/g, '\u0bb0\u0bc2');
  41. // same as mod. (example: kR)
  42. text = text.replace(/\u0bc3/g, '\u0bcd\u0bb0\u0bc1');
  43. text = text.replace(/\u0bc4/g, '\u0bcd\u0bb0\u0bc2');
  44. // lR, lRR
  45. text = text.replace(/\u0b8c/g, '\u0bb2\u0bcd\u0bb0\u0bc1');
  46. text = text.replace(/\u0be1/g, '\u0bb2\u0bcd\u0bb0\u0bc2');
  47. // same as mod. (example: kLR)
  48. text = text.replace(/\u0be2/g, '\u0bcd\u0bb2\u0bcd\u0bb0\u0bc1');
  49. text = text.replace(/\u0be3/g, '\u0bcd\u0bb2\u0bcd\u0bb0\u0bc2');
  50. // kha, ga, gha -> ka
  51. text = text.replace(/[\u0b96\u0b97\u0b98]/g, '\u0b95');
  52. // cha -> ca
  53. text = text.replace(/\u0b9b/g, '\u0b9a');
  54. // jha -> ja
  55. text = text.replace(/\u0b9d/g, '\u0b9c');
  56. // tha, da, dha -> ta
  57. text = text.replace(/[\u0ba0\u0ba1\u0ba2]/g, '\u0b9f');
  58. // Tha, Da, Dha -> Ta
  59. text = text.replace(/[\u0ba5\u0ba6\u0ba7]/g, '\u0ba4');
  60. // pha, ba, bha -> pa.
  61. text = text.replace(/[\u0bab\u0bac\u0bad]/g, '\u0baa');
  62. // OM
  63. text = text.replace(/\u0bd0/g, '\u0b93\u0bae\u0bcd');
  64. // m
  65. text = text.replace(/\u0b82/g, '\u0bae\u0bcd');
  66. // H
  67. text = text.replace(/\u0b83/g, '\u0903');
  68. // S -> nothing
  69. text = text.replace(/\u0bbd/g, '');
  70. // || -> .
  71. text = text.replace(/\u0be4\u0be4\s*/g, '. ');
  72. text = text.replace(/\u0be5\s*/g, '. ');
  73. // | -> ;
  74. text = text.replace(/\u0be4\s*/g, '; ');
  75. // na -> ~na if not at start of word.
  76. text = text.replace(/.[\u0ba8]+/g, function(m) {
  77. if (!m.charAt(0).match(/\s/))
  78. return m.charAt(0) + m.substr(1).replace(/\u0ba8/g,'\u0ba9');
  79. else
  80. return m;
  81. });
  82. // n if followed by ta.
  83. text = text.replace(/\u0ba9(?=\u0bcd\u0ba4)/g, '\u0ba8');
  84. // nr -> nR (e.g., manram -> manRam)
  85. text = text.replace(/\u0ba9\u0bcd\u0bb0/g, '\u0ba9\u0bcd\u0bb1');
  86. // ra[ra,Ra] -> RRa
  87. // bonus: t[ra] -> RRa
  88. text = text.replace(/[\u0bb0\u0b9f]\u0bcd[\u0bb0\u0bb1]/g, '\u0bb1\u0bcd\u0bb1');
  89. return text;
  90. }
  91.  
  92. // Fix character sequences unique to Devanagari.
  93. function _pp_devanagari(text, from_encoding) {
  94. // Replace e with E.
  95. text = text.replace(/\u090e/g, '\u090f');
  96. text = text.replace(/\u0946/g, '\u0947');
  97. // Replace o with O.
  98. text = text.replace(/\u0912/g, '\u0913');
  99. text = text.replace(/\u094a/g, '\u094b');
  100. // Replace n~ with n.
  101. text = text.replace(/\u0929/g, '\u0928');
  102. // Replace R with r.
  103. text = text.replace(/\u0931/g, '\u0930');
  104. // Replace zh with L (to handle tamil -> devanagari)
  105. text = text.replace(/\u0934/g, '\u0933');
  106. return text;
  107. }
  108.  
  109. var _Scripts = {
  110. devanagari : new _ScriptInfo(0x0900, 0x097f, _pp_devanagari),
  111. // bengali : new _ScriptInfo(0x0980, 0x09ff),
  112. // gurmukhi : new _ScriptInfo(0x0A00, 0x0A7f),
  113. // gujarati : new _ScriptInfo(0x0A80, 0x08ff),
  114. // oriya : new _ScriptInfo(0x0B00, 0x0B7f),
  115. tamil : new _ScriptInfo(0x0B80, 0x0Bff, _pp_tamil),
  116. // telugu : new _ScriptInfo(0x0C00, 0x0C7f),
  117. // kannadam : new _ScriptInfo(0x0C80, 0x0Cff),
  118. // malayalam : new _ScriptInfo(0x0D00, 0x0D7),
  119. };
  120.  
  121. /*
  122. * Create a script metadata object.
  123. * s,e: Unicode values for the range of characters for this script.
  124. * pp_function: Function called with converted Unicode data
  125. * to perform any additional processing (typically to handle
  126. * commonly used sloppy text).
  127. */
  128. function _ScriptInfo(s, e, pp_function) {
  129. this.start = s;
  130. this.end = e;
  131. this.l2uregex = null;
  132. this.pp_function = pp_function;
  133. };
  134.  
  135. function get_scripts() {
  136. return _Scripts;
  137. }
  138. // END itranslit_data.js
  139.  
  140. // ====================================================================
  141.  
  142. // BEGIN itranslit.js.
  143.  
  144. const Encodings = {hk: 'Harvard-Kyoto', generic: 'Generic'};
  145. const Mappings = {
  146. vows: { // Vowels.
  147. COMMON: {
  148. a: 0x05, A: 0x06, i: 0x07, I: 0x08, u: 0x09,
  149. U: 0x0a, ai: 0x10, au: 0x14,
  150. },
  151. generic: {
  152. aa: 0x6, ee: 0x08, oo: 0x0a,
  153. e: 0x0e, E: 0x0f, o: 0x12, O: 0x13,
  154. },
  155. hk: {
  156. R: 0x0b, RR: 0x60, lR: 0x0c, lRR: 0x61,
  157. e: 0x0f, E: 0x0f, o: 0x13, O: 0x13,
  158. }
  159. },
  160. mods: { // Consonant modifiers corr to vowels.
  161. COMMON: {
  162. a: null, A: 0x3e, i: 0x3f, I: 0x40,
  163. u: 0x41, U: 0x42, ai: 0x48, au: 0x4c,
  164. },
  165. generic: {
  166. aa: 0x3e, ee: 0x40, oo: 0x42,
  167. e: 0x46, E: 0x47, o: 0x4a, O: 0x4b,
  168. },
  169. hk: {
  170. R: 0x43, RR: 0x44, lR: 0x62, lRR: 0x63,
  171. e: 0x47, E: 0x47, o: 0x4b, O: 0x4b,
  172. }
  173. },
  174. specialmods: { // Can be combined with both vowels and consants.
  175. COMMON: {
  176. },
  177. generic: {
  178. },
  179. hk: {
  180. M: 0x02
  181. }
  182. },
  183. cons: { // Consonants.
  184. COMMON: {
  185. k: 0x15, kh: 0x16, g: 0x17, gh: 0x18, G: 0x19,
  186. c: 0x1a, ch: 0x1b, j: 0x1c, jh: 0x1d, J: 0x1e,
  187. T: 0x1f, Th: 0x20, D: 0x21, Dh: 0x22, N: 0x23,
  188. t: 0x24, th: 0x25, d: 0x26, dh: 0x27, n: 0x28,
  189. p: 0x2a, ph: 0x2b, f: 0x2b, b: 0x2c, bh: 0x2d, m: 0x2e,
  190. y: 0x2f, r: 0x30, l: 0x32, L: 0x33, v: 0x35, w: 0x35, h: 0x39,
  191. },
  192. generic: {
  193. '~g': 0x19, '~j': 0x1e,
  194. '~n': 0x29, /* tamil small-na */
  195. R: 0x31, /* tamil ra */
  196. z: 0x34, zh: 0x34, /* tamil zh */
  197. sh: 0x36, Sh: 0x37, s: 0x38, h: 0x39,
  198. },
  199. hk: {
  200. z: 0x36, S: 0x37, s: 0x38, h: 0x39,
  201. }
  202. },
  203. others: { // Miscellaneous. These don't combine with anything.
  204. COMMON: {
  205. q: 0x3, '.h': 0x3, H: 0x3,
  206. OM: 0x50, AUM: 0x50, '.': 0x64, '\\\\':0x65, '\\': 0x64,
  207. '|':0x64, '||': 0x65,
  208. '0': 0x66, '1': 0x67, '2': 0x68, '3': 0x69, '4': 0x6a, '5': 0x6b, '6': 0x6c,
  209. '7': 0x6d, '8': 0x6e, '9': 0x6f,
  210. },
  211. generic: {
  212. '.a': 0x3d,
  213. },
  214. hk: {
  215. "'": 0x3d,
  216. }
  217. }
  218. };
  219.  
  220. const _ShortCode = 0x4d;
  221.  
  222. var _IVows = {}
  223. var _IMods = {};
  224. var _ISpecialMods = {};
  225. var _ICons = {};
  226. var _IOthers = {};
  227.  
  228. var _IChars = {};
  229.  
  230. // Convert characters in from_script
  231. // (or all) from one Indic unicode script to another.
  232. function u2u(/* to_script, text, from_script */) {
  233. if (arguments.length < 2) {
  234. return "";
  235. }
  236. var to_script = arguments[0];
  237. var scripts = get_scripts();
  238. var to_start = scripts[to_script].start;
  239. var text = arguments[1];
  240. var script_names = new Array();
  241. if (arguments.length > 2) {
  242. for (var i = 2; i < arguments.length; ++i)
  243. script_names.concat(arguments[i]);
  244. } else {
  245. script_names = Object.keys(get_scripts());
  246. }
  247.  
  248. var starts = new Array();
  249. for (var i in script_names) {
  250. starts.push(scripts[script_names[i]].start);
  251. }
  252. var out = new String();
  253. for (var i = 0; i < text.length; ++i) {
  254. var c = text.charCodeAt(i);
  255. if (starts.indexOf(c & 0xff80) >= 0)
  256. out = out.concat(String.fromCharCode(to_start + (c&0x7f)));
  257. else
  258. out = out.concat(text.charAt(i));
  259. }
  260. return _pp(to_script, out);
  261. }
  262.  
  263. // Convert from Indic unicode to latin.
  264. function u2l(text, to_encoding = 'generic') {
  265. var itext = "";
  266. for (var i = 0; i < text.length; ++i) {
  267. var ucode = text.charCodeAt(i);
  268. if (ucode <= 0x7f) {
  269. itext += text.charAt(i);
  270. continue;
  271. }
  272. var ichar = null;
  273. ucode = ucode & 0x7f;
  274. var con = _getIChar(to_encoding, ucode, _ICons);
  275. if (con != null) {
  276. var nextcode = text.charCodeAt(++i) &0x7f;
  277. if (nextcode == _ShortCode)
  278. ichar = con;
  279. else {
  280. var mod = _getIChar(to_encoding, nextcode, _IMods, _ISpecialMods);
  281. if (mod != null)
  282. ichar = con + mod;
  283. else {
  284. ichar = con + 'a';
  285. --i;
  286. }
  287. }
  288. } else {
  289. var vow = _getIChar(to_encoding, ucode, _IVows);
  290. if (vow != null)
  291. ichar = vow;
  292. else {
  293. var special = _getIChar(to_encoding, ucode, _IOthers);
  294. if (special != null)
  295. ichar = special;
  296. }
  297. }
  298. if (ichar != null) {
  299. itext += ichar;
  300. } else {
  301. }
  302. }
  303. return itext;
  304. }
  305.  
  306. // Convert latin to Indic Unicode
  307. function l2u(text, to_script, from_encoding = 'generic') {
  308. // FIXME: For now, hardcode.
  309. from_encoding = (to_script == 'tamil') ? 'generic' : 'hk';
  310. // END FIXME
  311. var pat = "";
  312. var pref = '';
  313. var to_info = get_scripts()[to_script];
  314. encodingIChars = _IChars[from_encoding];
  315. var regex = to_info.l2uregex;
  316. if (regex == null) {
  317. for (var ichar in encodingIChars) {
  318. ichar = ichar.replace(/\\/g, '\\\\');
  319. ichar = ichar.replace(/\./g, '\\.');
  320. ichar = ichar.replace(/\^/g, '\\^');
  321. ichar = ichar.replace(/\|/g, '\\|');
  322. pat += pref + ichar;
  323. pref = '|';
  324. }
  325. regex = new RegExp('(' + pat + ')', 'gm');
  326. to_info.l2uregex = regex;
  327. }
  328. var to_start = to_info.start;
  329. return _pp(to_script, text.replace(regex, function(m) {
  330. return (encodingIChars[m] != null) ?
  331. _get_chars(encodingIChars[m], to_start) :
  332. m;
  333. }), from_encoding);
  334. }
  335.  
  336. function _getIChar() {
  337. var encoding = arguments[0];
  338. var ucode = arguments[1];
  339. for (var i = 2; i < arguments.length; ++i) {
  340. var chars = arguments[i][encoding];
  341. for (var ichar in chars) {
  342. if (chars[ichar] == ucode)
  343. return ichar;
  344. }
  345. }
  346. return null;
  347. }
  348.  
  349. function _get_chars(codes, start) {
  350. var out = new String();
  351. for (var j = 0; j < codes.length; ++j) {
  352. out = out.concat(String.fromCharCode(start + codes[j]));
  353. }
  354. return out;
  355. }
  356.  
  357. function _pp(to_script, text, from_encoding) {
  358. var f = get_scripts()[to_script].pp_function;
  359. return (f != null) ? f(text, from_encoding) : text;
  360. }
  361.  
  362. function _init() {
  363. for (encoding in Encodings) {
  364. _IVows[encoding] = Object.assign({}, Mappings['vows']['COMMON'], Mappings['vows'][encoding]);
  365. _IMods[encoding] = Object.assign({}, Mappings['mods']['COMMON'], Mappings['mods'][encoding]);
  366. _ICons[encoding] = Object.assign({}, Mappings['cons']['COMMON'], Mappings['cons'][encoding]);
  367. _ISpecialMods[encoding] = Object.assign({}, Mappings['specialmods']['COMMON'], _ISpecialMods[encoding]);
  368. _IOthers[encoding] = Object.assign({}, Mappings['others']['COMMON'], Mappings['others'][encoding]);
  369. _init_encoding(encoding);
  370. }
  371. }
  372.  
  373. function _init_encoding(encoding) {
  374. _IChars[encoding] = {};
  375. for (var vow in _IVows[encoding]) {
  376. _IChars[encoding][vow] = [ _IVows[encoding][vow] ];
  377. for (var smod in _ISpecialMods[encoding]) {
  378. _IChars[encoding][vow + smod] = (_ISpecialMods[encoding][smod] != null ) ?
  379. [_IVows[encoding][vow], _ISpecialMods[encoding][smod]] :
  380. [_IVows[encoding][vow]];
  381. }
  382. }
  383.  
  384. for (var cons in _ICons[encoding]) {
  385. _IChars[encoding][cons] = [ _ICons[encoding][cons], _ShortCode];
  386. for (var mod in _IMods[encoding]) {
  387. _IChars[encoding][cons + mod] = (_IMods[encoding][mod] != null ) ?
  388. [_ICons[encoding][cons], _IMods[encoding][mod]] :
  389. [_ICons[encoding][cons]];
  390. for (var smod in _ISpecialMods[encoding]) {
  391. _IChars[encoding][cons + mod + smod] = (_IMods[encoding][mod] != null ) ?
  392. [_ICons[encoding][cons], _IMods[encoding][mod], _ISpecialMods[encoding][smod]] :
  393. [_ICons[encoding][cons], _ISpecialMods[encoding][smod]];
  394. }
  395. }
  396. }
  397.  
  398. for (var other in _IOthers[encoding]) {
  399. _IChars[encoding][other] = [ _IOthers[encoding][other]];
  400. }
  401.  
  402. _IChars[encoding] = _sortMap(_IChars[encoding], function(a,b) {
  403. return b.length - a.length;
  404. });
  405. }
  406.  
  407. function _sortMap(m, f) {
  408. var keys = [];
  409. for (key in m) {
  410. keys.push(key);
  411. }
  412. keys.sort(f);
  413. var new_m = {};
  414. for (key in keys) {
  415. new_m[keys[key]] = m[keys[key]];
  416. }
  417. return new_m;
  418. }
  419.  
  420. _init();
  421.  
  422. // END itranslit.js
  423.  
  424. // ====================================================================
  425.  
  426. // BEGIN itmain.user.js
  427.  
  428. var body;
  429. var toggler;
  430.  
  431. var SelectStyle = {
  432. border: '1px solid #aaaae0',
  433. backroundColor: '#fcfcff',
  434. whiteSpace: 'normal',
  435. };
  436.  
  437. var TranslitStyle = {
  438. whiteSpace: 'pre-wrap',
  439. };
  440.  
  441. var ButtonStyle = {
  442. lineHeight: 1.5,
  443. fontWeight: 'bold',
  444. color: 'blue',
  445. marginLeft: '5px',
  446. };
  447.  
  448. var CloseButtonStyle = {
  449. lineHeight: 1.5,
  450. fontWeight: 'bold',
  451. color: 'red',
  452. marginLeft: '5px',
  453. };
  454.  
  455. var DisabledButtonStyle = {
  456. lineHeight: 1.5,
  457. fontWeight: 'normal',
  458. color: '#888888',
  459. marginLeft: '5px',
  460. };
  461.  
  462. var TogglerEnabledStyle = {
  463. color: 'green',
  464. };
  465.  
  466. var TogglerDisabledStyle = {
  467. color: 'red',
  468. };
  469.  
  470. const ATTR_SEEN_BEFORE = "seen";
  471. var ATTR_ENABLED = 'intranslit_enabled_' + window.location.host;
  472.  
  473. function getSelectedText(trim) {
  474. var text =
  475. (window.getSelection) ? window.getSelection().toString() :
  476. (document.getSelection) ? document.getSelection().toString() :
  477. (document.selection) ? document.selection.createRange().text : null;
  478. if (trim && text != null)
  479. text = text.trim();
  480. return text;
  481. }
  482.  
  483. function style(el, css) {
  484. for (var k in css)
  485. el.style[k] = css[k];
  486. return el;
  487. }
  488.  
  489. function createToggler() {
  490. toggler = document.createElement('div');
  491. toggler.id = 'itranslit_toggle';
  492. toggler.title = 'Click to enable/disable transliteration';
  493. style(toggler, {
  494. cursor: 'pointer',
  495. 'float': 'right',
  496. padding: '0px 15px 0px',
  497. fontWeight : 'bold',
  498. backgroundColor: 'transparent',
  499. position: 'fixed',
  500. right: '0px',
  501. bottom: '35px',
  502. width: '10px',
  503. zIndex: '99999',
  504. fontSize: '20px',
  505. });
  506. body.appendChild(toggler);
  507. toggler.innerHTML = '&diams;';
  508. }
  509.  
  510. function getEnabled() {
  511. v = GM_getValue(ATTR_ENABLED, false);
  512. return v;
  513. }
  514.  
  515. function setEnabled(v) {
  516. GM_setValue(ATTR_ENABLED, v);
  517. style(toggler, v ? TogglerEnabledStyle : TogglerDisabledStyle);
  518. }
  519.  
  520. function transliterate(target) {
  521. var textScript;
  522.  
  523. if (haveSeenBefore(target))
  524. return;
  525.  
  526. var content = getContent(target);
  527. textScript = getTextScript(content);
  528.  
  529. resetChildren(target);
  530. // Save old content.
  531. var oldHTML = target.innerHTML;
  532.  
  533. // Add buttons at the top of the section.
  534. var newId = new Date().getTime();
  535. var newHTML =
  536. '<div>' +
  537. '<div>';
  538. if (textScript == 'latin') {
  539. // FIXME: Get list of encodings from metadata instead of
  540. // hardcoding here.
  541. newHTML +=
  542. '<div style="visibility:hidden; margin:10px 0 0 0; line-height:1.5; float:left;">' +
  543. '<span>Input Encoding: </span>' +
  544. '<input type="radio" name="'+newId+'_lscript" value="generic"/>&nbsp;Generic' +
  545. '<input checked="checked" style="margin-left: 10px" type="radio" name="'+newId+'_lscript" value="hk"/>&nbsp;HK' +
  546. '</div>';
  547. }
  548. newHTML += '<div style="float:right;">';
  549. var allButtons = [];
  550. scripts = get_scripts();
  551. for (var script in scripts) {
  552. var bid = 'do_' + script + '_' + newId;
  553. allButtons.push(bid);
  554. newHTML +=
  555. '<input title="Transliterate into '+ script + '" type="button" id="' + bid +
  556. '" data-script="' + script +
  557. '" value="' + String.fromCharCode(scripts[script].start + 5) + '"/>';
  558. }
  559.  
  560. newHTML +=
  561. '<input title="Close" type="button" id="close_' + newId + '" value="x"/>' +
  562. '</div>' + // end opts_out
  563. '</div>' + // end opts
  564. '<br/>' +
  565. '<div style="padding:5px; clear:both" id="text_' + newId + '">' +
  566. oldHTML +
  567. '</div>' +
  568. '</div>';
  569.  
  570. target.innerHTML = newHTML;
  571. var newTarget = document.getElementById('text_' + newId);
  572. style(newTarget, SelectStyle);
  573. var radios = document.getElementsByName(newId+'_lscript');
  574.  
  575. // Add click handlers for the buttons.
  576. for (var script in scripts) {
  577. (function(l) {
  578. var bid = 'do_' + l + '_' + newId;
  579. var button = document.getElementById(bid);
  580. style(button, ButtonStyle);
  581. button.addEventListener('click', function(ee) {
  582. if (button.value != 'x') {
  583. // Transliterate.
  584. var convertedText;
  585. if (textScript == 'latin') {
  586. // latin -> Indic Unicode.
  587. inputOpt = radios[0].checked ? radios[0].value : radios[1].value;
  588. convertedText = l2u(content, l, inputOpt);
  589. } else {
  590. // Indic Unicode -> latin.
  591. /*
  592. * Disabled for now.
  593. if (textScript == button.getAttribute('data-script')) {
  594. convertedText = u2l(content);
  595. } else {
  596. */
  597. // Indic Unicode => Indic Unicode.
  598. convertedText = u2u(l, content);
  599. /*
  600. }
  601. */
  602. }
  603. newTarget.innerHTML = convertedText;
  604. style(newTarget, TranslitStyle);
  605. button.value = 'x';
  606. button.title = 'Revert';
  607. for (i in allButtons) {
  608. if (allButtons[i] != bid) {
  609. document.getElementById(allButtons[i]).disabled = true;
  610. style(document.getElementById(allButtons[i]),
  611. DisabledButtonStyle);
  612. }
  613. }
  614. for (var r in radios) {
  615. radios[r].disabled = true;
  616. }
  617. } else {
  618. // Revert.
  619. newTarget.innerHTML = oldHTML;
  620. style(newTarget, SelectStyle);
  621. button.value = String.fromCharCode(scripts[l].start+5);
  622. button.title = 'Transliterate into ' + l;
  623. for (i in allButtons) {
  624. if (allButtons[i] != bid) {
  625. document.getElementById(allButtons[i]).disabled = false;
  626. }
  627. style(document.getElementById(allButtons[i]), ButtonStyle);
  628. }
  629. for (var r in radios) {
  630. radios[r].disabled = false;
  631. }
  632. }
  633. }, false);
  634. })(script);
  635. }
  636. var closeLit = document.getElementById('close_' + newId);
  637. style(closeLit, CloseButtonStyle);
  638. closeLit.style.color = 'red';
  639. closeLit.addEventListener('click', function(ee) {
  640. target.innerHTML = oldHTML;
  641. clearSeenBefore(target);
  642. }, false);
  643. // Mark that we've seen this section, so we don't add buttons
  644. // more than once.
  645. setSeenBefore(target);
  646. }
  647.  
  648. /*
  649. * Return the script of the given text.
  650. * null: Unrecognized.
  651. */
  652. function getTextScript(content) {
  653. var script = null;
  654. if (content) {
  655. content = content
  656. .trim()
  657. .replace(/ +/g, ' ')
  658. .replace(/[\r\n]+/g, '\n');
  659. if (content.match(/[\u0900-\u0d7f]/)) {
  660. var charCode = 0;
  661. for (var i = 0; i < content.length; ++i) {
  662. charCode = content.charCodeAt(i);
  663. if (charCode >= 0x0900) break;
  664. }
  665. charCode &= 0xff80;
  666. var scripts = get_scripts();
  667. for (i in scripts) {
  668. if (scripts[i].start == charCode) {
  669. script = i;
  670. break;
  671. }
  672. }
  673. } else if (content.match(/[A-Za-z]/)) {
  674. script = 'latin';
  675. }
  676. }
  677. return script;
  678. }
  679.  
  680. function getContent(t) {
  681. var content = t.innerText;
  682. return content;
  683. }
  684.  
  685. function setSeenBefore(t) {
  686. t.setAttribute(ATTR_SEEN_BEFORE, '1');
  687. }
  688.  
  689. function clearSeenBefore(t) {
  690. t.removeAttribute(ATTR_SEEN_BEFORE);
  691. }
  692.  
  693. function haveSeenBefore(t) {
  694. var v = false;
  695. while (t) {
  696. if (t.getAttribute && t.getAttribute(ATTR_SEEN_BEFORE)) {
  697. v = true;
  698. break;
  699. }
  700. t = t.parentNode;
  701. }
  702. return v;
  703. }
  704.  
  705. function resetChildren(t) {
  706. var ev = document.createEvent('MouseEvents');
  707. ev.initEvent("click", true, true);
  708. for (var i = 0; i < t.childNodes.length; ++i) {
  709. var ct = t.childNodes[i];
  710. if (ct.id && ct.id.match(/close_\d+/) && ct.nodeName == 'INPUT')
  711. ct.dispatchEvent(ev);
  712. else if (t.childNodes)
  713. resetChildren(ct);
  714. }
  715. }
  716.  
  717. function handleClick(e) {
  718. if (!getEnabled() || e.button != 0)
  719. return;
  720. var target = (e.target || e.srcElement);
  721. if (!target || target == body || target == toggler)
  722. return;
  723. var n = target;
  724. while (n && n != body) {
  725. if (n.nodeName == 'A' || n.nodeName == 'INPUT' ||
  726. n.nodeName == 'TEXTAREA' || n.nodeName == 'FORM') {
  727. return;
  728. }
  729. n = n.parentNode;
  730. }
  731. transliterate(target);
  732. }
  733.  
  734. // Main.
  735.  
  736. body = document.getElementsByTagName('body')[0];
  737.  
  738. // Create the feature toggler.
  739. createToggler();
  740. setEnabled(getEnabled());
  741. toggler.addEventListener('click', function(e) {
  742. setEnabled(getEnabled() === false);
  743. }, false);
  744.  
  745. // Init click listener.
  746. document.addEventListener('mouseup', handleClick, false);
  747.  
  748. // END itmain.user.js
  749.  
  750. })();