wiki-reference

Позволяет генерировать ссылки в формате {{Статья}} и {{книга}} для ру-вики

Mint 2014.09.28.. Lásd a legutóbbi verzió

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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/*
// @require     https://code.jquery.com/jquery-2.1.1.min.js
// @version     1.6.1
// @description Позволяет генерировать ссылки в формате {{Статья}} и {{книга}} для ру-вики
// @grant       GM_xmlhttpRequest
// @grant       GM_setClipboard
// ==/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(getResult, tag) {
	tag = tag || 'a';
	return $('<' + tag + '>')
		.attr('href', '#')
		.text('WP')
		.click(function(e) {
			e.preventDefault();

			var promise = $.Deferred();

			promise.done(function(result) {
				showResult(result);
			}).fail(function(result) {
				alert(result);
			});

			getResult({
				resolve: function(result) {
					promise.resolve(result)
				},
				reject: function(result) {
					promise.reject(result)
				},
			});
		})
		.get(0);
}

var showResult = function(text) {
	var button;

	var dialog = $('<div>').css({
		'position': 'fixed',
		'top': 0,
		'left': 0,
		'width': '100%',
		'height': '100%',
		'z-index': 9999999,
	}).appendTo(document.body).append(
		// dimmer
		$('<div>').css({
			'width': '100%',
			'height': '100%',
			'background-color': 'black',
			'opacity': 0.6,
		})
	).append(
		// dialog container
		$('<div>').css({
			'display': 'table',
			'position': 'absolute',
			'top': 0,
			'left': 0,
			'width': '100%',
			'height': '100%',
			'font': '12px sans-serif',
		}).append(
			$('<div>').css({
				'text-align': 'center',
				'display': 'table-cell',
				'vertical-align': 'middle',
			}).append(
				// dialog
				$('<div>').css({
					'padding': 10,
					'background-color': 'white',
					'display': 'inline-block',
					'max-width': '80%',
				}).append(
					// text
					$('<div>').css({
						'padding': 5,
						'white-space': 'pre-wrap',
						'text-align': 'left',
					}).text(text)
				).append(
					// buttons
					$('<div>').css({
						'text-align': 'right',
						'margin-top': 10,
					}).append(
						button = $('<button>').text('Copy & close').click(function() {
							GM_setClipboard(text);
							dialog.remove();
						}).focus()
					).append(
						$('<button>').text('Cancel').click(function() {
							dialog.remove();
						})
					)
				)
			)
		)
	);

	button.focus();
}

var pages = [
	// pubmed
	{
		test: function() {
			return testUrl(/\/pubmed\/(\d+)$/);
		},
		process: function(match) {
			var id = match[1];
			$('#messagearea').after(
				$('<div>').append(
					createWpButton(function(promise) {
						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");
								promise.resolve(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(promise) {
				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) {
							promise.reject('bibtex not found');
							return;
						}

						try {
							promise.resolve(getWpFromObj(templates.article, adsabsBibcode, Bibtex(response.responseText, index, 'article')));
						} catch(e) {
							promise.reject(e + '\n' + e.stack);
						}
					}
				});
			}, false);
			$('h3').eq(0)
				.append(document.createTextNode(' '))
				.append(button);
		},
	},
	// ufn
	{
		test: function() {
			return testUrl(/\/ufn\.ru\/ru\/articles\/(\d+\/\d+\/\w+)\//);
		},
		process: function(match) {
			var id = match[1];

			var button = createWpButton(function(promise) {
				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) {
							promise.reject('bibtex not found');
							return;
						}

						try {
							promise.resolve(getWpFromObj(templates.article, ufnBibtex, Bibtex(node.textContent, 0, 'article')));
						} catch(e) {
							promise.reject(e + '\n' + e.stack);
						}
					}
				});
			});

			$('#print > table tr > td').next().append(
				$('<td>').append(button)
			);
		},
	},
	// 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(promise) {
				ajax({
					method: "GET",
					url: 'http://books.google.us/books/download/?id=' + id + '&output=bibtex',
					onload: function(response) {
						try {
							promise.resolve(getWpFromObj(templates.book, googleBibtex('http://books.google.com/books?id=' + id), Bibtex(response.responseText, 0, 'book')));
						} catch(e) {
							promise.reject(e + '\n' + e.stack);
						}
					}
				});
			});
			$(button).addClass('gb-button').css('margin-left', '4px');
			$('.metadata_value > .gb-button:last-child, #gb-get-book-container > *:first-child')
			 	.parent()
			 	.append(button);
		},
	},
	// sciencedirect
	{
		test: function() {
			return testUrl(/sciencedirect\.com\/science\/article\//);
		},
		process: function() {
			var button = createWpButton(function(promise) {
				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 {
							promise.resolve(getWpFromObj(templates.article, sciencedirectBibtex, Bibtex(response.responseText, 0, 'article')));
						} catch(e) {
							promise.reject(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 anchor = rows[i].querySelector('td:first-child > a');
				if (!anchor) 
					continue;
				let doi = anchor.textContent;
				var button = createWpButton(function(promise) {
					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 {
								promise.resolve(getWpFromObj(templates.article, libGenesisBibtex, Bibtex(html.querySelector('textarea#bibtext').value, 0, 'article')));
							} catch(e) {
								promise.reject(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 doi = /^DOI:\s+(.+)$/.exec($('#doi').text().trim());
			if (!doi) return;
			doi = doi[1];

			var button = createWpButton(function(promise) {
				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) {
								promise.reject('unknown type: ' + bibtex.type);
								return;
							}
							promise.resolve(getWpFromObj(template, wileyBibtex, bibtex));
						} catch(e) {
							promise.reject(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(promise) {
				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()];
							promise.resolve(getWpFromObj(template, jstorBibtex, bibtex));
						} catch(e) {
							promise.reject(e + '\n' + e.stack);
						}
					}
				});
			});

			$('#navSearchContainer').append($(button).css('margin-left', '10px'));
		}
	},
];

try {
	pages.forEach(function(page) {
		var res = page.test();
		if (res) {
			page.process(res);
			return false; // break
		}
	});
} catch(e) {
	alert(e + '\n\n' + e.stack);
}