// ==UserScript==
// @name fixbib
// @namespace https://github.com/alick9188
// @description Fix common bib errors.
// @include http://scholar.google.com/scholar.bib*
// @include https://scholar.googleusercontent.com/*
// @include http://ieeexplore.ieee.org/xpl/downloadCitations
// @include /^https?://dl\.acm\.org/citation\.cfm.*$/
// @include /^https?://dl\.acm\.org/exportformats\.cfm.*$/
// @version 1.4
// @grant none
// ==/UserScript==
(function () {
// Title case function via https://raw.github.com/gouch/to-title-case/master/to-title-case.js
/*
* To Title Case 2.1 – http://individed.com/code/to-title-case/
* Copyright © 2008–2013 David Gouch. Licensed under the MIT License.
*/
String.prototype.toTitleCase = function(){
var smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i;
return this.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, function(match, index, title){
if (index > 0 && index + match.length !== title.length &&
match.search(smallWords) > -1 && title.charAt(index - 2) !== ":" &&
(title.charAt(index + match.length) !== '-' || title.charAt(index - 1) === '-') &&
title.charAt(index - 1).search(/[^\s-]/) < 0) {
return match.toLowerCase();
}
if (match.substr(1).search(/[A-Z]|\../) > -1) {
return match;
}
return match.charAt(0).toUpperCase() + match.substr(1);
});
};
// Title case function ended.
var booktitle_abbrev_dict = {
'Proceedings of the' : 'Proc.',
'Annals': 'Ann.',
'Annual': 'Annu.',
'International' : 'Int.',
'Conference' : 'Conf.',
'Symposium' : 'Symp.',
'on ' : '',
'First' : '1st',
'Second': '2nd',
'Third' : '3rd',
'Fourth': '4th',
'Fifth' : '5th',
'Sixth' : '6th',
'Seventh' : '7th',
'Eighth': '8th',
'Ninth' : '9th'
};
function abbrevBooktitle (booktitle, dict) {
var output = booktitle;
for (key in dict) {
output = output.replace(key, dict[key]);
}
return output;
}
var sites = {
UNKNOWN : -1,
GOOGLE_SCHOLAR : 0,
IEEE_XPLORE : 1,
ACM_DL : 2,
ACM_DL_WEB : 3
};
var site = sites.UNKNOWN;
if (location.hostname === 'scholar.google.com' ||
location.hostname === 'scholar.googleusercontent.com') {
site = sites.GOOGLE_SCHOLAR;
} else if (location.hostname === 'dl.acm.org') {
if (location.pathname === '/citation.cfm') {
site = sites.ACM_DL_WEB;
} else if (location.pathname === '/exportformats.cfm') {
site = sites.ACM_DL;
}
} else if (location.hostname === 'ieeexplore.ieee.org') {
site = sites.IEEE_XPLORE;
}
// For ACM DL webpage, modify the BibTeX link to open in a new tab.
if (site === sites.ACM_DL_WEB) {
var ret = /id=(\d+\.)?(\d+)/.exec(location.search);
if (ret !== null) {
var id = ret[2];
var newurl = 'http://dl.acm.org/exportformats.cfm?id=' + id + '&expformat=bibtex';
var s = Ext.select('#divtools a:contains(BibTeX)');
s.elements[0].href = newurl;
}
return;
}
var pres, pre;
var npre = 0;
var orig = '', fixed = '';
if (site === sites.GOOGLE_SCHOLAR || site === sites.ACM_DL) {
pres = document.getElementsByTagName('pre');
npre = pres.length;
} else if (site === sites.IEEE_XPLORE) {
npre = 1;
orig = document.body.innerHTML.replace(/<br>\s+/g, '');
}
// We intentionally count from the last one, to ensure
// newpre not breaks the reference positions of pre in pres.
for (var i = npre - 1; i >= 0; --i) {
if (site === sites.GOOGLE_SCHOLAR || site === sites.ACM_DL) {
pre = pres[i];
orig = pre.innerHTML;
}
var colored = true;
var cb, ce;
if (colored == true) {
cb = '<span style="color: blue;">';
ce = '</span>';
} else {
cb = ce = '';
}
fixed = orig.replace(/([^k])title\s*=\s*{([^}]+)},/, function (match, p1, p2, offset, string) {
var p = p2.toTitleCase();
if (p === p2) {
return match;
} else {
return p1 + 'title={' + cb + p + ce + '},';
}
}).replace(/journal\s*=\s*{([^,}]+), ([^}]*IEEE[^}]*)},/, function (match, p1, p2, offset, string) {
// Fix journal name.
return 'journal={' + cb + p2 + ' ' + p1 + ce + '},';
}).replace(/booktitle\s*=\s*{([^}]+)},/, function (match, p1, offset, string) {
// Fix booktitle field.
// Check for a period. If so, transpose the two parts around the *last* period.
var res = p1.replace(/(.*)\.\s*(.*)/, '$2 $1');
if (res === p1) {
// Check for a comma.
res = p1.replace(/(.*),\s*(.*)/, '$2 $1');
}
res = res.toTitleCase();
res = abbrevBooktitle(res, booktitle_abbrev_dict);
if (res === p1) {
return match;
} else {
return 'booktitle={' + cb + res + ce + '},';
}
}).replace(/month\s*=\s*{\s*(\w+)\s*},/, function (match, p1, offset, string) {
// Use three-letter month macro.
return 'month=' + cb + p1.substr(0, 3).toLowerCase() + ce + ',';
}).replace(/pages\s*=\s*{\s*(\d+)\s*-\s*(\d+)([^}]*)},/, function (match, p1, p2, p3, offset, string) {
// Use en-dash to separate page numbers.
return 'pages={' + cb + p1 + '--' + p2 + p3 + ce + '},';
}).replace(/([A-Z]\.)([A-Z]\.)/g, cb + '$1 $2' + ce);
// Separate first name intial and middle name initial in author names.
if (site === sites.ACM_DL) {
fixed = fixed.replace(/url\s*=\s*{http:\/\/doi\.acm\.org[^}]*},\s*/, '');
fixed = fixed.replace(/series\s*=\s*{[^}]*},\s*/, '');
fixed = fixed.replace(/address\s*=\s*{[^}]*},\s*/, '').replace(/location\s*=\s*/,'address = ');
}
// Quit if nothing is changed.
if (fixed === orig) {
continue;
}
// Create new elements on page.
if (site === sites.GOOGLE_SCHOLAR || site === sites.IEEE_XPLORE || site === sites.ACM_DL) {
var newpre = document.createElement('pre');
newpre.setAttribute('contentEditable', 'true');
newpre.innerHTML = fixed;
newpre.style = 'background-color: #EEEEEE; border-width: 0px;';
if (site === sites.GOOGLE_SCHOLAR || site === sites.ACM_DL) {
if (pre.nextSibling) {
// Note the reverse order of newp and newpre with insertBefore.
pre.parentNode.insertBefore(newpre, pre.nextSibling);
} else {
pre.parentNode.appendChild(newpre);
}
} else {
document.body.appendChild(newpre);
}
}
}
})();
// vim: set et sw=2 sts=2: