wiki-reference

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

当前为 2014-09-10 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name wiki-reference
  3. // @namespace torvin
  4. // @include https://www.ncbi.nlm.nih.gov/pubmed/*
  5. // @include http://www.ncbi.nlm.nih.gov/pubmed/*
  6. // @include http://adsabs.harvard.edu/abs/*
  7. // @include http://adsabs.harvard.edu/doi/*
  8. // @include http://ufn.ru/ru/articles/*
  9. // @include http://books.google.*/books?*
  10. // @include http://www.sciencedirect.com/science/article/*
  11. // @include http://gen.lib.rus.ec/scimag/*
  12. // @include http://onlinelibrary.wiley.com/doi/*
  13. // @include http://www.jstor.org/stable/*
  14. // @include http://www.jstor.org/discover/*
  15. // @require https://code.jquery.com/jquery-2.1.1.min.js
  16. // @version 1.6
  17. // @description Позволяет генерировать ссылки в формате {{Статья}} и {{книга}} для ру-вики
  18. // @grant GM_xmlhttpRequest
  19. // @grant GM_setClipboard
  20. // ==/UserScript==
  21.  
  22. const templates = {
  23. article: 'Статья',
  24. book: 'книга',
  25. };
  26.  
  27. var Template = function(name) {
  28. var attrs = [];
  29.  
  30. this.add = function(name, value) {
  31. attrs.push({
  32. name: name,
  33. value: value
  34. });
  35. return this;
  36. };
  37.  
  38. var getAttr = function(x) {
  39. return "|" + x.name + (x.value === undefined ? "" : " = " + x.value);
  40. };
  41.  
  42. this.toWiki = function() {
  43. if (attrs.length == 1)
  44. return "{{" + name + getAttr(attrs[0]) + "}}";
  45. else
  46. return "{{" + name + "\n" + attrs.map(function(x) { return " " + getAttr(x)}).join("\n") + "\n}}";
  47. };
  48. };
  49.  
  50. var pubmed = {
  51. 'автор': {
  52. selector: 'Article > AuthorList > Author',
  53. map: function(node) { return [ node.querySelector('LastName'), node.querySelector('Initials') ] },
  54. mapText: function(nodes) { return new Template('nobr').add(nodes[0] + ' ' + nodes[1].replace(/(.)/g, "$1. ").trim()).toWiki() },
  55. },
  56. 'заглавие': {
  57. selector: 'Article > ArticleTitle',
  58. mapText: function(text) { return text.replace(/^(.*?)\.?$/, "$1") },
  59. },
  60. 'издание': {
  61. selector: 'Article > Journal > Title',
  62. },
  63. 'год': {
  64. selector: 'Article > Journal > JournalIssue > PubDate',
  65. mapText: function(text) { return /^\s*(\d{4})/.exec(text)[1] },
  66. },
  67. 'выпуск': {
  68. selector: 'Article > Journal > JournalIssue > Issue',
  69. },
  70. 'том': {
  71. selector: 'Article > Journal > JournalIssue > Volume',
  72. },
  73. 'страницы': {
  74. selector: 'Article > Pagination > MedlinePgn',
  75. },
  76. 'issn': {
  77. selector: 'Article > Journal > ISSN[IssnType=Electronic]',
  78. },
  79. 'doi': {
  80. selector: 'ArticleIdList > ArticleId[IdType=doi]',
  81. },
  82. 'pmid': {
  83. selector: 'ArticleIdList > ArticleId[IdType=pubmed]',
  84. },
  85. 'ссылка': { const: "" },
  86. 'ref': { const: "" },
  87. 'archiveurl': { const: "" },
  88. 'archivedate': { const: "" },
  89. };
  90.  
  91. var getText = function(node) {
  92. return node instanceof Element ? node.textContent : node;
  93. };
  94.  
  95. var ajax = function(params) {
  96. setTimeout(function() {
  97. GM_xmlhttpRequest(params)
  98. }, 0);
  99. }
  100.  
  101. var clone = function(obj) {
  102. var target = {};
  103. for (var i in obj) {
  104. var value = obj[i];
  105. if (value instanceof Function)
  106. ;
  107. else if (typeof value == 'string')
  108. ;
  109. else
  110. value = clone(value);
  111. target[i] = value;
  112. }
  113. return target;
  114. }
  115.  
  116. var getWpFromXml = function(name, rules, xml) {
  117. var article = new Template(name);
  118.  
  119. for(var name in rules) {
  120. var rule = rules[name];
  121. article.add(name, rule.const ||
  122. Array.slice(xml.querySelectorAll(rule.selector)).map(function(node) {
  123. if (rule.map)
  124. node = rule.map(node);
  125. return Array.isArray(node) ? node.map(getText) : getText(node);
  126. }).map(function(item) {
  127. return rule.mapText ? rule.mapText(item) : item;
  128. }).join(rule.separator || ', ')
  129. );
  130. }
  131.  
  132. return article.toWiki();
  133. };
  134.  
  135. var Parser = function(sourceText, index, tokens) {
  136. var _match;
  137. var _isEof;
  138.  
  139. //var _tokenRegex = /(\s*)(\{|\}|,|=|\\\W|\\[\w]+|[^\{\},\\=\s])/g;
  140. var _tokenRegex = new RegExp("(\\s*)(" + tokens.map(function(x) { return x.source || x }).join('|') + ")", 'g');
  141. _tokenRegex.lastIndex = index;
  142.  
  143. var getToken = function() {
  144. if (_isEof)
  145. throw new Error("EOF");
  146.  
  147. var index = _tokenRegex.lastIndex;
  148.  
  149. var res = _tokenRegex.exec(sourceText);
  150. if (!res) {
  151. _isEof = true;
  152. return null;
  153. }
  154. _match = {
  155. match: res[0],
  156. token: res[2],
  157. space: res[1].replace(/\s+/g, ' '),
  158. index: index,
  159. }
  160. }
  161.  
  162. this.matchAny = function() {
  163. var res = _match;
  164. getToken();
  165. return res;
  166. }
  167.  
  168. this.match = function(str) {
  169. if (_match.token !== str)
  170. throw new Error("Parser error at pos " + _tokenRegex.lastIndex + ". Expected '" + str + "', found '" + _match.token + "'.");
  171. return this.matchAny();
  172. }
  173.  
  174. this.matchIgnoreCase = function(str) {
  175. if (_match.token.toUpperCase() !== str.toUpperCase())
  176. throw new Error("Parser error at pos " + _tokenRegex.lastIndex + ". Expected '" + str + "', found '" + _match.token + "'.");
  177. return this.matchAny();
  178. }
  179.  
  180. this.matchAnyIgnoreCase = function(strs) {
  181. if (strs.every(function(str) { return _match.token.toUpperCase() !== str.toUpperCase(); }))
  182. throw new Error("Parser error at pos " + _tokenRegex.lastIndex + ". Expected any of: '" + strs.join("', '") + "', found '" + _match.token + "'.");
  183. return this.matchAny();
  184. }
  185.  
  186. this.matchNot = function(strs) {
  187. if (strs.indexOf(_match.token) != -1)
  188. throw new Error("Parser error at pos " + _tokenRegex.lastIndex + ". Unexpected '" + _match.token + "'.");
  189. return this.matchAny();
  190. }
  191.  
  192. this.index = function() {
  193. return _match.index;
  194. }
  195.  
  196. Object.defineProperty(this, "token", { get: function() { return _match.token; }});
  197.  
  198. getToken();
  199. }
  200.  
  201. var Bibtex = function(sourceText, index, entryTypes) {
  202. var _plainText = /[^\{\},\\=\s]+/;
  203. const _tokens = [
  204. /\{/,
  205. /\}/,
  206. /,/,
  207. /=/,
  208. /@/,
  209. /\\\W/,
  210. /\\[\w]+/,
  211. _plainText,
  212. ];
  213.  
  214. var _parser = new Parser(sourceText, index, _tokens);
  215.  
  216. var entry = function() {
  217. _parser.match("{");
  218. var id = fieldValue();
  219. _parser.match(",");
  220. var f = fields();
  221. _parser.match("}");
  222.  
  223. f.bibcode = id;
  224. return f;
  225. }
  226.  
  227. var comment = function() {
  228. _parser.match("{");
  229. var text = fieldValue();
  230. _parser.match("}");
  231. return { comment: text };
  232. }
  233.  
  234. var type = function() {
  235. _parser.match('@');
  236. var token = _parser.token;
  237. if (entryTypes.length)
  238. _parser.matchAnyIgnoreCase(entryTypes);
  239. else
  240. _parser.matchAny();
  241. return token;
  242. }
  243.  
  244. var fields = function() {
  245. var res = {};
  246. for(;;) {
  247. var f = field();
  248. res[f.name] = f.value;
  249. if (_parser.token !== ",") break;
  250. _parser.match(",");
  251. if (_parser.token === "}") break;
  252. }
  253. return res;
  254. }
  255.  
  256. var quoted = function() {
  257. return _parser.match("{").space + quotedValue() + _parser.match("}").space;
  258. }
  259.  
  260. var diacritics = {
  261. '`': '\u0300',
  262. '\'': '\u0301',
  263. '^': '\u0302',
  264. '~': '\u0303',
  265. '=': '\u0304',
  266. 'u': '\u0306',
  267. '.': '\u0307',
  268. '"': '\u0308',
  269. 'r': '\u030a',
  270. 'H': '\u030b',
  271. 'v': '\u030c',
  272. 'c': '\u0327',
  273. 'k': '\u0328',
  274. 'd': '\u0323',
  275. 'b': '\u0331',
  276. 't': '\u0361',
  277. };
  278.  
  279. var ligatures = {
  280. 'L': '\u0141',
  281. 'l': '\u0142',
  282. 'AA': '\u00c5',
  283. 'aa': '\u00e5',
  284. 'AE': '\u00c6',
  285. 'ae': '\u00e6',
  286. 'O': '\u00d8',
  287. 'o': '\u00f8',
  288. 'OE': '\u0152',
  289. 'oe': '\u0153',
  290. 'i': '\u0131',
  291. 'j': '\u0237',
  292. 'ss': '\u00df',
  293. };
  294.  
  295. var entity = function() {
  296. if (_parser.token[0] != '\\')
  297. throw new Error("Expected entity, found " + _parser.token);
  298.  
  299. var cmd = _parser.matchAny().token.substr(1);
  300.  
  301. var value = ligatures[cmd];
  302. if (value)
  303. return value;
  304.  
  305. value = diacritics[cmd];
  306. if (value)
  307. return fieldValue() + value;
  308.  
  309. return cmd;
  310. }
  311.  
  312. var quotedValue = function() {
  313. var res = "";
  314. for(;;) {
  315. if (_parser.token === "{")
  316. res += quoted();
  317. else if (_parser.token === "}")
  318. break;
  319. else if (_parser.token[0] === '\\')
  320. res += entity();
  321. else
  322. res += _parser.matchAny().match;
  323. }
  324. return res;
  325. }
  326.  
  327. var fieldValue = function() {
  328. var res = "";
  329. for(;;) {
  330. if (_parser.token == "{")
  331. res += quoted();
  332. else if (_parser.token[0] === '\\')
  333. res += entity();
  334. else if (_plainText.test(_parser.token))
  335. res += _parser.matchAny().match;
  336. else
  337. break;
  338. }
  339. return res.trim().replace(/^"?(.*?)"?$/, '$1').replace(/---?/g, '—');
  340.  
  341. }
  342.  
  343. var field = function() {
  344. var name = fieldValue();
  345. _parser.match("=");
  346. var value = fieldValue();
  347.  
  348. return {
  349. name: name,
  350. value: value
  351. }
  352. }
  353.  
  354. if (!entryTypes)
  355. entryTypes = []
  356. else if (typeof entryTypes == 'string' || entryTypes instanceof String)
  357. entryTypes = [ entryTypes ];
  358. var realType = type(entryTypes);
  359.  
  360. if (realType.toLowerCase() == 'comment')
  361. var result = comment();
  362. else
  363. var result = entry();
  364.  
  365. result.type = realType;
  366. result._index = _parser.index();
  367. return result;
  368. }
  369.  
  370. var bibtexBase = {
  371. 'автор': {
  372. selector: 'author',
  373. getAuthors: function(text) {
  374. return text.split(' and ').map(function(name) {
  375. return name.replace(/~/g, ' ').replace(',', '');
  376. });
  377. },
  378. getWiki: function(authors) {
  379. return authors.map(function(name) {
  380. return new Template('nobr').add(name).toWiki()
  381. }).join(', ');
  382. },
  383. map: function(text) {
  384. var me = bibtexBase['автор'];
  385. return me.getWiki(me.getAuthors(text));
  386. },
  387. },
  388. 'заглавие': {
  389. selector: 'title',
  390. map: function(text) {
  391. return text.replace(/^"|"$/g, '')
  392. }
  393. },
  394. 'издание': {
  395. selector: 'journal',
  396. map: function(text) {
  397. return {
  398. aj: 'Astronomical Journal',
  399. actaa: 'Acta Astronomica',
  400. araa: 'Annual Review of Astron and Astrophys',
  401. apj: 'Astrophysical Journal',
  402. apjl: 'Astrophysical Journal, Letters',
  403. apjs: 'Astrophysical Journal, Supplement',
  404. ao: 'Applied Optics',
  405. apss: 'Astrophysics and Space Science',
  406. aap: 'Astronomy and Astrophysics',
  407. aapr: 'Astronomy and Astrophysics Reviews',
  408. aaps: 'Astronomy and Astrophysics, Supplement',
  409. azh: 'Astronomicheskii Zhurnal',
  410. baas: 'Bulletin of the AAS',
  411. caa: 'Chinese Astronomy and Astrophysics',
  412. cjaa: 'Chinese Journal of Astronomy and Astrophysics',
  413. icarus: 'Icarus',
  414. jcap: 'Journal of Cosmology and Astroparticle Physics',
  415. jrasc: 'Journal of the RAS of Canada',
  416. memras: 'Memoirs of the RAS',
  417. mnras: 'Monthly Notices of the RAS',
  418. na: 'New Astronomy',
  419. nar: 'New Astronomy Review',
  420. pra: 'Physical Review A: General Physics',
  421. prb: 'Physical Review B: Solid State',
  422. prc: 'Physical Review C',
  423. prd: 'Physical Review D',
  424. pre: 'Physical Review E',
  425. prl: 'Physical Review Letters',
  426. pasa: 'Publications of the Astron. Soc. of Australia',
  427. pasp: 'Publications of the ASP',
  428. pasj: 'Publications of the ASJ',
  429. rmxaa: 'Revista Mexicana de Astronomia y Astrofisica',
  430. qjras: 'Quarterly Journal of the RAS',
  431. skytel: 'Sky and Telescope',
  432. solphys: 'Solar Physics',
  433. sovast: 'Soviet Astronomy',
  434. ssr: 'Space Science Reviews',
  435. zap: 'Zeitschrift fuer Astrophysik',
  436. nat: 'Nature',
  437. iaucirc: 'IAU Cirulars',
  438. aplett: 'Astrophysics Letters',
  439. apspr: 'Astrophysics Space Physics Research',
  440. bain: 'Bulletin Astronomical Institute of the Netherlands',
  441. fcp: 'Fundamental Cosmic Physics',
  442. gca: 'Geochimica Cosmochimica Acta',
  443. grl: 'Geophysics Research Letters',
  444. jcp: 'Journal of Chemical Physics',
  445. jgr: 'Journal of Geophysics Research',
  446. jqsrt: 'Journal of Quantitiative Spectroscopy and Radiative Transfer',
  447. memsai: 'Mem. Societa Astronomica Italiana',
  448. nphysa: 'Nuclear Physics A',
  449. physrep: 'Physics Reports',
  450. physscr: 'Physica Scripta',
  451. planss: 'Planetary Space Science',
  452. procspie: 'Proceedings of the SPIE',
  453. }[text] || text;
  454. },
  455. },
  456. 'год': {
  457. selector: 'year',
  458. },
  459. 'выпуск': {
  460. selector: 'number',
  461. },
  462. 'том': {
  463. selector: 'volume',
  464. },
  465. 'страницы': {
  466. selector: 'pages',
  467. },
  468. 'издательство': {
  469. selector: 'publisher',
  470. },
  471. 'issn': {
  472. selector: 'issn',
  473. },
  474. 'doi': {
  475. selector: 'doi',
  476. },
  477. 'arxiv': {
  478. selector: 'eprint',
  479. map: function(text) {
  480. const prefix = 'arXiv:';
  481. if (text.indexOf(prefix) == 0)
  482. text = text.substr(prefix.length);
  483. return text;
  484. }
  485. },
  486. 'ссылка': { const: "" },
  487. 'ref': { const: "" },
  488. 'archiveurl': { const: "" },
  489. 'archivedate': { const: "" },
  490. };
  491.  
  492. var adsabsBibcode = (function() {
  493. var bibtex = clone(bibtexBase);
  494. bibtex.bibcode = { selector: 'bibcode' };
  495. return bibtex;
  496. })();
  497.  
  498. var ufnBibtex = (function() {
  499. var bibtex = clone(bibtexBase);
  500.  
  501. var nameRegex = /^(.+) (\S+)$/;
  502. var author = bibtex['автор'];
  503. author.map = function(text) {
  504. return author.getWiki(author.getAuthors(text).map(function(name) {
  505. var match = nameRegex.exec(name);
  506. if (!match) return name;
  507. return match[2] + ' ' + match[1];
  508. }));
  509. }
  510. return bibtex;
  511. })();
  512.  
  513. var googleBibtex = function(url) {
  514. var bibtex = clone(bibtexBase);
  515. bibtex.серия = { 'selector': 'series' };
  516. bibtex.страниц = { const: "" };
  517. bibtex.isbn = { 'selector': 'isbn' };
  518. delete bibtex.ссылка;
  519. delete bibtex.archiveurl;
  520. delete bibtex.archivedate;
  521. delete bibtex.ref;
  522. bibtex.ссылка = { const: url };
  523. bibtex.ref = { const: "" };
  524. return bibtex;
  525. };
  526.  
  527. var sciencedirectBibtex = (function() {
  528. var bibtex = clone(bibtexBase);
  529. bibtex.ссылка = { selector: 'url' };
  530. bibtex.doi.map = function(text) {
  531. var res = /http:\/\/dx\.doi\.org\/(.*)$/.exec(text) || [];
  532. return res[1] || text;
  533. }
  534. bibtex.страницы.map = function(text) {
  535. return text.replace(' - ', '—')
  536. }
  537. return bibtex;
  538. })();
  539.  
  540. var libGenesisBibtex = (function() {
  541. var bibtex = clone(bibtexBase);
  542. bibtex.выпуск = { selector: 'issue' };
  543. bibtex.страницы = { selector: 'page' };
  544. return bibtex;
  545. })();
  546.  
  547. var wileyBibtex = (function() {
  548. var bibtex = clone(bibtexBase);
  549. bibtex.ссылка = { selector: 'url' };
  550. return bibtex;
  551. })();
  552.  
  553. var jstorBibtex = (function() {
  554. var bibtex = clone(bibtexBase);
  555. bibtex.ссылка = { selector: 'url' };
  556. bibtex.выпуск.selector = function(obj) {
  557. return obj['number'] || obj['jstor_issuetitle'];
  558. }
  559. bibtex.страницы.map = function(text) {
  560. return text.replace(/^p?p\. /, "").replace('-', '—');
  561. };
  562. return bibtex;
  563. })();
  564.  
  565. var getWpFromObj = function(name, rules, obj) {
  566. var article = new Template(name);
  567.  
  568. for(var name in rules) {
  569. var rule = rules[name];
  570.  
  571. var value;
  572. if (rule.const !== undefined)
  573. value = rule.const
  574. else {
  575. if (typeof rule.selector === "function")
  576. value = rule.selector(obj);
  577. else
  578. value = obj[rule.selector];
  579. if (!value)continue;
  580. }
  581.  
  582. if (rule.map)
  583. value = rule.map(value, obj);
  584.  
  585. article.add(name, value);
  586. }
  587.  
  588. return article.toWiki();
  589. }
  590.  
  591. var testUrl = function(regex) {
  592. return regex.exec(window.location.href)
  593. }
  594.  
  595. var createWpButton = function(getResult, tag) {
  596. tag = tag || 'a';
  597. return $('<' + tag + '>')
  598. .attr('href', '#')
  599. .text('WP')
  600. .click(function(e) {
  601. e.preventDefault();
  602.  
  603. var promise = $.Deferred();
  604.  
  605. promise.done(function(result) {
  606. showResult(result);
  607. }).fail(function(result) {
  608. alert(result);
  609. });
  610.  
  611. getResult({
  612. resolve: function(result) {
  613. promise.resolve(result)
  614. },
  615. reject: function(result) {
  616. promise.reject(result)
  617. },
  618. });
  619. })
  620. .get(0);
  621. }
  622.  
  623. var showResult = function(text) {
  624. var button;
  625.  
  626. var dialog = $('<div>').css({
  627. 'position': 'fixed',
  628. 'top': 0,
  629. 'left': 0,
  630. 'width': '100%',
  631. 'height': '100%',
  632. 'z-index': 9999999,
  633. }).appendTo(document.body).append(
  634. // dimmer
  635. $('<div>').css({
  636. 'width': '100%',
  637. 'height': '100%',
  638. 'background-color': 'black',
  639. 'opacity': 0.6,
  640. })
  641. ).append(
  642. // dialog container
  643. $('<div>').css({
  644. 'display': 'table',
  645. 'position': 'absolute',
  646. 'top': 0,
  647. 'left': 0,
  648. 'width': '100%',
  649. 'height': '100%',
  650. 'font': '12px sans-serif',
  651. }).append(
  652. $('<div>').css({
  653. 'text-align': 'center',
  654. 'display': 'table-cell',
  655. 'vertical-align': 'middle',
  656. }).append(
  657. // dialog
  658. $('<div>').css({
  659. 'padding': 10,
  660. 'background-color': 'white',
  661. 'display': 'inline-block',
  662. 'max-width': '80%',
  663. }).append(
  664. // text
  665. $('<div>').css({
  666. 'padding': 5,
  667. 'white-space': 'pre-wrap',
  668. 'text-align': 'left',
  669. }).text(text)
  670. ).append(
  671. // buttons
  672. $('<div>').css({
  673. 'text-align': 'right',
  674. 'margin-top': 10,
  675. }).append(
  676. button = $('<button>').text('Copy & close').click(function() {
  677. GM_setClipboard(text);
  678. dialog.remove();
  679. }).focus()
  680. ).append(
  681. $('<button>').text('Cancel').click(function() {
  682. dialog.remove();
  683. })
  684. )
  685. )
  686. )
  687. )
  688. );
  689.  
  690. button.focus();
  691. }
  692.  
  693. var pages = [
  694. // pubmed
  695. {
  696. test: function() {
  697. return testUrl(/\/pubmed\/(\d+)$/);
  698. },
  699. process: function(match) {
  700. var id = match[1];
  701. $('#messagearea').after(
  702. $('<div>').append(
  703. createWpButton(function(promise) {
  704. ajax({
  705. method: "GET",
  706. url: id + '?dopt=Abstract&report=xml&format=text',
  707. onload: function(response) {
  708. var html = new DOMParser().parseFromString(response.responseText, "text/html");
  709. var xml = new DOMParser().parseFromString(html.body.textContent, "text/xml");
  710. promise.resolve(getWpFromXml(templates.article, pubmed, xml));
  711. }
  712. });
  713. })
  714. )
  715. );
  716. },
  717. },
  718. // adsabs
  719. {
  720. test: function() {
  721. return testUrl(/adsabs\.harvard\.edu\/(abs|doi)\/(.*)$/);
  722. },
  723. process: function(match) {
  724. var id = match[2];
  725. var button = createWpButton(function(promise) {
  726. ajax({
  727. method: "GET",
  728. url: '/cgi-bin/nph-bib_query?data_type=BIBTEX&bibcode=' + id,
  729. onload: function(response) {
  730. var index = response.responseText.indexOf('@ARTICLE{');
  731. if (index == -1) {
  732. promise.reject('bibtex not found');
  733. return;
  734. }
  735.  
  736. try {
  737. promise.resolve(getWpFromObj(templates.article, adsabsBibcode, Bibtex(response.responseText, index, 'article')));
  738. } catch(e) {
  739. promise.reject(e + '\n' + e.stack);
  740. }
  741. }
  742. });
  743. }, false);
  744. $('h3').eq(0)
  745. .append(document.createTextNode(' '))
  746. .append(button);
  747. },
  748. },
  749. // ufn
  750. {
  751. test: function() {
  752. return testUrl(/\/ufn\.ru\/ru\/articles\/(\d+\/\d+\/\w+)\//);
  753. },
  754. process: function(match) {
  755. var id = match[1];
  756.  
  757. var button = createWpButton(function(promise) {
  758. ajax({
  759. method: "GET",
  760. url: '/ru/articles/' + id + '/citation/ru/bibtex.html',
  761. onload: function(response) {
  762. var html = new DOMParser().parseFromString(response.responseText, "text/html");
  763.  
  764. var node = html.body.querySelector('.cit_code > pre');
  765. if (!node) {
  766. promise.reject('bibtex not found');
  767. return;
  768. }
  769.  
  770. try {
  771. promise.resolve(getWpFromObj(templates.article, ufnBibtex, Bibtex(node.textContent, 0, 'article')));
  772. } catch(e) {
  773. promise.reject(e + '\n' + e.stack);
  774. }
  775. }
  776. });
  777. });
  778.  
  779. $('#print > table tr > td').next().append(
  780. $('<td>').append(button)
  781. );
  782. },
  783. },
  784. // google books
  785. {
  786. test: function() {
  787. return window.self == window.top && testUrl(/http:\/\/books\.google\.\w+\/books\?id=([^&$]+)/);
  788. },
  789. process: function(match) {
  790. var id = match[1];
  791.  
  792. var button = createWpButton(function(promise) {
  793. ajax({
  794. method: "GET",
  795. url: 'http://books.google.us/books/download/?id=' + id + '&output=bibtex',
  796. onload: function(response) {
  797. try {
  798. promise.resolve(getWpFromObj(templates.book, googleBibtex('http://books.google.com/books?id=' + id), Bibtex(response.responseText, 0, 'book')));
  799. } catch(e) {
  800. promise.reject(e + '\n' + e.stack);
  801. }
  802. }
  803. });
  804. });
  805. $(button).addClass('class', 'gb-button').css('margin-left', '4px');
  806.  
  807. ['.metadata_value > .gb-button:last-child', '#gb-get-book-container > *:first-child']
  808. .map(x => document.body.querySelector(x))
  809. .filter(item => item !== null)
  810. .forEach(item => item.parentNode.appendChild(button));
  811. },
  812. },
  813. // sciencedirect
  814. {
  815. test: function() {
  816. return testUrl(/sciencedirect\.com\/science\/article\//);
  817. },
  818. process: function() {
  819. var button = createWpButton(function(promise) {
  820. var params = [];
  821. $('form[name=exportCite] input[type=hidden]').each(function(i, hidden) {
  822. params.push(encodeURIComponent($(hidden).attr('name')) + '=' + encodeURIComponent($(hidden).val()));
  823. })
  824. ajax({
  825. method: "GET",
  826. url: $('form[name=exportCite]').attr('action') + params.join('&') + '&citation-type=BIBTEX',
  827. onload: function(response) {
  828. try {
  829. promise.resolve(getWpFromObj(templates.article, sciencedirectBibtex, Bibtex(response.responseText, 0, 'article')));
  830. } catch(e) {
  831. promise.reject(e + '\n' + e.stack);
  832. }
  833. }
  834. });
  835. }, 'input');
  836.  
  837. $('.exportTxt').after($('<div />').append(
  838. $(button).attr('type', 'button').val('WP').css({
  839. 'border-radius': '5px',
  840. 'padding': '3px 5px 3px 24px',
  841. 'border': '1px solid rgb(204, 204, 204)',
  842. 'color': '#0156AA',
  843. 'background': '#FFF',
  844. 'margin-left': '2px',
  845. 'cursor': 'pointer',
  846. 'height': '24px',
  847. 'margin-bottom': '5px',
  848. 'font-weight': 'bold',
  849. })
  850. ));
  851. },
  852. },
  853. // Library Genesis
  854. {
  855. test: function() {
  856. return testUrl(/gen\.lib\.rus\.ec\/scimag\//);
  857. },
  858. process: function() {
  859. var node = document.querySelector('form[name=search]');
  860. while(node && node.nodeName != 'TABLE') {
  861. node = node.nextSibling;
  862. }
  863. var rows = node.querySelectorAll('tr');
  864. for(var i = 0; i < rows.length; i++) {
  865. let anchor = rows[i].querySelector('td:first-child > a');
  866. if (!anchor)
  867. continue;
  868. let doi = anchor.textContent;
  869. var button = createWpButton(function(promise) {
  870. ajax({
  871. method: "GET",
  872. url: 'http://gen.lib.rus.ec/scimag/bibtex.php?doi=' + doi,
  873. onload: function(response) {
  874. var html = new DOMParser().parseFromString(response.responseText, "text/html");
  875. try {
  876. promise.resolve(getWpFromObj(templates.article, libGenesisBibtex, Bibtex(html.querySelector('textarea#bibtext').value, 0, 'article')));
  877. } catch(e) {
  878. promise.reject(e + '\n' + e.stack);
  879. }
  880. }
  881. });
  882. });
  883. rows[i].querySelector('td:last-child').appendChild(button);
  884. button.style.fontWeight = 'bold';
  885. }
  886. }
  887. },
  888. // wiley
  889. {
  890. test: function() {
  891. return testUrl(/onlinelibrary\.wiley\.com\/doi\//)
  892. },
  893. process: function() {
  894. var doi = /^DOI:\s+(.+)$/.exec($('#doi').text().trim());
  895. if (!doi) return;
  896. doi = doi[1];
  897.  
  898. var button = createWpButton(function(promise) {
  899. ajax({
  900. method: 'POST',
  901. url: '/documentcitationdownloadformsubmit',
  902. data: 'doi=' + encodeURIComponent(doi) + '&fileFormat=BIBTEX&hasAbstract=CITATION',
  903. headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  904. onload: function(response) {
  905. try {
  906. var bibtex = Bibtex(response.responseText, 0);
  907. bibtex.url = window.location.href;
  908.  
  909. var template = {
  910. 'article': templates.article,
  911. }[bibtex.type.toLowerCase()];
  912.  
  913. if (!template) {
  914. promise.reject('unknown type: ' + bibtex.type);
  915. return;
  916. }
  917. promise.resolve(getWpFromObj(template, wileyBibtex, bibtex));
  918. } catch(e) {
  919. promise.reject(e + '\n' + e.stack);
  920. }
  921. }
  922. });
  923. });
  924. setTimeout(function() {
  925. $('#toggleAddInfo').append(button);
  926. }, 500);
  927. }
  928. },
  929. // jstor
  930. {
  931. test: function() {
  932. return testUrl(/www\.jstor\.org\/[^\/]+\/(.*?)($|\?)/)
  933. },
  934. process: function(doi) {
  935. doi = decodeURIComponent(doi[1]);
  936. var button = createWpButton(function(promise) {
  937. ajax({
  938. method: 'GET',
  939. url: '/action/downloadSingleCitationSec?userAction=export&format=bibtex&include=abs&singleCitation=true&noDoi=yesDoi&doi=' + doi,
  940. onload: function(response) {
  941. try {
  942. var txt = response.responseText.trim();
  943. const header = 'JSTOR CITATION LIST';
  944.  
  945. var index = txt.indexOf(header);
  946. if (index == -1)
  947. throw new Error('header not found');
  948. index += header.length;
  949.  
  950. while(index < txt.length) {
  951. var bibtex = Bibtex(txt, index, [ 'article', 'comment', 'book' ]);
  952. if (bibtex.type != 'comment')
  953. break;
  954. index = bibtex._index;
  955. }
  956.  
  957. if (!bibtex)
  958. throw new Error('bibtex not found');
  959.  
  960. var template = {
  961. 'article': templates.article,
  962. 'book': templates.book,
  963. }[bibtex.type.toLowerCase()];
  964. promise.resolve(getWpFromObj(template, jstorBibtex, bibtex));
  965. } catch(e) {
  966. promise.reject(e + '\n' + e.stack);
  967. }
  968. }
  969. });
  970. });
  971.  
  972. $('#navSearchContainer').append($(button).css('margin-left', '10px'));
  973. }
  974. },
  975. ];
  976.  
  977. try {
  978. pages.forEach(function(page) {
  979. var res = page.test();
  980. if (res) {
  981. page.process(res);
  982. return false; // break
  983. }
  984. });
  985. } catch(e) {
  986. alert(e + '\n\n' + e.stack);
  987. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址