// ==UserScript==
// @name wiki-reference
// @namespace torvin
// @include https://www.ncbi.nlm.nih.gov/pubmed/*
// @include http://www.ncbi.nlm.nih.gov/pubmed/*
// @include http://adsabs.harvard.edu/abs/*
// @include http://adsabs.harvard.edu/doi/*
// @include http://ufn.ru/ru/articles/*
// @include http://books.google.*/books?*
// @include http://www.sciencedirect.com/science/article/*
// @include http://gen.lib.rus.ec/scimag/*
// @include http://onlinelibrary.wiley.com/doi/*
// @include http://www.jstor.org/stable/*
// @include http://www.jstor.org/discover/*
// @version 1.5.2
// @description Позволяет генерировать ссылки в формате {{Статья}} и {{книга}} для ру-вики
// @grant GM_xmlhttpRequest
// ==/UserScript==
const templates = {
article: 'Статья',
book: 'книга',
};
var Template = function(name) {
var attrs = [];
this.add = function(name, value) {
attrs.push({
name: name,
value: value
});
return this;
};
var getAttr = function(x) {
return "|" + x.name + (x.value === undefined ? "" : " = " + x.value);
};
this.toWiki = function() {
if (attrs.length == 1)
return "{{" + name + getAttr(attrs[0]) + "}}";
else
return "{{" + name + "\n" + attrs.map(function(x) { return " " + getAttr(x)}).join("\n") + "\n}}";
};
};
var pubmed = {
'автор': {
selector: 'Article > AuthorList > Author',
map: function(node) { return [ node.querySelector('LastName'), node.querySelector('Initials') ] },
mapText: function(nodes) { return new Template('nobr').add(nodes[0] + ' ' + nodes[1].replace(/(.)/g, "$1. ").trim()).toWiki() },
},
'заглавие': {
selector: 'Article > ArticleTitle',
mapText: function(text) { return text.replace(/^(.*?)\.?$/, "$1") },
},
'издание': {
selector: 'Article > Journal > Title',
},
'год': {
selector: 'Article > Journal > JournalIssue > PubDate',
mapText: function(text) { return /^\s*(\d{4})/.exec(text)[1] },
},
'выпуск': {
selector: 'Article > Journal > JournalIssue > Issue',
},
'том': {
selector: 'Article > Journal > JournalIssue > Volume',
},
'страницы': {
selector: 'Article > Pagination > MedlinePgn',
},
'issn': {
selector: 'Article > Journal > ISSN[IssnType=Electronic]',
},
'doi': {
selector: 'ArticleIdList > ArticleId[IdType=doi]',
},
'pmid': {
selector: 'ArticleIdList > ArticleId[IdType=pubmed]',
},
'ссылка': { const: "" },
'ref': { const: "" },
'archiveurl': { const: "" },
'archivedate': { const: "" },
};
var getText = function(node) {
return node instanceof Element ? node.textContent : node;
};
var ajax = function(params) {
setTimeout(function() {
GM_xmlhttpRequest(params)
}, 0);
}
var clone = function(obj) {
var target = {};
for (var i in obj) {
var value = obj[i];
if (value instanceof Function)
;
else if (typeof value == 'string')
;
else
value = clone(value);
target[i] = value;
}
return target;
}
var getWpFromXml = function(name, rules, xml) {
var article = new Template(name);
for(var name in rules) {
var rule = rules[name];
article.add(name, rule.const ||
Array.slice(xml.querySelectorAll(rule.selector)).map(function(node) {
if (rule.map)
node = rule.map(node);
return Array.isArray(node) ? node.map(getText) : getText(node);
}).map(function(item) {
return rule.mapText ? rule.mapText(item) : item;
}).join(rule.separator || ', ')
);
}
return article.toWiki();
};
var Parser = function(sourceText, index, tokens) {
var _match;
var _isEof;
//var _tokenRegex = /(\s*)(\{|\}|,|=|\\\W|\\[\w]+|[^\{\},\\=\s])/g;
var _tokenRegex = new RegExp("(\\s*)(" + tokens.map(function(x) { return x.source || x }).join('|') + ")", 'g');
_tokenRegex.lastIndex = index;
var getToken = function() {
if (_isEof)
throw new Error("EOF");
var index = _tokenRegex.lastIndex;
var res = _tokenRegex.exec(sourceText);
if (!res) {
_isEof = true;
return null;
}
_match = {
match: res[0],
token: res[2],
space: res[1].replace(/\s+/g, ' '),
index: index,
}
}
this.matchAny = function() {
var res = _match;
getToken();
return res;
}
this.match = function(str) {
if (_match.token !== str)
throw new Error("Parser error at pos " + _tokenRegex.lastIndex + ". Expected '" + str + "', found '" + _match.token + "'.");
return this.matchAny();
}
this.matchIgnoreCase = function(str) {
if (_match.token.toUpperCase() !== str.toUpperCase())
throw new Error("Parser error at pos " + _tokenRegex.lastIndex + ". Expected '" + str + "', found '" + _match.token + "'.");
return this.matchAny();
}
this.matchAnyIgnoreCase = function(strs) {
if (strs.every(function(str) { return _match.token.toUpperCase() !== str.toUpperCase(); }))
throw new Error("Parser error at pos " + _tokenRegex.lastIndex + ". Expected any of: '" + strs.join("', '") + "', found '" + _match.token + "'.");
return this.matchAny();
}
this.matchNot = function(strs) {
if (strs.indexOf(_match.token) != -1)
throw new Error("Parser error at pos " + _tokenRegex.lastIndex + ". Unexpected '" + _match.token + "'.");
return this.matchAny();
}
this.index = function() {
return _match.index;
}
Object.defineProperty(this, "token", { get: function() { return _match.token; }});
getToken();
}
var Bibtex = function(sourceText, index, entryTypes) {
var _plainText = /[^\{\},\\=\s]+/;
const _tokens = [
/\{/,
/\}/,
/,/,
/=/,
/@/,
/\\\W/,
/\\[\w]+/,
_plainText,
];
var _parser = new Parser(sourceText, index, _tokens);
var entry = function() {
_parser.match("{");
var id = fieldValue();
_parser.match(",");
var f = fields();
_parser.match("}");
f.bibcode = id;
return f;
}
var comment = function() {
_parser.match("{");
var text = fieldValue();
_parser.match("}");
return { comment: text };
}
var type = function() {
_parser.match('@');
var token = _parser.token;
if (entryTypes.length)
_parser.matchAnyIgnoreCase(entryTypes);
else
_parser.matchAny();
return token;
}
var fields = function() {
var res = {};
for(;;) {
var f = field();
res[f.name] = f.value;
if (_parser.token !== ",") break;
_parser.match(",");
if (_parser.token === "}") break;
}
return res;
}
var quoted = function() {
return _parser.match("{").space + quotedValue() + _parser.match("}").space;
}
var diacritics = {
'`': '\u0300',
'\'': '\u0301',
'^': '\u0302',
'~': '\u0303',
'=': '\u0304',
'u': '\u0306',
'.': '\u0307',
'"': '\u0308',
'r': '\u030a',
'H': '\u030b',
'v': '\u030c',
'c': '\u0327',
'k': '\u0328',
'd': '\u0323',
'b': '\u0331',
't': '\u0361',
};
var ligatures = {
'L': '\u0141',
'l': '\u0142',
'AA': '\u00c5',
'aa': '\u00e5',
'AE': '\u00c6',
'ae': '\u00e6',
'O': '\u00d8',
'o': '\u00f8',
'OE': '\u0152',
'oe': '\u0153',
'i': '\u0131',
'j': '\u0237',
'ss': '\u00df',
};
var entity = function() {
if (_parser.token[0] != '\\')
throw new Error("Expected entity, found " + _parser.token);
var cmd = _parser.matchAny().token.substr(1);
var value = ligatures[cmd];
if (value)
return value;
value = diacritics[cmd];
if (value)
return fieldValue() + value;
return cmd;
}
var quotedValue = function() {
var res = "";
for(;;) {
if (_parser.token === "{")
res += quoted();
else if (_parser.token === "}")
break;
else if (_parser.token[0] === '\\')
res += entity();
else
res += _parser.matchAny().match;
}
return res;
}
var fieldValue = function() {
var res = "";
for(;;) {
if (_parser.token == "{")
res += quoted();
else if (_parser.token[0] === '\\')
res += entity();
else if (_plainText.test(_parser.token))
res += _parser.matchAny().match;
else
break;
}
return res.trim().replace(/^"?(.*?)"?$/, '$1').replace(/---?/g, '—');
}
var field = function() {
var name = fieldValue();
_parser.match("=");
var value = fieldValue();
return {
name: name,
value: value
}
}
if (!entryTypes)
entryTypes = []
else if (typeof entryTypes == 'string' || entryTypes instanceof String)
entryTypes = [ entryTypes ];
var realType = type(entryTypes);
if (realType.toLowerCase() == 'comment')
var result = comment();
else
var result = entry();
result.type = realType;
result._index = _parser.index();
return result;
}
var bibtexBase = {
'автор': {
selector: 'author',
getAuthors: function(text) {
return text.split(' and ').map(function(name) {
return name.replace(/~/g, ' ').replace(',', '');
});
},
getWiki: function(authors) {
return authors.map(function(name) {
return new Template('nobr').add(name).toWiki()
}).join(', ');
},
map: function(text) {
var me = bibtexBase['автор'];
return me.getWiki(me.getAuthors(text));
},
},
'заглавие': {
selector: 'title',
map: function(text) {
return text.replace(/^"|"$/g, '')
}
},
'издание': {
selector: 'journal',
map: function(text) {
return {
aj: 'Astronomical Journal',
actaa: 'Acta Astronomica',
araa: 'Annual Review of Astron and Astrophys',
apj: 'Astrophysical Journal',
apjl: 'Astrophysical Journal, Letters',
apjs: 'Astrophysical Journal, Supplement',
ao: 'Applied Optics',
apss: 'Astrophysics and Space Science',
aap: 'Astronomy and Astrophysics',
aapr: 'Astronomy and Astrophysics Reviews',
aaps: 'Astronomy and Astrophysics, Supplement',
azh: 'Astronomicheskii Zhurnal',
baas: 'Bulletin of the AAS',
caa: 'Chinese Astronomy and Astrophysics',
cjaa: 'Chinese Journal of Astronomy and Astrophysics',
icarus: 'Icarus',
jcap: 'Journal of Cosmology and Astroparticle Physics',
jrasc: 'Journal of the RAS of Canada',
memras: 'Memoirs of the RAS',
mnras: 'Monthly Notices of the RAS',
na: 'New Astronomy',
nar: 'New Astronomy Review',
pra: 'Physical Review A: General Physics',
prb: 'Physical Review B: Solid State',
prc: 'Physical Review C',
prd: 'Physical Review D',
pre: 'Physical Review E',
prl: 'Physical Review Letters',
pasa: 'Publications of the Astron. Soc. of Australia',
pasp: 'Publications of the ASP',
pasj: 'Publications of the ASJ',
rmxaa: 'Revista Mexicana de Astronomia y Astrofisica',
qjras: 'Quarterly Journal of the RAS',
skytel: 'Sky and Telescope',
solphys: 'Solar Physics',
sovast: 'Soviet Astronomy',
ssr: 'Space Science Reviews',
zap: 'Zeitschrift fuer Astrophysik',
nat: 'Nature',
iaucirc: 'IAU Cirulars',
aplett: 'Astrophysics Letters',
apspr: 'Astrophysics Space Physics Research',
bain: 'Bulletin Astronomical Institute of the Netherlands',
fcp: 'Fundamental Cosmic Physics',
gca: 'Geochimica Cosmochimica Acta',
grl: 'Geophysics Research Letters',
jcp: 'Journal of Chemical Physics',
jgr: 'Journal of Geophysics Research',
jqsrt: 'Journal of Quantitiative Spectroscopy and Radiative Transfer',
memsai: 'Mem. Societa Astronomica Italiana',
nphysa: 'Nuclear Physics A',
physrep: 'Physics Reports',
physscr: 'Physica Scripta',
planss: 'Planetary Space Science',
procspie: 'Proceedings of the SPIE',
}[text] || text;
},
},
'год': {
selector: 'year',
},
'выпуск': {
selector: 'number',
},
'том': {
selector: 'volume',
},
'страницы': {
selector: 'pages',
},
'издательство': {
selector: 'publisher',
},
'issn': {
selector: 'issn',
},
'doi': {
selector: 'doi',
},
'arxiv': {
selector: 'eprint',
map: function(text) {
const prefix = 'arXiv:';
if (text.indexOf(prefix) == 0)
text = text.substr(prefix.length);
return text;
}
},
'ссылка': { const: "" },
'ref': { const: "" },
'archiveurl': { const: "" },
'archivedate': { const: "" },
};
var adsabsBibcode = (function() {
var bibtex = clone(bibtexBase);
bibtex.bibcode = { selector: 'bibcode' };
return bibtex;
})();
var ufnBibtex = (function() {
var bibtex = clone(bibtexBase);
var nameRegex = /^(.+) (\S+)$/;
var author = bibtex['автор'];
author.map = function(text) {
return author.getWiki(author.getAuthors(text).map(function(name) {
var match = nameRegex.exec(name);
if (!match) return name;
return match[2] + ' ' + match[1];
}));
}
return bibtex;
})();
var googleBibtex = function(url) {
var bibtex = clone(bibtexBase);
bibtex.серия = { 'selector': 'series' };
bibtex.страниц = { const: "" };
bibtex.isbn = { 'selector': 'isbn' };
delete bibtex.ссылка;
delete bibtex.archiveurl;
delete bibtex.archivedate;
delete bibtex.ref;
bibtex.ссылка = { const: url };
bibtex.ref = { const: "" };
return bibtex;
};
var sciencedirectBibtex = (function() {
var bibtex = clone(bibtexBase);
bibtex.ссылка = { selector: 'url' };
bibtex.doi.map = function(text) {
var res = /http:\/\/dx\.doi\.org\/(.*)$/.exec(text) || [];
return res[1] || text;
}
bibtex.страницы.map = function(text) {
return text.replace(' - ', '—')
}
return bibtex;
})();
var libGenesisBibtex = (function() {
var bibtex = clone(bibtexBase);
bibtex.выпуск = { selector: 'issue' };
bibtex.страницы = { selector: 'page' };
return bibtex;
})();
var wileyBibtex = (function() {
var bibtex = clone(bibtexBase);
bibtex.ссылка = { selector: 'url' };
return bibtex;
})();
var jstorBibtex = (function() {
var bibtex = clone(bibtexBase);
bibtex.ссылка = { selector: 'url' };
bibtex.выпуск.selector = function(obj) {
return obj['number'] || obj['jstor_issuetitle'];
}
bibtex.страницы.map = function(text) {
return text.replace(/^p?p\. /, "").replace('-', '—');
};
return bibtex;
})();
var getWpFromObj = function(name, rules, obj) {
var article = new Template(name);
for(var name in rules) {
var rule = rules[name];
var value;
if (rule.const !== undefined)
value = rule.const
else {
if (typeof rule.selector === "function")
value = rule.selector(obj);
else
value = obj[rule.selector];
if (!value)continue;
}
if (rule.map)
value = rule.map(value, obj);
article.add(name, value);
}
return article.toWiki();
}
var testUrl = function(regex) {
return regex.exec(window.location.href)
}
var createWpButton = function(onclick, tag) {
var element = document.createElement(tag || 'a');
element.setAttribute('href', '#');
element.textContent = 'WP';
element.addEventListener('click', function(e) {
e.preventDefault();
onclick();
});
return element;
}
var pages = [
// pubmed
{
test: function() {
return testUrl(/\/pubmed\/(\d+)$/);
},
process: function(match) {
var $ = unsafeWindow.jQuery;
var id = match[1];
$('#messagearea').after(
$('<div>').append(
$('<a>').attr('href', '#').text('WP').click(function(e) {
e.preventDefault();
ajax({
method: "GET",
url: id + '?dopt=Abstract&report=xml&format=text',
onload: function(response) {
var html = new DOMParser().parseFromString(response.responseText, "text/html");
var xml = new DOMParser().parseFromString(html.body.textContent, "text/xml");
alert(getWpFromXml(templates.article, pubmed, xml));
}
});
})
)
);
},
},
// adsabs
{
test: function() {
return testUrl(/adsabs\.harvard\.edu\/(abs|doi)\/(.*)$/);
},
process: function(match) {
var id = match[2];
var button = createWpButton(function() {
ajax({
method: "GET",
url: '/cgi-bin/nph-bib_query?data_type=BIBTEX&bibcode=' + id,
onload: function(response) {
var index = response.responseText.indexOf('@ARTICLE{');
if (index == -1) {
alert('bibtex not found');
return;
}
try {
alert(getWpFromObj(templates.article, adsabsBibcode, Bibtex(response.responseText, index, 'article')));
} catch(e) {
alert(e + '\n' + e.stack);
}
}
});
}, false);
var heading = document.body.querySelector('h3');
heading.appendChild(document.createTextNode(' '));
heading.appendChild(button);
},
},
// ufn
{
test: function() {
return testUrl(/\/ufn\.ru\/ru\/articles\/(\d+\/\d+\/\w+)\//);
},
process: function(match) {
var id = match[1];
var button = createWpButton(function() {
ajax({
method: "GET",
url: '/ru/articles/' + id + '/citation/ru/bibtex.html',
onload: function(response) {
var html = new DOMParser().parseFromString(response.responseText, "text/html");
var node = html.body.querySelector('.cit_code > pre');
if (!node) {
alert('bibtex not found');
return;
}
try {
alert(getWpFromObj(templates.article, ufnBibtex, Bibtex(node.textContent, 0, 'article')));
} catch(e) {
alert(e + '\n' + e.stack);
}
}
});
});
var node = document.body.querySelector('#print > table tr > td').nextSibling;
var td = document.createElement('TD');
td.appendChild(button);
node.parentNode.insertBefore(td, node);
},
},
// google books
{
test: function() {
return window.self == window.top && testUrl(/http:\/\/books\.google\.\w+\/books\?id=([^&$]+)/);
},
process: function(match) {
var id = match[1];
var button = createWpButton(function() {
ajax({
method: "GET",
url: 'http://books.google.us/books/download/?id=' + id + '&output=bibtex',
onload: function(response) {
try {
alert(getWpFromObj(templates.book, googleBibtex('http://books.google.com/books?id=' + id), Bibtex(response.responseText, 0, 'book')));
} catch(e) {
alert(e + '\n' + e.stack);
}
}
});
});
button.setAttribute('class', 'gb-button')
button.setAttribute('style', 'margin-left: 4px')
var item = document.body.querySelector('.metadata_value > .gb-button:last-child');
if (item !== null)
item.parentNode.appendChild(button);
},
},
// sciencedirect
{
test: function() {
return testUrl(/sciencedirect\.com\/science\/article\//);
},
process: function() {
var $ = unsafeWindow.jQuery;
var button = createWpButton(function() {
var params = [];
$('form[name=exportCite] input[type=hidden]').each(function(i, hidden) {
params.push(encodeURIComponent($(hidden).attr('name')) + '=' + encodeURIComponent($(hidden).val()));
})
ajax({
method: "GET",
url: $('form[name=exportCite]').attr('action') + params.join('&') + '&citation-type=BIBTEX',
onload: function(response) {
try {
alert(getWpFromObj(templates.article, sciencedirectBibtex, Bibtex(response.responseText, 0, 'article')));
} catch(e) {
alert(e + '\n' + e.stack);
}
}
});
}, 'input');
$('.exportTxt').after($('<div />').append(
$(button).attr('type', 'button').val('WP').css({
'border-radius': '5px',
'padding': '3px 5px 3px 24px',
'border': '1px solid rgb(204, 204, 204)',
'color': '#0156AA',
'background': '#FFF',
'margin-left': '2px',
'cursor': 'pointer',
'height': '24px',
'margin-bottom': '5px',
'font-weight': 'bold',
})
));
},
},
// Library Genesis
{
test: function() {
return testUrl(/gen\.lib\.rus\.ec\/scimag\//);
},
process: function() {
var node = document.querySelector('form[name=search]');
while(node && node.nodeName != 'TABLE') {
node = node.nextSibling;
}
var rows = node.querySelectorAll('tr');
for(var i = 0; i < rows.length; i++) {
let doi = rows[i].querySelector('td:first-child').textContent;
var button = createWpButton(function() {
ajax({
method: "GET",
url: 'http://gen.lib.rus.ec/scimag/bibtex.php?doi=' + doi,
onload: function(response) {
var html = new DOMParser().parseFromString(response.responseText, "text/html");
try {
alert(getWpFromObj(templates.article, libGenesisBibtex, Bibtex(html.querySelector('textarea#bibtext').value, 0, 'article')));
} catch(e) {
alert(e + '\n' + e.stack);
}
}
});
});
rows[i].querySelector('td:last-child').appendChild(button);
button.style.fontWeight = 'bold';
}
}
},
// wiley
{
test: function() {
return testUrl(/onlinelibrary\.wiley\.com\/doi\//)
},
process: function() {
var $ = unsafeWindow.$;
var doi = /^DOI:\s+(.+)$/.exec($('#doi').text().trim());
if (!doi) return;
doi = doi[1];
var button = createWpButton(function() {
ajax({
method: 'POST',
url: '/documentcitationdownloadformsubmit',
data: 'doi=' + encodeURIComponent(doi) + '&fileFormat=BIBTEX&hasAbstract=CITATION',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
onload: function(response) {
try {
var bibtex = Bibtex(response.responseText, 0);
bibtex.url = window.location.href;
var template = {
'article': templates.article,
}[bibtex.type.toLowerCase()];
if (!template) {
alert('unknown type: ' + bibtex.type);
return;
}
alert(getWpFromObj(template, wileyBibtex, bibtex));
} catch(e) {
alert(e + '\n' + e.stack);
}
}
});
});
setTimeout(function() {
$('#toggleAddInfo').append(button);
}, 500);
}
},
// jstor
{
test: function() {
return testUrl(/www\.jstor\.org\/[^\/]+\/(.*?)($|\?)/)
},
process: function(doi) {
doi = decodeURIComponent(doi[1]);
var button = createWpButton(function() {
ajax({
method: 'GET',
url: '/action/downloadSingleCitationSec?userAction=export&format=bibtex&include=abs&singleCitation=true&noDoi=yesDoi&doi=' + doi,
onload: function(response) {
try {
var txt = response.responseText.trim();
const header = 'JSTOR CITATION LIST';
var index = txt.indexOf(header);
if (index == -1)
throw new Error('header not found');
index += header.length;
while(index < txt.length) {
var bibtex = Bibtex(txt, index, [ 'article', 'comment', 'book' ]);
if (bibtex.type != 'comment')
break;
index = bibtex._index;
}
if (!bibtex)
throw new Error('bibtex not found');
var template = {
'article': templates.article,
'book': templates.book,
}[bibtex.type.toLowerCase()];
alert(getWpFromObj(template, jstorBibtex, bibtex));
} catch(e) {
alert(e + '\n' + e.stack);
}
}
});
});
document.querySelector('#navSearchContainer').appendChild(button);
button.style.marginLeft = "10px"
}
},
];
try {
pages.forEach(function(page) {
var res = page.test();
if (res) {
page.process(res);
return false; // break
}
});
} catch(e) {
alert(e);
}