Add a connector document integration endpoint
Specifically for google docs via the connector, but could potentially be used for any integration via HTTP or connector.
This commit is contained in:
parent
7c093b4fb0
commit
5e5b567782
9 changed files with 780 additions and 438 deletions
|
@ -7,6 +7,9 @@ describe("Zotero.Integration", function () {
|
|||
const INTEGRATION_TYPE_TEMP = 3;
|
||||
/**
|
||||
* To be used as a reference for Zotero-Word Integration plugins
|
||||
*
|
||||
* NOTE: Functions must return promises instead of values!
|
||||
* The functions defined for the dummy are promisified below
|
||||
*/
|
||||
var DocumentPluginDummy = {};
|
||||
|
||||
|
@ -17,6 +20,7 @@ describe("Zotero.Integration", function () {
|
|||
this.doc = new DocumentPluginDummy.Document();
|
||||
this.primaryFieldType = "Field";
|
||||
this.secondaryFieldType = "Bookmark";
|
||||
this.supportedNotes = ['footnotes', 'endnotes'];
|
||||
this.fields = [];
|
||||
};
|
||||
DocumentPluginDummy.Application.prototype = {
|
||||
|
@ -87,26 +91,15 @@ describe("Zotero.Integration", function () {
|
|||
throw new Error("noteType must be an integer");
|
||||
}
|
||||
var field = new DocumentPluginDummy.Field(this);
|
||||
this.fields.push(field);
|
||||
return field
|
||||
this.fields.push(field);
|
||||
return field;
|
||||
},
|
||||
/**
|
||||
* Gets all fields present in the document.
|
||||
* @param {String} fieldType
|
||||
* @returns {DocumentPluginDummy.FieldEnumerator}
|
||||
* @returns {DocumentPluginDummy.Field[]}
|
||||
*/
|
||||
getFields: function(fieldType) {return new DocumentPluginDummy.FieldEnumerator(this)},
|
||||
/**
|
||||
* Gets all fields present in the document. The observer will receive notifications for two
|
||||
* topics: "fields-progress", with the document as the subject and percent progress as data, and
|
||||
* "fields-available", with an nsISimpleEnumerator of fields as the subject and the length as
|
||||
* data
|
||||
* @param {String} fieldType
|
||||
* @param {nsIObserver} observer
|
||||
*/
|
||||
getFieldsAsync: function(fieldType, observer) {
|
||||
observer.observe(this.getFields(fieldType), 'fields-available', null)
|
||||
},
|
||||
getFields: function(fieldType) {return Array.from(this.fields)},
|
||||
/**
|
||||
* Sets the bibliography style, overwriting the current values for this document
|
||||
*/
|
||||
|
@ -114,7 +107,7 @@ describe("Zotero.Integration", function () {
|
|||
tabStops, tabStopsCount) => 0,
|
||||
/**
|
||||
* Converts all fields in a document to a different fieldType or noteType
|
||||
* @params {DocumentPluginDummy.FieldEnumerator} fields
|
||||
* @params {DocumentPluginDummy.Field[]} fields
|
||||
*/
|
||||
convert: (fields, toFieldType, toNoteType, count) => 0,
|
||||
/**
|
||||
|
@ -128,14 +121,6 @@ describe("Zotero.Integration", function () {
|
|||
complete: () => 0,
|
||||
};
|
||||
|
||||
DocumentPluginDummy.FieldEnumerator = function(doc) {this.doc = doc; this.idx = 0};
|
||||
DocumentPluginDummy.FieldEnumerator.prototype = {
|
||||
hasMoreElements: function() {return this.idx < this.doc.fields.length;},
|
||||
getNext: function() {return this.doc.fields[this.idx++]},
|
||||
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports,
|
||||
Components.interfaces.nsISimpleEnumerator])
|
||||
};
|
||||
|
||||
/**
|
||||
* The Field class corresponds to a field containing an individual citation
|
||||
* or bibliography
|
||||
|
@ -197,11 +182,12 @@ describe("Zotero.Integration", function () {
|
|||
getNoteIndex: () => 0,
|
||||
};
|
||||
|
||||
for (let cls of ['Application', 'Document', 'FieldEnumerator', 'Field']) {
|
||||
// Processing functions for logging and promisification
|
||||
for (let cls of ['Application', 'Document', 'Field']) {
|
||||
for (let methodName in DocumentPluginDummy[cls].prototype) {
|
||||
if (methodName !== 'QueryInterface') {
|
||||
let method = DocumentPluginDummy[cls].prototype[methodName];
|
||||
DocumentPluginDummy[cls].prototype[methodName] = function() {
|
||||
DocumentPluginDummy[cls].prototype[methodName] = async function() {
|
||||
try {
|
||||
Zotero.debug(`DocumentPluginDummy: ${cls}.${methodName} invoked with args ${JSON.stringify(arguments)}`, 2);
|
||||
} catch (e) {
|
||||
|
@ -250,7 +236,7 @@ describe("Zotero.Integration", function () {
|
|||
editBibliographyDialog: {}
|
||||
};
|
||||
|
||||
function initDoc(docID, options={}) {
|
||||
async function initDoc(docID, options={}) {
|
||||
applications[docID] = new DocumentPluginDummy.Application();
|
||||
var data = new Zotero.Integration.DocumentData();
|
||||
data.prefs = {
|
||||
|
@ -261,7 +247,7 @@ describe("Zotero.Integration", function () {
|
|||
data.style = {styleID, locale: 'en-US', hasBibliography: true, bibliographyStyleHasBeenSet: true};
|
||||
data.sessionID = Zotero.Utilities.randomString(10);
|
||||
Object.assign(data, options);
|
||||
applications[docID].getActiveDocument().setDocumentData(data.serialize());
|
||||
await (await applications[docID].getDocument(docID)).setDocumentData(data.serialize());
|
||||
}
|
||||
|
||||
function setDefaultIntegrationDocPrefs() {
|
||||
|
@ -354,10 +340,10 @@ describe("Zotero.Integration", function () {
|
|||
var displayAlertStub;
|
||||
var style;
|
||||
before(function* () {
|
||||
displayAlertStub = sinon.stub(DocumentPluginDummy.Document.prototype, 'displayAlert').returns(0);
|
||||
displayAlertStub = sinon.stub(DocumentPluginDummy.Document.prototype, 'displayAlert').resolves(0);
|
||||
});
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(async function () {
|
||||
// 🦉birds?
|
||||
style = {styleID: "http://www.example.com/csl/waterbirds", locale: 'en-US'};
|
||||
|
||||
|
@ -365,7 +351,7 @@ describe("Zotero.Integration", function () {
|
|||
try {
|
||||
Zotero.Styles.get(style.styleID).remove();
|
||||
} catch (e) {}
|
||||
initDoc(docID, {style});
|
||||
await initDoc(docID, {style});
|
||||
displayDialogStub.resetHistory();
|
||||
displayAlertStub.reset();
|
||||
});
|
||||
|
@ -386,7 +372,7 @@ describe("Zotero.Integration", function () {
|
|||
}
|
||||
return style;
|
||||
});
|
||||
displayAlertStub.returns(1);
|
||||
displayAlertStub.resolves(1);
|
||||
yield execCommand('addEditCitation', docID);
|
||||
assert.isTrue(displayAlertStub.calledOnce);
|
||||
assert.isFalse(displayDialogStub.calledWith(applications[docID].doc, 'chrome://zotero/content/integration/integrationDocPrefs.xul'));
|
||||
|
@ -397,7 +383,7 @@ describe("Zotero.Integration", function () {
|
|||
});
|
||||
|
||||
it('should prompt with the document preferences dialog if user clicks NO', function* () {
|
||||
displayAlertStub.returns(0);
|
||||
displayAlertStub.resolves(0);
|
||||
yield execCommand('addEditCitation', docID);
|
||||
assert.isTrue(displayAlertStub.calledOnce);
|
||||
// Prefs to select a new style and quickFormat
|
||||
|
@ -407,7 +393,7 @@ describe("Zotero.Integration", function () {
|
|||
});
|
||||
|
||||
it('should download the style without prompting if it is from zotero.org', function* (){
|
||||
initDoc(docID, {styleID: "http://www.zotero.org/styles/waterbirds", locale: 'en-US'});
|
||||
yield initDoc(docID, {styleID: "http://www.zotero.org/styles/waterbirds", locale: 'en-US'});
|
||||
var styleInstallStub = sinon.stub(Zotero.Styles, "install").resolves();
|
||||
var style = Zotero.Styles.get(styleID);
|
||||
var styleGetCalledOnce = false;
|
||||
|
@ -418,7 +404,7 @@ describe("Zotero.Integration", function () {
|
|||
}
|
||||
return style;
|
||||
});
|
||||
displayAlertStub.returns(1);
|
||||
displayAlertStub.resolves(1);
|
||||
yield execCommand('addEditCitation', docID);
|
||||
assert.isFalse(displayAlertStub.called);
|
||||
assert.isFalse(displayDialogStub.calledWith(applications[docID].doc, 'chrome://zotero/content/integration/integrationDocPrefs.xul'));
|
||||
|
@ -433,20 +419,20 @@ describe("Zotero.Integration", function () {
|
|||
describe('#addEditCitation', function() {
|
||||
var insertMultipleCitations = Zotero.Promise.coroutine(function *() {
|
||||
var docID = this.test.fullTitle();
|
||||
if (!(docID in applications)) initDoc(docID);
|
||||
if (!(docID in applications)) yield initDoc(docID);
|
||||
var doc = applications[docID].doc;
|
||||
|
||||
setAddEditItems(testItems[0]);
|
||||
yield execCommand('addEditCitation', docID);
|
||||
assert.equal(doc.fields.length, 1);
|
||||
var citation = (new Zotero.Integration.CitationField(doc.fields[0], doc.fields[0].code)).unserialize();
|
||||
var citation = yield (new Zotero.Integration.CitationField(doc.fields[0], doc.fields[0].code)).unserialize();
|
||||
assert.equal(citation.citationItems.length, 1);
|
||||
assert.equal(citation.citationItems[0].id, testItems[0].id);
|
||||
|
||||
setAddEditItems(testItems.slice(1, 3));
|
||||
yield execCommand('addEditCitation', docID);
|
||||
assert.equal(doc.fields.length, 2);
|
||||
citation = (new Zotero.Integration.CitationField(doc.fields[1], doc.fields[1].code)).unserialize();
|
||||
citation = yield (new Zotero.Integration.CitationField(doc.fields[1], doc.fields[1].code)).unserialize();
|
||||
assert.equal(citation.citationItems.length, 2);
|
||||
for (let i = 1; i < 3; i++) {
|
||||
assert.equal(citation.citationItems[i-1].id, testItems[i].id);
|
||||
|
@ -459,13 +445,13 @@ describe("Zotero.Integration", function () {
|
|||
var docID = this.test.fullTitle();
|
||||
var doc = applications[docID].doc;
|
||||
|
||||
sinon.stub(doc, 'cursorInField').returns(doc.fields[0]);
|
||||
sinon.stub(doc, 'canInsertField').returns(false);
|
||||
sinon.stub(doc, 'cursorInField').resolves(doc.fields[0]);
|
||||
sinon.stub(doc, 'canInsertField').resolves(false);
|
||||
|
||||
setAddEditItems(testItems.slice(3, 5));
|
||||
yield execCommand('addEditCitation', docID);
|
||||
assert.equal(doc.fields.length, 2);
|
||||
var citation = (new Zotero.Integration.CitationField(doc.fields[0], doc.fields[0].code)).unserialize();
|
||||
var citation = yield (new Zotero.Integration.CitationField(doc.fields[0], doc.fields[0].code)).unserialize();
|
||||
assert.equal(citation.citationItems.length, 2);
|
||||
assert.equal(citation.citationItems[0].id, testItems[3].id);
|
||||
});
|
||||
|
@ -494,7 +480,7 @@ describe("Zotero.Integration", function () {
|
|||
describe('when original citation text has been modified', function() {
|
||||
var displayAlertStub;
|
||||
before(function* () {
|
||||
displayAlertStub = sinon.stub(DocumentPluginDummy.Document.prototype, 'displayAlert').returns(0);
|
||||
displayAlertStub = sinon.stub(DocumentPluginDummy.Document.prototype, 'displayAlert').resolves(0);
|
||||
});
|
||||
beforeEach(function() {
|
||||
displayAlertStub.reset();
|
||||
|
@ -508,8 +494,8 @@ describe("Zotero.Integration", function () {
|
|||
var doc = applications[docID].doc;
|
||||
|
||||
doc.fields[0].text = "modified";
|
||||
sinon.stub(doc, 'cursorInField').returns(doc.fields[0]);
|
||||
sinon.stub(doc, 'canInsertField').returns(false);
|
||||
sinon.stub(doc, 'cursorInField').resolves(doc.fields[0]);
|
||||
sinon.stub(doc, 'canInsertField').resolves(false);
|
||||
|
||||
await execCommand('addEditCitation', docID);
|
||||
assert.equal(doc.fields.length, 2);
|
||||
|
@ -523,9 +509,9 @@ describe("Zotero.Integration", function () {
|
|||
let origText = doc.fields[0].text;
|
||||
doc.fields[0].text = "modified";
|
||||
// Return OK
|
||||
displayAlertStub.returns(1);
|
||||
sinon.stub(doc, 'cursorInField').returns(doc.fields[0]);
|
||||
sinon.stub(doc, 'canInsertField').returns(false);
|
||||
displayAlertStub.resolves(1);
|
||||
sinon.stub(doc, 'cursorInField').resolves(doc.fields[0]);
|
||||
sinon.stub(doc, 'canInsertField').resolves(false);
|
||||
setAddEditItems(testItems[0]);
|
||||
|
||||
await execCommand('addEditCitation', docID);
|
||||
|
@ -538,17 +524,17 @@ describe("Zotero.Integration", function () {
|
|||
var docID = this.test.fullTitle();
|
||||
var doc = applications[docID].doc;
|
||||
|
||||
var citation = (new Zotero.Integration.CitationField(doc.fields[0], doc.fields[0].code)).unserialize();
|
||||
var citation = await (new Zotero.Integration.CitationField(doc.fields[0], doc.fields[0].code)).unserialize();
|
||||
assert.isNotOk(citation.properties.dontUpdate);
|
||||
doc.fields[0].text = "modified";
|
||||
// Return Yes
|
||||
displayAlertStub.returns(1);
|
||||
displayAlertStub.resolves(1);
|
||||
|
||||
await execCommand('refresh', docID);
|
||||
assert.isTrue(displayAlertStub.called);
|
||||
assert.equal(doc.fields.length, 2);
|
||||
assert.equal(doc.fields[0].text, "modified");
|
||||
var citation = (new Zotero.Integration.CitationField(doc.fields[0], doc.fields[0].code)).unserialize();
|
||||
var citation = await (new Zotero.Integration.CitationField(doc.fields[0], doc.fields[0].code)).unserialize();
|
||||
assert.isOk(citation.properties.dontUpdate);
|
||||
});
|
||||
it('should reset citation text if "no" selected in refresh prompt', async function() {
|
||||
|
@ -556,18 +542,18 @@ describe("Zotero.Integration", function () {
|
|||
var docID = this.test.fullTitle();
|
||||
var doc = applications[docID].doc;
|
||||
|
||||
var citation = (new Zotero.Integration.CitationField(doc.fields[0], doc.fields[0].code)).unserialize();
|
||||
var citation = await (new Zotero.Integration.CitationField(doc.fields[0], doc.fields[0].code)).unserialize();
|
||||
assert.isNotOk(citation.properties.dontUpdate);
|
||||
let origText = doc.fields[0].text;
|
||||
doc.fields[0].text = "modified";
|
||||
// Return No
|
||||
displayAlertStub.returns(0);
|
||||
displayAlertStub.resolves(0);
|
||||
|
||||
await execCommand('refresh', docID);
|
||||
assert.isTrue(displayAlertStub.called);
|
||||
assert.equal(doc.fields.length, 2);
|
||||
assert.equal(doc.fields[0].text, origText);
|
||||
var citation = (new Zotero.Integration.CitationField(doc.fields[0], doc.fields[0].code)).unserialize();
|
||||
var citation = await (new Zotero.Integration.CitationField(doc.fields[0], doc.fields[0].code)).unserialize();
|
||||
assert.isNotOk(citation.properties.dontUpdate);
|
||||
});
|
||||
});
|
||||
|
@ -673,11 +659,11 @@ describe("Zotero.Integration", function () {
|
|||
var field = setTextSpy.firstCall.thisValue;
|
||||
|
||||
for (let i = 0; i < setTextSpy.callCount; i++) {
|
||||
assert.isTrue(field.equals(setTextSpy.getCall(i).thisValue));
|
||||
assert.isTrue(yield field.equals(setTextSpy.getCall(i).thisValue));
|
||||
}
|
||||
|
||||
for (let i = 0; i < setCodeSpy.callCount; i++) {
|
||||
assert.isTrue(field.equals(setCodeSpy.getCall(i).thisValue));
|
||||
assert.isTrue(yield field.equals(setCodeSpy.getCall(i).thisValue));
|
||||
}
|
||||
|
||||
setTextSpy.restore();
|
||||
|
@ -689,7 +675,7 @@ describe("Zotero.Integration", function () {
|
|||
describe('#addEditBibliography', function() {
|
||||
var docID = this.fullTitle();
|
||||
beforeEach(function* () {
|
||||
initDoc(docID);
|
||||
yield initDoc(docID);
|
||||
yield execCommand('addEditCitation', docID);
|
||||
});
|
||||
|
||||
|
@ -699,7 +685,7 @@ describe("Zotero.Integration", function () {
|
|||
assert.isFalse(displayDialogStub.called);
|
||||
var biblPresent = false;
|
||||
for (let i = applications[docID].doc.fields.length-1; i >= 0; i--) {
|
||||
let field = Zotero.Integration.Field.loadExisting(applications[docID].doc.fields[i]);
|
||||
let field = yield Zotero.Integration.Field.loadExisting(applications[docID].doc.fields[i]);
|
||||
if (field.type == INTEGRATION_TYPE_BIBLIOGRAPHY) {
|
||||
biblPresent = true;
|
||||
break;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue