diff --git a/README.md b/README.md index b963bec..5b4cb8c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Currently, Zotero doesn't have any special field for the number of citations, th The add-on supports both versions of Zotero: 1. Zotero Standalone: - - Download the add-on from https://github.com/beloglazov/zotero-scholar-citations/raw/master/builds/zotero-scholar-citations-1.8.8-fx.xpi + - Download the add-on from https://github.com/beloglazov/zotero-scholar-citations/raw/master/builds/zotero-scholar-citations-1.9.0-fx.xpi - In Zotero Standalone go to Tools -> Add-ons -> click the settings button in the top-right corner -> Install Add-on From File -> select the downloaded file and restart Zotero. 2. Zotero for Firefox: - Install the Firefox add-on from https://addons.mozilla.org/en-us/firefox/addon/zotero-scholar-citations/ diff --git a/build b/build index 39e8a14..fd9134e 100755 --- a/build +++ b/build @@ -1,5 +1,5 @@ #!/bin/sh -version=1.8.8 +version=1.9.0 rm builds/zotero-scholar-citations-${version}-fx.xpi zip -r builds/zotero-scholar-citations-${version}-fx.xpi chrome/* chrome.manifest install.rdf diff --git a/builds/zotero-scholar-citations-1.9.0-fx.xpi b/builds/zotero-scholar-citations-1.9.0-fx.xpi new file mode 100644 index 0000000..f8310f8 Binary files /dev/null and b/builds/zotero-scholar-citations-1.9.0-fx.xpi differ diff --git a/chrome/content/scripts/zoteroscholarcitations.js b/chrome/content/scripts/zoteroscholarcitations.js index 7ed3aa8..f015e23 100644 --- a/chrome/content/scripts/zoteroscholarcitations.js +++ b/chrome/content/scripts/zoteroscholarcitations.js @@ -1,3 +1,6 @@ +if (typeof Zotero === 'undefined') { + Zotero = {}; +} Zotero.ScholarCitations = {}; @@ -7,9 +10,9 @@ Zotero.ScholarCitations.init = function() { stringBundle = document.getElementById('zoteroscholarcitations-bundle'); Zotero.ScholarCitations.captchaString = 'Please enter the Captcha on the page that will now open and then re-try updating the citations, or wait a while to get unblocked by Google if the Captcha is not present.'; Zotero.ScholarCitations.citedPrefixString = '' - if (stringBundle != null) { - Zotero.ScholarCitations.captchaString = stringBundle.getString('captchaString'); - } + if (stringBundle != null) { + Zotero.ScholarCitations.captchaString = stringBundle.getString('captchaString'); + } // Register the callback in Zotero as an item observer var notifierID = Zotero.Notifier.registerObserver( @@ -23,10 +26,10 @@ Zotero.ScholarCitations.init = function() { Zotero.ScholarCitations.notifierCallback = { notify: function(event, type, ids, extraData) { - if (event == 'add') { - Zotero.ScholarCitations.updateItems(Zotero.Items.get(ids)); - } - } + if (event == 'add') { + Zotero.ScholarCitations.updateItems(Zotero.Items.get(ids)); + } + } }; Zotero.ScholarCitations.resetState = function() { @@ -47,24 +50,21 @@ Zotero.ScholarCitations.updateSelectedEntity = function(libraryId) { if (collection) { var items = []; - var _items = collection.getChildren(true, false, 'item'); - for each(var item in _items) { + collection.getChildren(true, false, 'item').forEach(function (item) { items.push(Zotero.Items.get(item.id)); - } + }); Zotero.ScholarCitations.updateItems(items); } else if (group) { if (!group.editable) { alert("This group is not editable!"); return; } - var collections = group.getCollections(); var items = []; - for each(collection in collections) { - var _items = collection.getChildren(true, false, 'item'); - for each(var item in _items) { + group.getCollections().forEach(function(collection) { + collection.getChildren(true, false, 'item').forEach(function(item) { items.push(Zotero.Items.get(item.id)); - } - } + }) + }); Zotero.ScholarCitations.updateItems(items); } else { Zotero.ScholarCitations.updateAll(); @@ -77,8 +77,7 @@ Zotero.ScholarCitations.updateSelectedItems = function() { Zotero.ScholarCitations.updateAll = function() { var items = []; - var _items = Zotero.Items.getAll(); - for each(var item in _items) { + Zotero.Items.getAll().forEach(function (item) { if (item.isRegularItem() && !item.isCollection()) { var libraryId = item.getField('libraryID'); if (libraryId == null || @@ -87,7 +86,7 @@ Zotero.ScholarCitations.updateAll = function() { items.push(item); } } - } + }); Zotero.ScholarCitations.updateItems(items); }; @@ -116,29 +115,35 @@ Zotero.ScholarCitations.updateNextItem = function() { Zotero.ScholarCitations.itemsToUpdate[Zotero.ScholarCitations.current]); }; -Zotero.ScholarCitations.updateItem = function(item) { - if (typeof item.attachmentHash !== 'undefined') { - Zotero.ScholarCitations.updateNextItem(); - return; - } +Zotero.ScholarCitations.generateItemUrl = function(item) { var baseUrl = 'http://scholar.google.com/'; var url = baseUrl + 'scholar?hl=en&as_q=' + encodeURIComponent(item.getField('title')).replace(/ /g, '+') + '&as_occt=title&num=1'; - var date = item.getField('date'); - if (date != '') { - url += '&as_ylo=' + date + '&as_yhi=' + date; - } - var creators = item.getCreators(); if (creators.length > 0) { url += '&as_sauthors=' + encodeURIComponent(creators[0].ref.lastName).replace(/ /g, '+'); + } else { + var date = item.getField('date'); + if (date != '') { + url += '&as_ylo=' + date + '&as_yhi=' + date; + } + } + + return url; +}; + +Zotero.ScholarCitations.updateItem = function(item) { + if (typeof item.attachmentHash !== 'undefined') { + Zotero.ScholarCitations.updateNextItem(); + return; } var req = new XMLHttpRequest(); + var url = Zotero.ScholarCitations.generateItemUrl(item); req.open('GET', url, true); req.onreadystatechange = function() { @@ -149,23 +154,23 @@ Zotero.ScholarCitations.updateItem = function(item) { req.responseText); try { var old = item.getField('extra') - if (old.length == 0 || old.search(/^\d{5}$/) != -1) { - item.setField('extra', citations); - } else if (old.search(/^\d{5} *\n/) != -1) { - item.setField( - 'extra', - old.replace(/^\d{5} */, citations + ' ')); - } else if (old.search(/^\d{5} *[^\n]+/) != -1) { - item.setField( - 'extra', - old.replace(/^\d{5} */, citations + ' \n')); - } else if (old.search(/^\d{5}/) != -1) { - item.setField( - 'extra', - old.replace(/^\d{5}/, citations)); - } else { - item.setField('extra', citations + ' \n' + old); - } + if (old.length == 0 || old.search(/^\d{5}$/) != -1) { + item.setField('extra', citations); + } else if (old.search(/^\d{5} *\n/) != -1) { + item.setField( + 'extra', + old.replace(/^\d{5} */, citations + ' ')); + } else if (old.search(/^\d{5} *[^\n]+/) != -1) { + item.setField( + 'extra', + old.replace(/^\d{5} */, citations + ' \n')); + } else if (old.search(/^\d{5}/) != -1) { + item.setField( + 'extra', + old.replace(/^\d{5}/, citations)); + } else { + item.setField('extra', citations + ' \n' + old); + } item.save(); } catch (e) {} } @@ -225,6 +230,10 @@ Zotero.ScholarCitations.getCitationCount = function(responseText) { tmpString.substr(lengthOfCiteByStr, end)); }; -window.addEventListener('load', function(e) { - Zotero.ScholarCitations.init(); -}, false); +if (typeof window !== 'undefined') { + window.addEventListener('load', function(e) { + Zotero.ScholarCitations.init(); + }, false); +} + +module.exports = Zotero.ScholarCitations; diff --git a/install.rdf b/install.rdf index 3b3ea19..4d1b360 100644 --- a/install.rdf +++ b/install.rdf @@ -12,7 +12,7 @@ RDF:about="urn:mozilla:install-manifest" em:id="zoteroscholarcitations@beloglazov.info" em:name="Zotero Scholar Citations" - em:version="1.8.8" + em:version="1.9.0" em:type="2" em:creator="Anton Beloglazov" em:description="Zotero plugin for auto-fetching numbers of citations from Google Scholar" diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..08823a7 --- /dev/null +++ b/test/test.js @@ -0,0 +1,84 @@ +var zsc = require('../chrome/content/scripts/zoteroscholarcitations.js'); +var assert = require('assert'); +var sinon = require('sinon'); +var request = require('sync-request'); + +var items = [ +{ + 'citations': 400, + 'title': 'Energy-aware resource allocation heuristics for efficient management of data centers for cloud computing', + 'date': '2012', + 'creators': [{ + 'ref': { + 'firstName': 'Anton', + 'lastName': 'Beloglazov' + } + }, { + 'ref': { + 'firstName': 'Jemal', + 'lastName': 'Abawajy' + } + }, { + 'ref': { + 'firstName': 'Rajkumar', + 'lastName': 'Buyya' + } + }] +}, +{ + 'citations': 50, + 'title': 'Optimal value of information in graphical models', + 'date': '2009', + 'creators': [{ + 'ref': { + 'firstName': 'Carlos', + 'lastName': 'Guestrin', + } + }, { + 'ref': { + 'firstName': 'CMU', + 'lastName': 'EDU', + } + }] +}]; + + +function createMockItem(item) { + var mock = { + citations: item.citations, + getField: sinon.stub(), + getCreators: sinon.stub() + }; + mock.getField.withArgs('title').returns(item.title); + mock.getField.withArgs('date').returns(item.date); + mock.getCreators.returns(item.creators); + return mock; +} + +function fetchCitations(item) { + var url = zsc.generateItemUrl(item); + var res = request('GET', url); + var content = res.body.toString('utf-8'); + return parseInt(zsc.getCitationCount(content)); +} + + +suite('Zotero Scholar Citations', function() { + this.timeout(0); + + test('fillZeros', function() { + assert.equal(zsc.fillZeros(''), '00000'); + assert.equal(zsc.fillZeros('1'), '00001'); + assert.equal(zsc.fillZeros('32'), '00032'); + }); + + test('fetchCitations', function() { + items.forEach(function (item) { + var mock = createMockItem(item); + assert(fetchCitations(mock) > mock.citations); + }); + }); + + +}); +