background.js | |
---|---|
/*jshint indent:2 */
/*global chrome:true */ | |
This is the background-script that stays alive all the time, the dialog and the menu are connected to this. All main interactions, with the api or with the browser-ui are here. The communication with the menu is done via Port (messaging object from chrome) the cite-popup is handled with a single message that send, but for this we need to use a kind of a messageQueue to handle the awkful nature of the chrome-api (missing right events to interact with an created window) | (function() {
'use strict';
var debug, messageQueue, checkIntervalID, easyUtils, EasyBibUtils; |
polyfill | if (typeof String.prototype.startsWith !== 'function') { |
see below for better implementation! | String.prototype.startsWith = function(str) {
return this.indexOf(str) === 0;
};
} |
wrapping console.logs for debug purposes | debug = {
active: true,
log: function() {
if (debug.active) {
console.log.apply(console, arguments);
}
}
}; |
MessageQueue, which is needed to communicate with the cite-popup, so message is send when the tab is complete loaded | messageQueue = [];
function checkMessageQueue() {
var msg;
if (messageQueue.length === 0) {
return;
}
while (msg = messageQueue.pop()) {
var mymsg = msg; //cause gets undefined is empty - async nature of get tabs
chrome.tabs.get(msg.tabId, function(tab) {
if (tab.status !== 'complete') {
messageQueue.push(mymsg);
} else {
if (tab.url.toString().startsWith('chrome-')) {
chrome.tabs.sendMessage(mymsg.tabId, {
type: mymsg.type,
url: mymsg.url,
params: mymsg.params
});
}
}
});
}
}
checkIntervalID = window.setInterval(checkMessageQueue, 100);
EasyBibUtils = function() {};
EasyBibUtils.prototype = {
timeout: 4000, // standard - timeout for $.ajax-calls |
urls that are used by different functions | url: {
search: 'http://research.easybib.com/research/index/search?utm_campaign=toolbar&utm_source=chrome&search=',
bibliography: 'http://www.easybib.com/cite/view?utm_source=chrome&utm_campaign=toolbar',
bibliographyEntry: 'http://www.easybib.com/cite/json?list=',
autocite: 'https://autocite.citation-api.com/index/json',
citeform: 'http://www.easybib.com/mla-format/website-citation?toolbar=true',
newcitation:'http://easybib.com/rest/bulkadd',
credibility: 'http://www.easybib.com/credibility/index/json',
notebook: 'http://www.easybib.com/notebook/api/Helper_Bulk.send',
home: 'http://www.easybib.com/?utm_source=chrome&utm_campaign=toolbar',
profile: 'http://www.easybib.com/account/profile',
loggedin: 'http://www.easybib.com/account/session',
projectlist: 'http://www.easybib.com/folders/api/projects',
change_active_project: 'http://www.easybib.com/cite/view/list/' // this + the project id would change the active project |
projectlist: 'http://v5.easybib.com/list/lists' | }, |
this vars are used to cache the data, they will be reseted, if the user is clicking the refresh button | login: false,
projectlist: [],
openedFirsttime: true, |
Utility function that sets the url of the active tab in the active window. This function is used to navigate to a specific url (easybib, bibliography, search) | openUrl: function(url) {
var df = new $.Deferred();
chrome.windows.getCurrent(function(currentWindow) {
chrome.tabs.create({
url: url
}, function() {
df.resolve(true);
});
});
return df;
}, |
This function checks the credibility of the url of the active tab in the active window. @returns Deferred-Object (done: yes, may, no | fail: errormsg) | checkCredibility: function(checkurl) {
var df = new $.Deferred(),
self = this;
$.ajax({
url: self.url.credibility,
type: 'GET',
dataType: 'JSON',
timeout: self.timeout,
data: {
url: checkurl
}
}).done(function(response) {
var not_eval_msg = 'Source is not evaluated. ';
not_eval_msg += '<a href="http://content.easybib.com/students/research-guide/';
not_eval_msg += 'website-credibility-evaluation/" target="_blank" class="evaluate">Evaluate it</a>!';
if (response.status === 'error') {
df.reject(not_eval_msg);
}
if (response.status === 'not_found') {
df.reject(not_eval_msg);
}
if (response.status === 'ok') {
if ((/yes/i).test(response.info.credible)) {
df.resolve('yes');
} else if ((/maybe/i).test(response.info.credible)) {
df.resolve('may');
} else {
df.resolve('no');
}
}
}).fail(function(err) {
df.reject('Credibility could not be determined.');
});
return df;
},
getCitationID: function(projectID, currentPageURL){
var df = new $.Deferred(),
self = this,
citationExists = false;
$.ajax({
url: self.url.bibliographyEntry,
type: 'GET',
timeout: self.timeout,
data: projectID
}).done(function(response) {
var documentID;
$.each(JSON.parse(response).data, function(index, bibliographyEntry) {
if ( bibliographyEntry.doc.pubonline ) {
if ( bibliographyEntry.doc.pubonline.url === currentPageURL) {
documentID = bibliographyEntry.doc._id;
}
}
});
df.resolve(documentID);
}).fail(function(err) {
df.reject('Couldnt get document id for ' + currentPageURL);
});
return df;
}, |
This function calls autocite to generate bibliography data @returns Deferred-Object (done: yes, may, no | fail: errormsg) | createNewCitation: function(autociteData, projectID) {
var df = new $.Deferred(),
self = this;
autociteData.source = "website";
autociteData.listid = projectID;
$.ajax({
url: self.url.newcitation,
type: 'POST',
dataType: 'JSON',
timeout: self.timeout,
data: {'docs': [autociteData]}
}).done(function(response) {
df.resolve(response);
}).fail(function(err) {
df.reject('Could not call autocite.');
});
return df;
}, |
This function calls autocite to generate bibliography data @returns Deferred-Object (done: yes, may, no | fail: errormsg) | callAutocite: function(currentPageURL, projectID) {
var df = new $.Deferred(),
self = this;
$.ajax({
url: self.url.autocite + '?url=' + currentPageURL,
type: 'GET',
timeout: self.timeout |
data: currentPageURL | }).done(function(response) {
self.createNewCitation(response.data.data, projectID).then(function(resp) {
df.resolve(resp);
});
}).fail(function(err) {
df.reject('Could not call autocite.');
});
return df;
}, |
This function creates a new bibliography entry though it can be called on it's own, it's intended to be used in conjunction with functions that create new notes. @returns Deferred-Object (done: yes, may, no | fail: errormsg) | checkIfWebCitationExists: function(projectID, currentPageURL) {
var df = new $.Deferred(),
self = this,
documentID = null;
$.ajax({
url: self.url.bibliographyEntry,
type: 'GET', |
dataType: 'JSON', | timeout: self.timeout,
data: projectID
}).done(function(response) {
var documentID;
$.each(JSON.parse(response).data, function(index, bibliographyEntry) {
if ( bibliographyEntry.doc.pubonline ) {
if ( bibliographyEntry.doc.pubonline.url === currentPageURL) {
documentID = bibliographyEntry.doc._id;
df.resolve(documentID);
}
}
});
if (df.state() !== 'resolved'){
self.callAutocite(currentPageURL, projectID).done(function(result){
if (result.status == 'ok') {
var message = JSON.parse(result.message);
documentID = message[0].id;
df.resolve(documentID);
} else {
df.reject('Citation not created.');
}
});
}
}).fail(function(err) {
df.reject('Could not create new note.');
});
return df;
}, |
This function submits the contents of the clipboard to the notebook specified in the UI of the extension @returns Deferred-Object (done: yes, may, no | fail: errormsg) | addToNotebook: function(content, projectID) {
var df = new $.Deferred(),
self = this;
var randomSevenDigitNum = Math.floor(Math.random() * 9000000) + 1000000;
var randomTenDigitNum = (+new Date() + "").substr(0, 10);
var randomID = randomSevenDigitNum + '-' + randomTenDigitNum; |
var notecardTitle = content.evidence.substr(0, 20); | var notecardTitle = content.title || content.evidence.substr(0, 20);
var notecardLeft = 120;
var notecardTop = 100;
var randomInterval = (Math.floor(Math.random() * 10) + 10);
var leftPosition = randomInterval + notecardLeft + 'px';
var topPosition = randomInterval + notecardTop + 'px';
var currentTimestamp = Date.now(); |
The nomenclature for the note fields and their actual labels in the form starts to get hairy at this point. | var noteData = {
document: [{
"method": "Note.save",
"id": randomID,
"document": {
"color": "rgb(235, 235, 235)",
"id": randomID,
"title": notecardTitle,
"quote": content.evidence,
"paraphrasing": content.paraphrasing,
"source": null,
"url": "",
"left": leftPosition,
"top": topPosition,
"content": content.comment,
"type": "Note",
"timestamp": currentTimestamp,
"created_by": easyUtils.login.id
}
}],
"listId": projectID
};
self.checkIfWebCitationExists(projectID, content.currentPageURL).then(function(result) {
noteData.document[0].document.source = result;
$.ajax({
url: self.url.notebook,
type: 'POST',
dataType: 'JSON',
timeout: self.timeout,
data: $.param(noteData)
}).done(function(response) {
df.resolve(true);
}).fail(function(err) {
df.reject('Could not create new note.');
});
});
return df;
}, |
Collects Autocite - Data, if possible and then opens the citation-form on easybib.com | citeOnEasyBib: function(citeurl) {
var self = this;
self.getCiteData(citeurl)
.done(function(data) {
self.openCiteOnEasyBib(data);
})
.fail(function(err) {
self.openCiteOnEasyBib({});
});
}, |
gets autocite data for url in the active tab in the active window @returns Deferred-Object | getCiteData: function(citeurl) {
var df = new $.Deferred(),
self = this;
chrome.windows.getCurrent(function(currentWindow) {
chrome.tabs.getSelected(currentWindow.id, function(selectedTab) {
$.ajax({
url: self.url.autocite,
type: 'GET',
dataType: 'JSON',
timeout: self.timeout,
data: {
url: citeurl
}
}).done(function(resp) {
if (resp.status === 'ok') {
df.resolve(resp.data.data);
} else {
df.reject(resp);
}
}).fail(function(err) {
df.reject(err);
});
});
});
return df;
}, |
Opens cite-dialog. Works a strange, cause the api is expecting an json-post this is realized by generating a form in the new window (dialog_popup.js) and submitting it to the apis-endpoint. | openCiteOnEasyBib: function(data) {
var df = new $.Deferred(),
self = this;
chrome.windows.create({
type: 'popup',
url: 'dialog.html',
width: 590,
height: 550
}, function(nWindow) {
var tabInfo = nWindow.tabs[0],
message = {
tabId: tabInfo.id,
type: 'send_postdata',
url: self.url.citeform,
params: data
};
messageQueue.push(message);
});
}, |
check if the user is logged into easybib | getLoggedInStatus: function() {
var df = new $.Deferred(),
self = this; |
just reset the cache | easyUtils.login = false;
$.ajax({
type: 'GET',
accepts: {
json: 'application/json'
},
dataType: 'json',
url: self.url.loggedin
})
.done(function(res) {
if (res.error) {
easyUtils.login = false;
df.resolve(false);
} else {
easyUtils.login = res.data;
df.resolve(res.data);
}
})
.fail(function(err, statusText) {
easyUtils.login = false;
if (statusText === 'parsererror') {
df.resolve(false); //for now its a parse error if no session is fount
} else {
df.reject(err);
}
});
return df;
},
getProjectList: function() {
var df = new $.Deferred(),
self = this; |
just reset the cache | easyUtils.projectlist = [];
$.ajax({
type: 'GET',
accepts: {
json: 'application/json'
},
dataType: 'json',
url: self.url.projectlist
})
.done(function(res) {
easyUtils.projectlist = res;
df.resolve(res);
})
.fail(function(err, statusText) {
easyUtils.projectlist = [];
if (statusText === 'parseerror') { |
not logged in | df.resolve(false);
} else {
df.reject(err);
}
});
return df;
},
changeActiveProject: function(projectid) {
var df = new $.Deferred(),
self = this;
$.ajax({
type: 'GET',
dataType: 'html',
url: self.url.change_active_project + projectid
})
.done(function(res) { |
ok we think its done | df.resolve(true);
})
.fail(function(err) { |
something went wrong | df.reject('something went wrong');
});
return df;
}
}; |
delegating messages | easyUtils = new EasyBibUtils();
window.easyUtils = easyUtils;
window.$ = $;
chrome.extension.onConnect.addListener(function(port) {
port.onMessage.addListener(function(msg) {
if (msg.type === 'cite') {
easyUtils.citeOnEasyBib(msg.param);
} else if (msg.type === 'goeasybib') {
easyUtils.openUrl(easyUtils.url.home);
} else if (msg.type === 'gonotebook') {
easyUtils.addToNotebook(msg.content, msg.projectID)
.done(function() {
debug.log('done!');
port.postMessage({
type: 'done-creating-note',
state: 'done'
});
})
.fail(function() {
port.postMessage({
type: 'done-creating-note'
});
debug.log('note creation failed! :(');
});
} else if (msg.type === 'gobibliography') {
easyUtils.openUrl(easyUtils.url.bibliography);
} else if (msg.type === 'search') {
easyUtils.openUrl(easyUtils.url.search + msg.param);
} else if (msg.type === 'check-credibility') {
easyUtils.checkCredibility(msg.param)
.done(function(res) {
port.postMessage({
type: 'update-credibility',
state: 'done',
res: res
});
})
.fail(function(msg) {
port.postMessage({
type: 'update-credibility',
state: 'fail',
text: msg
});
});
} else if (msg.type === 'check-loginstatus') {
easyUtils.getLoggedInStatus()
.done(function(res) {
port.postMessage({
type: 'update-loginstatus',
state: 'done',
res: res
});
})
.fail(function(err) {
port.postMessage({
type: 'update-loginstatus',
state: 'fail',
res: err
});
});
} else if (msg.type === 'get-projectlist') {
easyUtils.getProjectList()
.done(function(res) {
port.postMessage({
type: 'update-projectlist',
state: 'done',
res: res
});
})
.fail(function(err) {
port.postMessage({
type: 'update-projectlist',
state: 'fail',
res: err
});
});
} else if (msg.type === 'popup-opened') { |
the popup is opened, so look into the cache and fire status if there is any other than logged out out of the cache | var loginStatus = easyUtils.login;
port.postMessage({
type: 'update-loginstatus',
state: 'done',
res: loginStatus
});
port.postMessage({
type: 'check-textselection'
});
if (easyUtils.login !== false) {
if (easyUtils.projectlist && easyUtils.projectlist.length > 0) { |
out of the cache | port.postMessage({
type: 'update-projectlist',
state: 'done',
res: easyUtils.projectlist
});
}
} else if (easyUtils.openedFirsttime) { |
if the popup is opened the first time then login status is really checked and setted after this only the refresh button would trigger this action again | easyUtils.openedFirsttime = false;
easyUtils.getLoggedInStatus()
.done(function(res) {
port.postMessage({
type: 'update-loginstatus',
state: 'done',
res: res
});
})
.fail(function(err) {
port.postMessage({
type: 'update-loginstatus',
state: 'fail',
res: err
});
});
} else {
throw new Error('obviously opened not the first time');
}
} else if (msg.type === 'change-active-project') {
easyUtils.changeActiveProject(msg.project_id);
}
});
}); |
adding webRequest listener to trigger login-status updates if the user loads /logout successfully that gets redirected by the server | chrome.webRequest.onBeforeRedirect.addListener(function(details) {
easyUtils.getLoggedInStatus()
.always(function() { |
reset the cached project list | easyUtils.projectlist = [];
});
}, {
urls: ['*://*.easybib.com/logout']
}); |
adding webRequest listener to trigger login-status updates if the user successfully logs in and loads the project list view | chrome.webRequest.onCompleted.addListener(function(details) {
easyUtils.getLoggedInStatus()
.always(function() { |
reset the cached project list | easyUtils.projectlist = [];
});
}, {
urls: ['*://*.easybib.com/list']
});
function launchPopUp() {
return function(info, tab) {
var selectionText = info.selectionText;
var url = "../context_menu_support/modal.html";
var popUpHeight = 560;
var popUpWidth = 800;
chrome.windows.create({
type: 'popup',
url: url,
height: popUpHeight,
width: popUpWidth,
left: screen.width / 2 - (popUpHeight / 2),
top: screen.height / 2 - (popUpWidth / 2)
});
};
}
}());
|