Greasy Fork 支持简体中文。

fixbib

Fix common bib errors.

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