fixbib

Fix common bib errors.

当前为 2014-12-27 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name fixbib
  3. // @namespace https://github.com/alick9188
  4. // @description Fix common bib errors.
  5. // @include http://scholar.google.com/scholar.bib*
  6. // @include http://ieeexplore.ieee.org/xpl/downloadCitations
  7. // @include /^https?://dl\.acm\.org/citation\.cfm.*$/
  8. // @include /^https?://dl\.acm\.org/exportformats\.cfm.*$/
  9. // @version 1.3
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. // Title case function via https://raw.github.com/gouch/to-title-case/master/to-title-case.js
  15. /*
  16. * To Title Case 2.1 – http://individed.com/code/to-title-case/
  17. * Copyright © 2008–2013 David Gouch. Licensed under the MIT License.
  18. */
  19.  
  20. String.prototype.toTitleCase = function(){
  21. var smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i;
  22.  
  23. return this.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function(match, index, title){
  24. if (index > 0 && index + match.length !== title.length &&
  25. match.search(smallWords) > -1 && title.charAt(index - 2) !== ":" &&
  26. (title.charAt(index + match.length) !== '-' || title.charAt(index - 1) === '-') &&
  27. title.charAt(index - 1).search(/[^\s-]/) < 0) {
  28. return match.toLowerCase();
  29. }
  30.  
  31. if (match.substr(1).search(/[A-Z]|\../) > -1) {
  32. return match;
  33. }
  34.  
  35. return match.charAt(0).toUpperCase() + match.substr(1);
  36. });
  37. };
  38. // Title case function ended.
  39.  
  40. var booktitle_abbrev_dict = {
  41. 'Proceedings of the' : 'Proc.',
  42. 'Annals': 'Ann.',
  43. 'Annual': 'Annu.',
  44. 'International' : 'Int.',
  45. 'Conference' : 'Conf.',
  46. 'Symposium' : 'Symp.',
  47. 'on ' : '',
  48. 'First' : '1st',
  49. 'Second': '2nd',
  50. 'Third' : '3rd',
  51. 'Fourth': '4th',
  52. 'Fifth' : '5th',
  53. 'Sixth' : '6th',
  54. 'Seventh' : '7th',
  55. 'Eighth': '8th',
  56. 'Ninth' : '9th'
  57. };
  58. function abbrevBooktitle (booktitle, dict) {
  59. var output = booktitle;
  60. for (key in dict) {
  61. output = output.replace(key, dict[key]);
  62. }
  63. return output;
  64. }
  65.  
  66. var sites = {
  67. UNKNOWN : -1,
  68. GOOGLE_SCHOLAR : 0,
  69. IEEE_XPLORE : 1,
  70. ACM_DL : 2,
  71. ACM_DL_WEB : 3
  72. };
  73.  
  74. var site = sites.UNKNOWN;
  75. if (location.hostname === 'scholar.google.com') {
  76. site = sites.GOOGLE_SCHOLAR;
  77. } else if (location.hostname === 'dl.acm.org') {
  78. if (location.pathname === '/citation.cfm') {
  79. site = sites.ACM_DL_WEB;
  80. } else if (location.pathname === '/exportformats.cfm') {
  81. site = sites.ACM_DL;
  82. }
  83. } else if (location.hostname === 'ieeexplore.ieee.org') {
  84. site = sites.IEEE_XPLORE;
  85. }
  86.  
  87. // For ACM DL webpage, modify the BibTeX link to open in a new tab.
  88. if (site === sites.ACM_DL_WEB) {
  89. var ret = /id=(\d+\.)?(\d+)/.exec(location.search);
  90. if (ret !== null) {
  91. var id = ret[2];
  92. var newurl = 'http://dl.acm.org/exportformats.cfm?id=' + id + '&expformat=bibtex';
  93. var s = Ext.select('#divtools a:contains(BibTeX)');
  94. s.elements[0].href = newurl;
  95. }
  96. return;
  97. }
  98.  
  99. var pres, pre;
  100. var npre = 0;
  101. var orig = '', fixed = '';
  102. if (site === sites.GOOGLE_SCHOLAR || site === sites.ACM_DL) {
  103. pres = document.getElementsByTagName('pre');
  104. npre = pres.length;
  105. } else if (site === sites.IEEE_XPLORE) {
  106. npre = 1;
  107. orig = document.body.innerHTML.replace(/<br>\s+/g, '');
  108. }
  109.  
  110. // We intentionally count from the last one, to ensure
  111. // newpre not breaks the reference positions of pre in pres.
  112. for (var i = npre - 1; i >= 0; --i) {
  113. if (site === sites.GOOGLE_SCHOLAR || site === sites.ACM_DL) {
  114. pre = pres[i];
  115. orig = pre.innerHTML;
  116. }
  117.  
  118. var colored = true;
  119. var cb, ce;
  120. if (colored == true) {
  121. cb = '<span style="color: blue;">';
  122. ce = '</span>';
  123. } else {
  124. cb = ce = '';
  125. }
  126.  
  127. fixed = orig.replace(/([^k])title\s*=\s*{([^}]+)},/, function (match, p1, p2, offset, string) {
  128. var p = p2.toTitleCase();
  129. if (p === p2) {
  130. return match;
  131. } else {
  132. return p1 + 'title={' + cb + p + ce + '},';
  133. }
  134. }).replace(/journal\s*=\s*{([^,}]+), ([^}]*)},/, function (match, p1, p2, offset, string) {
  135. // Fix journal name.
  136. return 'journal={' + cb + p2 + ' ' + p1 + ce + '},';
  137. }).replace(/booktitle\s*=\s*{([^}]+)},/, function (match, p1, offset, string) {
  138. // Fix booktitle field.
  139. // Check for a period. If so, transpose the two parts around the *last* period.
  140. var res = p1.replace(/(.*)\.\s*(.*)/, '$2 $1');
  141. if (res === p1) {
  142. // Check for a comma.
  143. res = p1.replace(/(.*),\s*(.*)/, '$2 $1');
  144. }
  145. res = res.toTitleCase();
  146. res = abbrevBooktitle(res, booktitle_abbrev_dict);
  147. if (res === p1) {
  148. return match;
  149. } else {
  150. return 'booktitle={' + cb + res + ce + '},';
  151. }
  152. }).replace(/month\s*=\s*{\s*(\w+)\s*},/, function (match, p1, offset, string) {
  153. // Use three-letter month macro.
  154. return 'month=' + cb + p1.substr(0, 3).toLowerCase() + ce + ',';
  155. }).replace(/pages\s*=\s*{\s*(\d+)\s*-\s*(\d+)([^}]*)},/, function (match, p1, p2, p3, offset, string) {
  156. // Use en-dash to separate page numbers.
  157. return 'pages={' + cb + p1 + '--' + p2 + p3 + ce + '},';
  158. }).replace(/([A-Z]\.)([A-Z]\.)/g, cb + '$1 $2' + ce);
  159. // Separate first name intial and middle name initial in author names.
  160.  
  161. if (site === sites.ACM_DL) {
  162. fixed = fixed.replace(/url\s*=\s*{http:\/\/doi\.acm\.org[^}]*},\s*/, '');
  163. fixed = fixed.replace(/series\s*=\s*{[^}]*},\s*/, '');
  164. fixed = fixed.replace(/address\s*=\s*{[^}]*},\s*/, '').replace(/location\s*=\s*/,'address = ');
  165. }
  166.  
  167. // Quit if nothing is changed.
  168. if (fixed === orig) {
  169. continue;
  170. }
  171.  
  172. // Create new elements on page.
  173. if (site === sites.GOOGLE_SCHOLAR || site === sites.IEEE_XPLORE || site === sites.ACM_DL) {
  174. var newpre = document.createElement('pre');
  175. newpre.setAttribute('contentEditable', 'true');
  176. newpre.innerHTML = fixed;
  177. newpre.style = 'background-color: #EEEEEE; border-width: 0px;';
  178.  
  179. if (site === sites.GOOGLE_SCHOLAR || site === sites.ACM_DL) {
  180. if (pre.nextSibling) {
  181. // Note the reverse order of newp and newpre with insertBefore.
  182. pre.parentNode.insertBefore(newpre, pre.nextSibling);
  183. } else {
  184. pre.parentNode.appendChild(newpre);
  185. }
  186. } else {
  187. document.body.appendChild(newpre);
  188. }
  189. }
  190. }
  191. })();
  192.  
  193. // vim: set et sw=2 sts=2: