citeproc-rs support (#2220)
Disabled under zotero.cite.useCiteprocRs by default
This commit is contained in:
parent
55e8f7914b
commit
44b6cd0525
22 changed files with 7429 additions and 182 deletions
|
@ -750,7 +750,7 @@ var Zotero_File_Interface = new function() {
|
||||||
var clipboardService = Components.classes["@mozilla.org/widget/clipboard;1"].
|
var clipboardService = Components.classes["@mozilla.org/widget/clipboard;1"].
|
||||||
getService(Components.interfaces.nsIClipboard);
|
getService(Components.interfaces.nsIClipboard);
|
||||||
style = Zotero.Styles.get(style);
|
style = Zotero.Styles.get(style);
|
||||||
var cslEngine = style.getCiteProc(locale);
|
var cslEngine = style.getCiteProc(locale, 'html');
|
||||||
|
|
||||||
if (asCitations) {
|
if (asCitations) {
|
||||||
cslEngine.updateItems(items.map(item => item.id));
|
cslEngine.updateItems(items.map(item => item.id));
|
||||||
|
@ -779,11 +779,13 @@ var Zotero_File_Interface = new function() {
|
||||||
else {
|
else {
|
||||||
// Generate engine again to work around citeproc-js problem:
|
// Generate engine again to work around citeproc-js problem:
|
||||||
// https://github.com/zotero/zotero/commit/4a475ff3
|
// https://github.com/zotero/zotero/commit/4a475ff3
|
||||||
cslEngine = style.getCiteProc(locale);
|
cslEngine.free();
|
||||||
output = Zotero.Cite.makeFormattedBibliographyOrCitationList(cslEngine, items, "text");
|
cslEngine = style.getCiteProc(locale, 'text');
|
||||||
|
output = Zotero.Cite.makeFormattedBibliographyOrCitationList(cslEngine, items, 'text');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cslEngine.free();
|
||||||
|
|
||||||
var str = Components.classes["@mozilla.org/supports-string;1"].
|
var str = Components.classes["@mozilla.org/supports-string;1"].
|
||||||
createInstance(Components.interfaces.nsISupportsString);
|
createInstance(Components.interfaces.nsISupportsString);
|
||||||
str.data = output;
|
str.data = output;
|
||||||
|
@ -831,7 +833,7 @@ var Zotero_File_Interface = new function() {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var style = Zotero.Styles.get(io.style);
|
var style = Zotero.Styles.get(io.style);
|
||||||
var cslEngine = style.getCiteProc(locale);
|
var cslEngine = style.getCiteProc(locale, format);
|
||||||
var bibliography = Zotero.Cite.makeFormattedBibliographyOrCitationList(cslEngine,
|
var bibliography = Zotero.Cite.makeFormattedBibliographyOrCitationList(cslEngine,
|
||||||
items, format, io.mode === "citations");
|
items, format, io.mode === "citations");
|
||||||
}
|
}
|
||||||
|
|
|
@ -465,8 +465,7 @@ var Zotero_RTFScan = new function() {
|
||||||
// load style and create ItemSet with all items
|
// load style and create ItemSet with all items
|
||||||
var zStyle = Zotero.Styles.get(document.getElementById("style-listbox").value)
|
var zStyle = Zotero.Styles.get(document.getElementById("style-listbox").value)
|
||||||
var locale = document.getElementById("locale-menu").value;
|
var locale = document.getElementById("locale-menu").value;
|
||||||
var style = zStyle.getCiteProc(locale);
|
var style = zStyle.getCiteProc(locale, 'rtf');
|
||||||
style.setOutputFormat("rtf");
|
|
||||||
var isNote = zStyle.class == "note";
|
var isNote = zStyle.class == "note";
|
||||||
|
|
||||||
// create citations
|
// create citations
|
||||||
|
@ -563,6 +562,8 @@ var Zotero_RTFScan = new function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cslEngine.free();
|
||||||
|
|
||||||
Zotero.File.putContents(outputFile, contents);
|
Zotero.File.putContents(outputFile, contents);
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ var Zotero_CSL_Editor = new function() {
|
||||||
var selectedLocale = document.getElementById("locale-menu").value;
|
var selectedLocale = document.getElementById("locale-menu").value;
|
||||||
var styleEngine;
|
var styleEngine;
|
||||||
try {
|
try {
|
||||||
styleEngine = style.getCiteProc(style.locale || selectedLocale);
|
styleEngine = style.getCiteProc(style.locale || selectedLocale, 'html');
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
iframe.contentDocument.documentElement.innerHTML = '<div>' + Zotero.getString('styles.editor.warning.parseError') + '</div><div>'+e+'</div>';
|
iframe.contentDocument.documentElement.innerHTML = '<div>' + Zotero.getString('styles.editor.warning.parseError') + '</div><div>'+e+'</div>';
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -231,7 +231,7 @@ var Zotero_CSL_Editor = new function() {
|
||||||
iframe.contentDocument.documentElement.innerHTML = '<div>' + Zotero.getString('styles.editor.warning.renderError') + '</div><div>'+e+'</div>';
|
iframe.contentDocument.documentElement.innerHTML = '<div>' + Zotero.getString('styles.editor.warning.renderError') + '</div><div>'+e+'</div>';
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
editor.styleEngine = styleEngine;
|
styleEngine.free();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
id="csl-edit"
|
id="csl-edit"
|
||||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
onload="Zotero_CSL_Editor.init();"
|
onload="Zotero_CSL_Editor.init();"
|
||||||
|
onunload="Zotero_CSL_Editor.onUnload()"
|
||||||
title="&styles.editor;">
|
title="&styles.editor;">
|
||||||
|
|
||||||
<script src="chrome://zotero/content/include.js"/>
|
<script src="chrome://zotero/content/include.js"/>
|
||||||
|
|
|
@ -99,7 +99,7 @@ var Zotero_CSL_Preview = new function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var locale = document.getElementById("locale-menu").value;
|
var locale = document.getElementById("locale-menu").value;
|
||||||
var styleEngine = style.getCiteProc(locale);
|
var styleEngine = style.getCiteProc(locale, 'html');
|
||||||
|
|
||||||
// Generate multiple citations
|
// Generate multiple citations
|
||||||
var citations = styleEngine.previewCitationCluster(
|
var citations = styleEngine.previewCitationCluster(
|
||||||
|
@ -117,6 +117,8 @@ var Zotero_CSL_Preview = new function() {
|
||||||
bibliography = Zotero.Cite.makeFormattedBibliography(styleEngine, "html");
|
bibliography = Zotero.Cite.makeFormattedBibliography(styleEngine, "html");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
styleEngine.free();
|
||||||
|
|
||||||
return '<p>' + citations + '</p>' + bibliography;
|
return '<p>' + citations + '</p>' + bibliography;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,6 @@ Zotero.Cite = {
|
||||||
* @return {String} Bibliography in specified format
|
* @return {String} Bibliography in specified format
|
||||||
*/
|
*/
|
||||||
"makeFormattedBibliography":function makeFormattedBibliography(cslEngine, format) {
|
"makeFormattedBibliography":function makeFormattedBibliography(cslEngine, format) {
|
||||||
cslEngine.setOutputFormat(format);
|
|
||||||
var bib = cslEngine.makeBibliography();
|
var bib = cslEngine.makeBibliography();
|
||||||
if(!bib) return false;
|
if(!bib) return false;
|
||||||
|
|
||||||
|
|
285
chrome/content/zotero/xpcom/citeprocRsBridge.js
Normal file
285
chrome/content/zotero/xpcom/citeprocRsBridge.js
Normal file
|
@ -0,0 +1,285 @@
|
||||||
|
/*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright © 2019 Center for History and New Media
|
||||||
|
George Mason University, Fairfax, Virginia, USA
|
||||||
|
http://zotero.org
|
||||||
|
|
||||||
|
This file is part of Zotero.
|
||||||
|
|
||||||
|
Zotero is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Zotero is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
***** END LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
const additionalCSLProperties = ['locator', 'label', 'suppress-author', 'author-only', 'prefix', 'suffix'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bridging code which allows to use citeproc-js and citeproc-rs almost interchangeably
|
||||||
|
* without big alterations to existing Zotero code
|
||||||
|
*/
|
||||||
|
Zotero.CiteprocRs = {
|
||||||
|
init: async function () {
|
||||||
|
if (Zotero.CiteprocRs.deferred) {
|
||||||
|
return Zotero.CiteprocRs.deferred.promise;
|
||||||
|
}
|
||||||
|
Zotero.CiteprocRs.deferred = Zotero.Promise.defer();
|
||||||
|
Zotero.debug("require('citeproc_rs_wasm')");
|
||||||
|
// This is kind of nasty:
|
||||||
|
// Due to Zotero being based on an old Firefox platform we are unable to use
|
||||||
|
// the commonJS modules generated by citeproc_rs because they use too
|
||||||
|
// advanced features.
|
||||||
|
// Cormac has decided to provide a custom build just for Zotero
|
||||||
|
// where citeproc_rs_wasm_include.js attaches some classes to Zotero.CiteprocRs.
|
||||||
|
// This works fine until we call resetDB() in the test runner (or any other time we
|
||||||
|
// could call ZoteroContext.reinit(). A usual require() call returns exported symbols
|
||||||
|
// from some Gecko script cache. Unfortunately that means that the necessary citeproc
|
||||||
|
// classes do not get reattached to the Zotero object and the Citeproc Wasm driver breaks
|
||||||
|
// when trying to create its own objects (e.g. Zotero.CiteprocRs.WasmResult).
|
||||||
|
// If we try to load citeproc_rs_wasm_include as a subscript we get errors about
|
||||||
|
// let WasmResult; lines, i.e. a redeclaration of a symbol.
|
||||||
|
// So we have to load this script and provide it a custom context with just a
|
||||||
|
// Zotero symbol so that things don't break. Obviously this isn't optimal.
|
||||||
|
// This might break with an upgrade to a higher Firefox version, but perhaps then we'll
|
||||||
|
// be able to load the normal citeproc-rs CommonJS build.
|
||||||
|
Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
|
||||||
|
.getService(Components.interfaces.mozIJSSubScriptLoader)
|
||||||
|
.loadSubScript('resource://zotero/citeproc_rs_wasm_include.js',
|
||||||
|
{ Zotero });
|
||||||
|
// require('citeproc_rs_wasm_include');
|
||||||
|
const CiteprocRs = require('citeproc_rs_wasm');
|
||||||
|
// Initialize the wasm code
|
||||||
|
Zotero.debug("Loading citeproc-rs wasm binary");
|
||||||
|
const xhr = await Zotero.HTTP.request('GET', 'resource://zotero/citeproc_rs_wasm_bg.wasm', {
|
||||||
|
responseType: "arraybuffer"
|
||||||
|
});
|
||||||
|
Zotero.debug("Initializing the CiteprocRs wasm driver");
|
||||||
|
await CiteprocRs(xhr.response);
|
||||||
|
Zotero.debug("CiteprocRs driver initialized successfully");
|
||||||
|
this.Driver = CiteprocRs.Driver;
|
||||||
|
Zotero.CiteprocRs.deferred.resolve();
|
||||||
|
},
|
||||||
|
|
||||||
|
Engine: class {
|
||||||
|
constructor(system, style, styleXML, locale, format, overrideLocale=false) {
|
||||||
|
this._styleXML = styleXML;
|
||||||
|
this._overrideLocale = overrideLocale;
|
||||||
|
|
||||||
|
this.locale = locale;
|
||||||
|
|
||||||
|
this._format = format;
|
||||||
|
this._resetDriver();
|
||||||
|
|
||||||
|
this.styleID = style.styleID;
|
||||||
|
this.hasBibliography = style._hasBibliography;
|
||||||
|
this.sys = system;
|
||||||
|
this.opt = { sort_citations: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ignoreErrors=false) {
|
||||||
|
try {
|
||||||
|
Zotero.debug('CiteprocRs: free Driver', 5);
|
||||||
|
this._driver.free();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (ignoreErrors) return;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_resetDriver() {
|
||||||
|
if (this._driver) {
|
||||||
|
Zotero.debug('CiteprocRs: free Driver', 5);
|
||||||
|
this._driver.free();
|
||||||
|
}
|
||||||
|
Zotero.debug('CiteprocRs: new Driver', 5);
|
||||||
|
let options = {
|
||||||
|
style: this._styleXML,
|
||||||
|
format: this._format,
|
||||||
|
fetcher: { fetchLocale: this._fetchLocale.bind(this) },
|
||||||
|
}
|
||||||
|
if (this._overrideLocale) {
|
||||||
|
options.localeOverride = this.locale;
|
||||||
|
}
|
||||||
|
this._driver = new Zotero.CiteprocRs.Driver(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _fetchLocale(lang) {
|
||||||
|
return Zotero.Cite.System.prototype.retrieveLocale(lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
setOutputFormat(format) {
|
||||||
|
if (format == 'text') format = 'plain';
|
||||||
|
if (this._format != format) {
|
||||||
|
this._format = format;
|
||||||
|
this._driver.setOutputFormat(format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_insertCitationReferences(citation) {
|
||||||
|
let cites = [];
|
||||||
|
for (const citationItem of citation.citationItems) {
|
||||||
|
let citeprocItem = this.sys.retrieveItem(citationItem.id);
|
||||||
|
citeprocItem.id = `${citeprocItem.id}`;
|
||||||
|
Zotero.debug(`CiteprocRs: insertReference ${JSON.stringify(citeprocItem)}`, 5);
|
||||||
|
this._driver.insertReference(citeprocItem);
|
||||||
|
let cite = { id: `${citeprocItem.id}`, locator: undefined, locators: undefined };
|
||||||
|
additionalCSLProperties.forEach((key) => {
|
||||||
|
if (!citationItem[key]) return;
|
||||||
|
switch (key) {
|
||||||
|
case 'suppress-author':
|
||||||
|
cite['mode'] = "SuppressAuthor";
|
||||||
|
break;
|
||||||
|
case 'author-only':
|
||||||
|
cite['mode'] = "AuthorOnly";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cite[key] = citationItem[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cites.push(cite);
|
||||||
|
}
|
||||||
|
return cites;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getClusterOrder(citations) {
|
||||||
|
let clusters = [];
|
||||||
|
for (let [citationID, noteIndex] of citations) {
|
||||||
|
let cluster = { id: citationID };
|
||||||
|
noteIndex = typeof noteIndex == "string" ? parseInt(noteIndex) : noteIndex;
|
||||||
|
if (noteIndex) {
|
||||||
|
cluster.note = noteIndex;
|
||||||
|
}
|
||||||
|
clusters.push(cluster);
|
||||||
|
}
|
||||||
|
return clusters;
|
||||||
|
}
|
||||||
|
|
||||||
|
previewCitationCluster(citation, citationsPre, citationsPost, outputFormat) {
|
||||||
|
if (!citation.citationID) citation.citationID = Zotero.Utilities.randomString(10);
|
||||||
|
|
||||||
|
let cites = this._insertCitationReferences(citation);
|
||||||
|
let cluster = { cites };
|
||||||
|
|
||||||
|
let thisClusterOrder = {};
|
||||||
|
let noteIndex = citation.properties.noteIndex;
|
||||||
|
noteIndex = typeof noteIndex == "string" ? parseInt(noteIndex) : noteIndex;
|
||||||
|
if (noteIndex) {
|
||||||
|
thisClusterOrder.note = noteIndex;
|
||||||
|
}
|
||||||
|
let allClusterOrder = this._getClusterOrder(citationsPre.concat(citationsPost));
|
||||||
|
allClusterOrder.splice(citationsPre.length, 0, thisClusterOrder);
|
||||||
|
|
||||||
|
Zotero.debug(`CiteprocRs: previewCluster ${JSON.stringify([cluster, allClusterOrder, outputFormat])}`, 5);
|
||||||
|
return this._driver.previewCluster(cluster, allClusterOrder, outputFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is an undocumented citeproc-js endpoint that is used by Zotero from way back
|
||||||
|
// when generating citations for clipboard or export.
|
||||||
|
appendCitationCluster(citation) {
|
||||||
|
this.insertCluster(citation);
|
||||||
|
Zotero.debug(`CiteprocRs: builtCluster ${citation.citationID}`, 5);
|
||||||
|
return this._driver.builtCluster(citation.citationID);
|
||||||
|
}
|
||||||
|
|
||||||
|
insertCluster(citation) {
|
||||||
|
let cluster = { id: citation.citationID };
|
||||||
|
cluster.cites = this._insertCitationReferences(citation);
|
||||||
|
|
||||||
|
Zotero.debug(`CiteprocRs: insertCluster ${JSON.stringify(cluster)}`, 5);
|
||||||
|
this._driver.insertCluster(cluster);
|
||||||
|
return cluster;
|
||||||
|
}
|
||||||
|
|
||||||
|
setClusterOrder(citations) {
|
||||||
|
let clusters = this._getClusterOrder(citations);
|
||||||
|
Zotero.debug(`CiteprocRs: setClusterOrder ${JSON.stringify(clusters)}`, 5);
|
||||||
|
this._driver.setClusterOrder(clusters);
|
||||||
|
}
|
||||||
|
|
||||||
|
getBatchedUpdates() {
|
||||||
|
Zotero.debug(`CiteprocRs: batchedUpdates`, 5);
|
||||||
|
return this._driver.batchedUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
rebuildProcessorState(citations, format, uncited) {
|
||||||
|
this._format = format;
|
||||||
|
this._resetDriver();
|
||||||
|
for (let citation of citations) {
|
||||||
|
this.insertCluster(citation);
|
||||||
|
}
|
||||||
|
this.setClusterOrder(citations.map(
|
||||||
|
citation => [citation.citationID, citation.properties.noteIndex]));
|
||||||
|
this.updateUncitedItems(uncited);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUncitedItems(itemIDs) {
|
||||||
|
let referenceIDs = [];
|
||||||
|
for (let id of itemIDs) {
|
||||||
|
let citeprocItem = this.sys.retrieveItem(id);
|
||||||
|
citeprocItem.id = `${citeprocItem.id}`;
|
||||||
|
referenceIDs.push(citeprocItem.id);
|
||||||
|
Zotero.debug(`CiteprocRs: insertReference ${JSON.stringify(citeprocItem)}`, 5);
|
||||||
|
this._driver.insertReference(citeprocItem);
|
||||||
|
}
|
||||||
|
Zotero.debug(`CiteprocRs: includeUncitedItems ${JSON.stringify(referenceIDs)}`);
|
||||||
|
this._driver.includeUncited({ Specific: referenceIDs });
|
||||||
|
}
|
||||||
|
|
||||||
|
updateItems(itemIDs) {
|
||||||
|
Zotero.debug('CiteprocRstoJs: updateItems [forwarding to updateUncitedItems()]');
|
||||||
|
return this.updateUncitedItems(itemIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
makeBibliography() {
|
||||||
|
Zotero.debug(`CiteprocRs: bibliographyMeta`, 5);
|
||||||
|
|
||||||
|
// Converting from the wrongly documented citeproc-rs return format
|
||||||
|
// to the poorly named citeproc-js format. Sigh.
|
||||||
|
let bibliographyMeta = this._driver.bibliographyMeta();
|
||||||
|
bibliographyMeta = Object.assign(bibliographyMeta, {
|
||||||
|
maxoffset: bibliographyMeta.maxOffset,
|
||||||
|
linespacing: bibliographyMeta.lineSpacing,
|
||||||
|
entryspacing: bibliographyMeta.entrySpacing,
|
||||||
|
hangingindent: bibliographyMeta.hangingIndent,
|
||||||
|
bibstart: bibliographyMeta.formatMeta && bibliographyMeta.formatMeta.markupPre,
|
||||||
|
bibend: bibliographyMeta.formatMeta && bibliographyMeta.formatMeta.markupPost,
|
||||||
|
});
|
||||||
|
bibliographyMeta['second-field-align'] = bibliographyMeta.secondFieldAlign;
|
||||||
|
|
||||||
|
Zotero.debug(`CiteprocRs: makeBibliography`, 5);
|
||||||
|
const bibliographyEntries = this._driver.makeBibliography();
|
||||||
|
// Crazy citeproc-js behavior here
|
||||||
|
const entry_ids = bibliographyEntries.map(entry => [entry.id]);
|
||||||
|
let strings;
|
||||||
|
if (this._format == 'html') {
|
||||||
|
strings = bibliographyEntries.map(entry => `<div class="csl-entry">${entry.value}</div>`);
|
||||||
|
}
|
||||||
|
else if (this._format == 'plain') {
|
||||||
|
strings = bibliographyEntries.map(entry => `${entry.value}\n`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strings = bibliographyEntries.map(entry => entry.value);
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
Object.assign({ entry_ids }, bibliographyMeta),
|
||||||
|
strings
|
||||||
|
];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
|
@ -263,7 +263,7 @@ Zotero.Integration = new function() {
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
if (!(e instanceof Zotero.Exception.UserCancelled)) {
|
if (!(e instanceof Zotero.Exception.UserCancelled)) {
|
||||||
Zotero.Integration._handleCommandError(document, e);
|
Zotero.Integration._handleCommandError(document, session, e);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (session) {
|
if (session) {
|
||||||
|
@ -318,7 +318,7 @@ Zotero.Integration = new function() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this._handleCommandError = async function (document, e) {
|
this._handleCommandError = async function (document, session, e) {
|
||||||
try {
|
try {
|
||||||
const supportURL = "https://www.zotero.org/support/kb/debugging_broken_documents";
|
const supportURL = "https://www.zotero.org/support/kb/debugging_broken_documents";
|
||||||
var displayError;
|
var displayError;
|
||||||
|
@ -370,6 +370,12 @@ Zotero.Integration = new function() {
|
||||||
if (index == 1) {
|
if (index == 1) {
|
||||||
Zotero.launchURL(supportURL);
|
Zotero.launchURL(supportURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the driver panicked we cannot reuse it
|
||||||
|
if (e instanceof Zotero.CiteprocRs.CiteprocRsDriverError) {
|
||||||
|
session.style.free(true);
|
||||||
|
delete Zotero.Integration.sessions[session.id];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
Zotero.logError(e);
|
Zotero.logError(e);
|
||||||
|
@ -1782,8 +1788,10 @@ Zotero.Integration.Session.prototype.setData = async function (data, resetStyle)
|
||||||
await Zotero.Styles.init();
|
await Zotero.Styles.init();
|
||||||
var getStyle = Zotero.Styles.get(data.style.styleID);
|
var getStyle = Zotero.Styles.get(data.style.styleID);
|
||||||
data.style.hasBibliography = getStyle.hasBibliography;
|
data.style.hasBibliography = getStyle.hasBibliography;
|
||||||
this.style = getStyle.getCiteProc(data.style.locale, data.prefs.automaticJournalAbbreviations);
|
if (this.style && this.style.free) {
|
||||||
this.style.setOutputFormat(this.outputFormat);
|
this.style.free();
|
||||||
|
}
|
||||||
|
this.style = getStyle.getCiteProc(data.style.locale, this.outputFormat, data.prefs.automaticJournalAbbreviations);
|
||||||
this.styleClass = getStyle.class;
|
this.styleClass = getStyle.class;
|
||||||
// We're changing the citeproc instance, so we'll have to reinsert all citations into the registry
|
// We're changing the citeproc instance, so we'll have to reinsert all citations into the registry
|
||||||
this.reload = true;
|
this.reload = true;
|
||||||
|
@ -2038,6 +2046,9 @@ Zotero.Integration.Session.prototype.getCiteprocLists = function() {
|
||||||
* Updates the list of citations to be serialized to the document
|
* Updates the list of citations to be serialized to the document
|
||||||
*/
|
*/
|
||||||
Zotero.Integration.Session.prototype._updateCitations = async function () {
|
Zotero.Integration.Session.prototype._updateCitations = async function () {
|
||||||
|
if (Zotero.Prefs.get('cite.useCiteprocRs')) {
|
||||||
|
return this._updateCitationsCiteprocRs();
|
||||||
|
}
|
||||||
Zotero.debug("Integration: Indices of new citations");
|
Zotero.debug("Integration: Indices of new citations");
|
||||||
Zotero.debug(Object.keys(this.newIndices));
|
Zotero.debug(Object.keys(this.newIndices));
|
||||||
Zotero.debug("Integration: Indices of updated citations");
|
Zotero.debug("Integration: Indices of updated citations");
|
||||||
|
@ -2080,6 +2091,52 @@ Zotero.Integration.Session.prototype._updateCitations = async function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the list of citations to be serialized to the document with citeproc-rs
|
||||||
|
*/
|
||||||
|
Zotero.Integration.Session.prototype._updateCitationsCiteprocRs = async function () {
|
||||||
|
Zotero.debug("Integration: Indices of new citations");
|
||||||
|
Zotero.debug(Object.keys(this.newIndices));
|
||||||
|
Zotero.debug("Integration: Indices of updated citations");
|
||||||
|
Zotero.debug(Object.keys(this.updateIndices));
|
||||||
|
|
||||||
|
for (let indexList of [this.newIndices, this.updateIndices]) {
|
||||||
|
for (let index in indexList) {
|
||||||
|
if (indexList == this.newIndices) {
|
||||||
|
delete this.newIndices[index];
|
||||||
|
delete this.updateIndices[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
var citation = this.citationsByIndex[index];
|
||||||
|
citation = citation.toJSON();
|
||||||
|
|
||||||
|
Zotero.debug(`Integration: citeprocRs.insertCluster(${citation.toSource()})`);
|
||||||
|
this.style.insertCluster(citation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let citationIDToIndex = {};
|
||||||
|
for (const key in this.citationsByIndex) {
|
||||||
|
citationIDToIndex[this.citationsByIndex[key].citationID] = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
const citations = this.getCiteprocLists()[0];
|
||||||
|
Zotero.debug("Integration: citeprocRs.setClusterOrder()");
|
||||||
|
this.style.setClusterOrder(citations);
|
||||||
|
Zotero.debug("Integration: citeprocRs.getBatchedUpdates()");
|
||||||
|
const updateSummary = this.style.getBatchedUpdates();
|
||||||
|
Zotero.debug("Integration: got UpdateSummary from citeprocRs");
|
||||||
|
for (const [citationID, text] of updateSummary.clusters) {
|
||||||
|
const index = citationIDToIndex[citationID];
|
||||||
|
this.citationsByIndex[index].text = text;
|
||||||
|
this.processIndices[index] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bibliographyHasChanged |= updateSummary.bibliography
|
||||||
|
&& Object.keys(updateSummary.bibliography.updatedEntries).length;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores processor state from document, without requesting citation updates
|
* Restores processor state from document, without requesting citation updates
|
||||||
*/
|
*/
|
||||||
|
@ -2844,6 +2901,14 @@ Zotero.Integration.BibliographyField = class extends Zotero.Integration.Field {
|
||||||
};
|
};
|
||||||
|
|
||||||
Zotero.Integration.Citation = class {
|
Zotero.Integration.Citation = class {
|
||||||
|
static refreshEmbeddedData(itemData) {
|
||||||
|
if (itemData.shortTitle) {
|
||||||
|
itemData['title-short'] = itemData.shortTitle;
|
||||||
|
delete itemData.shortTitle;
|
||||||
|
}
|
||||||
|
return itemData;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(citationField, data, noteIndex) {
|
constructor(citationField, data, noteIndex) {
|
||||||
data = Object.assign({ citationItems: [], properties: {} }, data)
|
data = Object.assign({ citationItems: [], properties: {} }, data)
|
||||||
this.citationID = data.citationID;
|
this.citationID = data.citationID;
|
||||||
|
@ -2914,6 +2979,7 @@ Zotero.Integration.Citation = class {
|
||||||
// Use embedded item
|
// Use embedded item
|
||||||
if (citationItem.itemData) {
|
if (citationItem.itemData) {
|
||||||
Zotero.debug(`Item ${JSON.stringify(citationItem.uris)} not in library. Using embedded data`);
|
Zotero.debug(`Item ${JSON.stringify(citationItem.uris)} not in library. Using embedded data`);
|
||||||
|
citationItem.itemData = Zotero.Integration.Citation.refreshEmbeddedData(citationItem.itemData);
|
||||||
// add new embedded item
|
// add new embedded item
|
||||||
var itemData = Zotero.Utilities.deepCopy(citationItem.itemData);
|
var itemData = Zotero.Utilities.deepCopy(citationItem.itemData);
|
||||||
|
|
||||||
|
@ -3017,7 +3083,7 @@ Zotero.Integration.Citation = class {
|
||||||
// make sure it's going to get updated
|
// make sure it's going to get updated
|
||||||
delete this.properties["formattedCitation"];
|
delete this.properties["formattedCitation"];
|
||||||
delete this.properties["plainCitation"];
|
delete this.properties["plainCitation"];
|
||||||
delete this.properties["dontUpdate"];
|
delete this.properties["dontUpdate"];
|
||||||
|
|
||||||
// Load items to be displayed in edit dialog
|
// Load items to be displayed in edit dialog
|
||||||
await this.loadItemData();
|
await this.loadItemData();
|
||||||
|
@ -3049,17 +3115,11 @@ Zotero.Integration.Citation = class {
|
||||||
serializeCitationItem.id = citationItem.id;
|
serializeCitationItem.id = citationItem.id;
|
||||||
serializeCitationItem.uris = citationItem.uris;
|
serializeCitationItem.uris = citationItem.uris;
|
||||||
|
|
||||||
// XXX For compatibility with Zotero 2.0; to be removed at a later date
|
|
||||||
serializeCitationItem.uri = serializeCitationItem.uris;
|
|
||||||
|
|
||||||
// always store itemData, since we have no way to get it back otherwise
|
// always store itemData, since we have no way to get it back otherwise
|
||||||
serializeCitationItem.itemData = citationItem.itemData;
|
serializeCitationItem.itemData = citationItem.itemData;
|
||||||
} else {
|
} else {
|
||||||
serializeCitationItem.id = citationItem.id;
|
serializeCitationItem.id = citationItem.id;
|
||||||
serializeCitationItem.uris = Zotero.Integration.currentSession.uriMap.getURIsForItemID(citationItem.id);
|
serializeCitationItem.uris = Zotero.Integration.currentSession.uriMap.getURIsForItemID(citationItem.id);
|
||||||
|
|
||||||
// XXX For compatibility with Zotero 2.0; to be removed at a later date
|
|
||||||
serializeCitationItem.uri = serializeCitationItem.uris;
|
|
||||||
|
|
||||||
serializeCitationItem.itemData = Zotero.Integration.currentSession.style.sys.retrieveItem(citationItem.id);
|
serializeCitationItem.itemData = Zotero.Integration.currentSession.style.sys.retrieveItem(citationItem.id);
|
||||||
}
|
}
|
||||||
|
@ -3184,7 +3244,6 @@ Zotero.Integration.Bibliography = class {
|
||||||
|
|
||||||
Zotero.debug(`Integration: style.updateUncitedItems ${Array.from(this.uncitedItemIDs.values()).toSource()}`);
|
Zotero.debug(`Integration: style.updateUncitedItems ${Array.from(this.uncitedItemIDs.values()).toSource()}`);
|
||||||
citeproc.updateUncitedItems(Array.from(this.uncitedItemIDs.values()));
|
citeproc.updateUncitedItems(Array.from(this.uncitedItemIDs.values()));
|
||||||
citeproc.setOutputFormat(Zotero.Integration.currentSession.outputFormat);
|
|
||||||
let bibliography = citeproc.makeBibliography();
|
let bibliography = citeproc.makeBibliography();
|
||||||
Zotero.Cite.removeFromBibliography(bibliography, this.omittedItemIDs);
|
Zotero.Cite.removeFromBibliography(bibliography, this.omittedItemIDs);
|
||||||
|
|
||||||
|
|
|
@ -288,13 +288,16 @@ Zotero.QuickCopy = new function() {
|
||||||
properties: {}
|
properties: {}
|
||||||
};
|
};
|
||||||
var html = csl.previewCitationCluster(citation, [], [], "html");
|
var html = csl.previewCitationCluster(citation, [], [], "html");
|
||||||
var text = csl.previewCitationCluster(citation, [], [], "text");
|
var text = csl.previewCitationCluster(citation, [], [], "text");
|
||||||
|
csl.free();
|
||||||
} else {
|
} else {
|
||||||
var style = Zotero.Styles.get(format.id);
|
var style = Zotero.Styles.get(format.id);
|
||||||
var cslEngine = style.getCiteProc(locale);
|
var cslEngine = style.getCiteProc(locale, 'html');
|
||||||
var html = Zotero.Cite.makeFormattedBibliographyOrCitationList(cslEngine, items, "html");
|
var html = Zotero.Cite.makeFormattedBibliographyOrCitationList(cslEngine, items, "html");
|
||||||
cslEngine = style.getCiteProc(locale);
|
cslEngine.free();
|
||||||
|
cslEngine = style.getCiteProc(locale, 'text');
|
||||||
var text = Zotero.Cite.makeFormattedBibliographyOrCitationList(cslEngine, items, "text");
|
var text = Zotero.Cite.makeFormattedBibliographyOrCitationList(cslEngine, items, "text");
|
||||||
|
cslEngine.free();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {text:(format.contentType == "html" ? html : text), html:html};
|
return {text:(format.contentType == "html" ? html : text), html:html};
|
||||||
|
|
|
@ -45,6 +45,8 @@ Zotero.Styles = new function() {
|
||||||
* Initializes styles cache, loading metadata for styles into memory
|
* Initializes styles cache, loading metadata for styles into memory
|
||||||
*/
|
*/
|
||||||
this.init = Zotero.Promise.coroutine(function* (options = {}) {
|
this.init = Zotero.Promise.coroutine(function* (options = {}) {
|
||||||
|
yield Zotero.CiteprocRs.init();
|
||||||
|
|
||||||
// Wait until bundled files have been updated, except when this is called by the schema update
|
// Wait until bundled files have been updated, except when this is called by the schema update
|
||||||
// code itself
|
// code itself
|
||||||
if (!options.fromSchemaUpdate) {
|
if (!options.fromSchemaUpdate) {
|
||||||
|
@ -682,15 +684,17 @@ Zotero.Style = function (style, path) {
|
||||||
/**
|
/**
|
||||||
* Get a citeproc-js CSL.Engine instance
|
* Get a citeproc-js CSL.Engine instance
|
||||||
* @param {String} locale Locale code
|
* @param {String} locale Locale code
|
||||||
|
* @param {String} format Output format one of [rtf, html, text]
|
||||||
* @param {Boolean} automaticJournalAbbreviations Whether to automatically abbreviate titles
|
* @param {Boolean} automaticJournalAbbreviations Whether to automatically abbreviate titles
|
||||||
*/
|
*/
|
||||||
Zotero.Style.prototype.getCiteProc = function(locale, automaticJournalAbbreviations) {
|
Zotero.Style.prototype.getCiteProc = function(locale, format, automaticJournalAbbreviations) {
|
||||||
if(!locale) {
|
if(!locale) {
|
||||||
var locale = Zotero.locale;
|
var locale = Zotero.locale;
|
||||||
if(!locale) {
|
if(!locale) {
|
||||||
var locale = 'en-US';
|
var locale = 'en-US';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
format = format || 'text';
|
||||||
|
|
||||||
// APA and some similar styles capitalize the first word of subtitles
|
// APA and some similar styles capitalize the first word of subtitles
|
||||||
var uppercaseSubtitlesRE = /^apa($|-)|^academy-of-management($|-)|^(freshwater-science)/;
|
var uppercaseSubtitlesRE = /^apa($|-)|^academy-of-management($|-)|^(freshwater-science)/;
|
||||||
|
@ -757,19 +761,36 @@ Zotero.Style.prototype.getCiteProc = function(locale, automaticJournalAbbreviati
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var citeproc = new Zotero.CiteProc.CSL.Engine(
|
var citeproc;
|
||||||
new Zotero.Cite.System({
|
if (Zotero.Prefs.get('cite.useCiteprocRs')) {
|
||||||
automaticJournalAbbreviations,
|
citeproc = new Zotero.CiteprocRs.Engine(
|
||||||
uppercaseSubtitles
|
new Zotero.Cite.System({
|
||||||
}),
|
automaticJournalAbbreviations,
|
||||||
xml,
|
uppercaseSubtitles: uppercaseSubtitles
|
||||||
locale,
|
}),
|
||||||
overrideLocale
|
this,
|
||||||
);
|
xml,
|
||||||
|
locale,
|
||||||
citeproc.opt.development_extensions.wrap_url_and_doi = true;
|
format == 'text' ? 'plain' : format,
|
||||||
// Don't try to parse author names. We parse them in itemToCSLJSON
|
overrideLocale
|
||||||
citeproc.opt.development_extensions.parse_names = false;
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
citeproc = new Zotero.CiteProc.CSL.Engine(
|
||||||
|
new Zotero.Cite.System({
|
||||||
|
automaticJournalAbbreviations,
|
||||||
|
uppercaseSubtitles
|
||||||
|
}),
|
||||||
|
xml,
|
||||||
|
locale,
|
||||||
|
overrideLocale
|
||||||
|
);
|
||||||
|
citeproc.setOutputFormat(format);
|
||||||
|
citeproc.free = () => 0;
|
||||||
|
citeproc.opt.development_extensions.wrap_url_and_doi = true;
|
||||||
|
// Don't try to parse author names. We parse them in itemToCSLJSON
|
||||||
|
citeproc.opt.development_extensions.parse_names = false;
|
||||||
|
}
|
||||||
|
|
||||||
return citeproc;
|
return citeproc;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 10ffb4a766ce7d43aac3b321863a4e585669be02
|
Subproject commit 9390fa2a4fd749688f2cf78e8a62a716643f4b90
|
|
@ -70,6 +70,7 @@ const xpcomFilesLocal = [
|
||||||
'api',
|
'api',
|
||||||
'attachments',
|
'attachments',
|
||||||
'cite',
|
'cite',
|
||||||
|
'citeprocRsBridge',
|
||||||
'cookieSandbox',
|
'cookieSandbox',
|
||||||
'data/library',
|
'data/library',
|
||||||
'data/libraries',
|
'data/libraries',
|
||||||
|
|
|
@ -116,6 +116,7 @@ pref("extensions.zotero.export.bibliographySettings", "save-as-rtf");
|
||||||
pref("extensions.zotero.export.displayCharsetOption", true);
|
pref("extensions.zotero.export.displayCharsetOption", true);
|
||||||
pref("extensions.zotero.export.citePaperJournalArticleURL", false);
|
pref("extensions.zotero.export.citePaperJournalArticleURL", false);
|
||||||
pref("extensions.zotero.cite.automaticJournalAbbreviations", true);
|
pref("extensions.zotero.cite.automaticJournalAbbreviations", true);
|
||||||
|
pref("extensions.zotero.cite.useCiteprocRs", false);
|
||||||
pref("extensions.zotero.import.charset", "auto");
|
pref("extensions.zotero.import.charset", "auto");
|
||||||
pref("extensions.zotero.import.createNewCollection.fromFileOpenHandler", true);
|
pref("extensions.zotero.import.createNewCollection.fromFileOpenHandler", true);
|
||||||
pref("extensions.zotero.rtfScan.lastInputFile", "");
|
pref("extensions.zotero.rtfScan.lastInputFile", "");
|
||||||
|
|
6963
package-lock.json
generated
6963
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -15,6 +15,7 @@
|
||||||
},
|
},
|
||||||
"license": "",
|
"license": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@citeproc-rs/wasm": "^0.2.0",
|
||||||
"ace-builds": "^1.4.12",
|
"ace-builds": "^1.4.12",
|
||||||
"bluebird": "^3.5.1",
|
"bluebird": "^3.5.1",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
|
|
1
resource/citeproc_rs_wasm.js
Symbolic link
1
resource/citeproc_rs_wasm.js
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../node_modules/@citeproc-rs/wasm/_zotero/citeproc_rs_wasm.js
|
1
resource/citeproc_rs_wasm_bg.wasm
Symbolic link
1
resource/citeproc_rs_wasm_bg.wasm
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../node_modules/@citeproc-rs/wasm/_zotero/citeproc_rs_wasm_bg.wasm
|
1
resource/citeproc_rs_wasm_include.js
Symbolic link
1
resource/citeproc_rs_wasm_include.js
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../node_modules/@citeproc-rs/wasm/_zotero/citeproc_rs_wasm_include.js
|
|
@ -1,7 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var require = (function() {
|
var require = (function() {
|
||||||
var win, Zotero;
|
var win, cons, Zotero;
|
||||||
Components.utils.import('resource://zotero/loader.jsm');
|
Components.utils.import('resource://zotero/loader.jsm');
|
||||||
var requirer = Module('/', '/');
|
var requirer = Module('/', '/');
|
||||||
var _runningTimers = {};
|
var _runningTimers = {};
|
||||||
|
@ -72,7 +72,6 @@ var require = (function() {
|
||||||
return Zotero || {};
|
return Zotero || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
var cons;
|
|
||||||
if (typeof win.console !== 'undefined') {
|
if (typeof win.console !== 'undefined') {
|
||||||
cons = console;
|
cons = console;
|
||||||
}
|
}
|
||||||
|
@ -82,6 +81,9 @@ var require = (function() {
|
||||||
cons[key] = text => {getZotero(); typeof Zotero !== 'undefined' && false && Zotero.debug(`console.${key}: ${text}`)};
|
cons[key] = text => {getZotero(); typeof Zotero !== 'undefined' && false && Zotero.debug(`console.${key}: ${text}`)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!win.console) {
|
||||||
|
win.console = cons;
|
||||||
|
}
|
||||||
let globals = {
|
let globals = {
|
||||||
window: win,
|
window: win,
|
||||||
document: typeof win.document !== 'undefined' && win.document || {},
|
document: typeof win.document !== 'undefined' && win.document || {},
|
||||||
|
@ -90,7 +92,9 @@ var require = (function() {
|
||||||
setTimeout: win.setTimeout,
|
setTimeout: win.setTimeout,
|
||||||
clearTimeout: win.clearTimeout,
|
clearTimeout: win.clearTimeout,
|
||||||
requestAnimationFrame: win.setTimeout,
|
requestAnimationFrame: win.setTimeout,
|
||||||
cancelAnimationFrame: win.clearTimeout
|
cancelAnimationFrame: win.clearTimeout,
|
||||||
|
TextEncoder: TextEncoder,
|
||||||
|
TextDecoder: TextDecoder,
|
||||||
};
|
};
|
||||||
Object.defineProperty(globals, 'Zotero', { get: getZotero });
|
Object.defineProperty(globals, 'Zotero', { get: getZotero });
|
||||||
var loader = Loader({
|
var loader = Loader({
|
||||||
|
|
|
@ -47,7 +47,6 @@ async function babelWorker(ev) {
|
||||||
.replace('document.body.appendChild(scrollDiv)', 'document.documentElement.appendChild(scrollDiv)')
|
.replace('document.body.appendChild(scrollDiv)', 'document.documentElement.appendChild(scrollDiv)')
|
||||||
.replace('document.body.removeChild(scrollDiv)', 'document.documentElement.removeChild(scrollDiv)');
|
.replace('document.body.removeChild(scrollDiv)', 'document.documentElement.removeChild(scrollDiv)');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch single-file
|
// Patch single-file
|
||||||
else if (sourcefile === 'resource/SingleFile/dist/single-file.js') {
|
else if (sourcefile === 'resource/SingleFile/dist/single-file.js') {
|
||||||
// Change for what I assume is a bug in Firefox. We create a singlefile
|
// Change for what I assume is a bug in Firefox. We create a singlefile
|
||||||
|
|
|
@ -53,7 +53,8 @@ const symlinkFiles = [
|
||||||
// Feed *.idl files are for documentation only
|
// Feed *.idl files are for documentation only
|
||||||
'!resource/feeds/*.idl',
|
'!resource/feeds/*.idl',
|
||||||
'update.rdf',
|
'update.rdf',
|
||||||
'!chrome/skin/default/zotero/**/*.scss'
|
'!chrome/skin/default/zotero/**/*.scss',
|
||||||
|
'!resource/citeproc_rs_wasm.js',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,7 +109,8 @@ const jsFiles = [
|
||||||
'resource/react.js',
|
'resource/react.js',
|
||||||
'resource/react-dom.js',
|
'resource/react-dom.js',
|
||||||
'resource/react-virtualized.js',
|
'resource/react-virtualized.js',
|
||||||
'resource/SingleFile/dist/single-file.js'
|
'resource/SingleFile/dist/single-file.js',
|
||||||
|
'resource/citeproc_rs_wasm.js',
|
||||||
];
|
];
|
||||||
|
|
||||||
const scssFiles = [
|
const scssFiles = [
|
||||||
|
|
170
test/tests/citeprocRsBridgeTest.js
Normal file
170
test/tests/citeprocRsBridgeTest.js
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("Zotero.CiteprocRs", function () {
|
||||||
|
var chicagoNoteStyleID = "http://www.zotero.org/styles/chicago-note-bibliography";
|
||||||
|
var chicagoAuthorDateStyleID = "http://www.zotero.org/styles/chicago-author-date";
|
||||||
|
var style;
|
||||||
|
function getCiteprocJSEngine(style) {
|
||||||
|
Zotero.Prefs.set('cite.useCiteprocRs', false);
|
||||||
|
return style.getCiteProc('en-US', 'text');
|
||||||
|
}
|
||||||
|
function getCiteprocRSEngine(style) {
|
||||||
|
Zotero.Prefs.set('cite.useCiteprocRs', true);
|
||||||
|
return style.getCiteProc('en-US', 'text');
|
||||||
|
}
|
||||||
|
function createCitationItem(item) {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
uris: Zotero.Utilities.randomString(10),
|
||||||
|
itemData: Zotero.Cite.System.prototype.retrieveItem(item.id)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function createACitation(items) {
|
||||||
|
if (!Array.isArray(items)) items = [items];
|
||||||
|
return {
|
||||||
|
citationID: Zotero.Utilities.randomString(10),
|
||||||
|
citationItems: items.map(createCitationItem),
|
||||||
|
properties: { noteIndex: noteIndex++ }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function assertProducedCitationsAreEqual(citation) {
|
||||||
|
citeprocRS.insertCluster(citation);
|
||||||
|
citeprocRS.setClusterOrder([[citation.citationID, citation.properties.noteIndex]]);
|
||||||
|
let updateSummary = citeprocRS.getBatchedUpdates();
|
||||||
|
let CRSCitation = updateSummary.clusters[0][1];
|
||||||
|
let CRSBibl = Zotero.Cite.makeFormattedBibliography(citeprocRS, 'text');
|
||||||
|
|
||||||
|
// We need to deepcopy before passing to citeproc-js, because it doesn't respect
|
||||||
|
// our objects and just writes stuff all over them.
|
||||||
|
let [_, citationInfo] = citeprocJS.processCitationCluster(citation, [], []);
|
||||||
|
let CJSCitation = citationInfo[0][1];
|
||||||
|
let CJSBibl = Zotero.Cite.makeFormattedBibliography(citeprocJS, 'text');
|
||||||
|
|
||||||
|
Zotero.debug(`\nciteproc-js: ${CJSCitation}\nciteproc-rs: ${CRSCitation}`, 2);
|
||||||
|
Zotero.debug(`\nciteproc-js: ${CJSBibl}\nciteproc-rs: ${CRSBibl}`, 2);
|
||||||
|
|
||||||
|
assert.equal(CJSCitation, CRSCitation, 'citations are equal');
|
||||||
|
assert.deepEqual(CJSBibl, CRSBibl, 'bibliographies are equal');
|
||||||
|
}
|
||||||
|
|
||||||
|
var item1, item2SameLastName, item3;
|
||||||
|
var citeprocRS, citeprocJS;
|
||||||
|
var noteIndex = 1;
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
await Zotero.Styles.init();
|
||||||
|
item1 = createUnsavedDataObject(
|
||||||
|
'item',
|
||||||
|
{
|
||||||
|
itemType: 'book',
|
||||||
|
title: 'Test book'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
item1.libraryID = Zotero.Libraries.userLibraryID;
|
||||||
|
item1.setField('date', '2021');
|
||||||
|
item1.setCreators([
|
||||||
|
{
|
||||||
|
firstName: "First1",
|
||||||
|
lastName: "Last1",
|
||||||
|
creatorType: "author"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
item2SameLastName = item1.clone();
|
||||||
|
item2SameLastName.setField('title', 'Test book 2');
|
||||||
|
item2SameLastName.setCreators([
|
||||||
|
{
|
||||||
|
firstName: "DifferentFirst2",
|
||||||
|
lastName: "Last1",
|
||||||
|
creatorType: "author"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
item3 = item1.clone();
|
||||||
|
item3.setCreators([
|
||||||
|
{
|
||||||
|
firstName: "First3",
|
||||||
|
lastName: "Last3",
|
||||||
|
creatorType: "author"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
await Zotero.Promise.all([item1.saveTx(), item2SameLastName.saveTx(), item3.saveTx()]);
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function () {
|
||||||
|
Zotero.Prefs.set('cite.useCiteprocRs', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
noteIndex = 1;
|
||||||
|
citeprocJS = getCiteprocJSEngine(style);
|
||||||
|
citeprocRS = getCiteprocRSEngine(style);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
citeprocJS.free();
|
||||||
|
citeprocRS.free();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with chicago-note-bibliography.csl', function () {
|
||||||
|
before(function () {
|
||||||
|
style = Zotero.Styles.get(chicagoNoteStyleID);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should produce a correct citation", function () {
|
||||||
|
assertProducedCitationsAreEqual(createACitation([item1, item3]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should produce a correct citation with a locator", function () {
|
||||||
|
let citation = createACitation(item1);
|
||||||
|
Object.assign(citation.citationItems[0], { locator: 1, label: "page" });
|
||||||
|
assertProducedCitationsAreEqual(citation);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should produce a correct citation with a prefix", function () {
|
||||||
|
let citation = createACitation(item1);
|
||||||
|
Object.assign(citation.citationItems[0], { prefix: 'hello' });
|
||||||
|
assertProducedCitationsAreEqual(citation);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should produce a correct citation with a suppressed author", function () {
|
||||||
|
let citation = createACitation(item1);
|
||||||
|
Object.assign(citation.citationItems[0], { 'suppress-author': true });
|
||||||
|
assertProducedCitationsAreEqual(citation);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should should produce ibid when appropriate", function () {
|
||||||
|
let citation1 = createACitation(item1);
|
||||||
|
let citation2 = createACitation(item1);
|
||||||
|
|
||||||
|
citeprocRS.insertCluster(citation1);
|
||||||
|
citeprocRS.insertCluster(citation2);
|
||||||
|
citeprocRS.setClusterOrder([[citation1.citationID, 1], [citation2.citationID, 2]]);
|
||||||
|
let updateSummary = citeprocRS.getBatchedUpdates();
|
||||||
|
|
||||||
|
let [_, citationInfo] = citeprocJS.processCitationCluster(citation1, [], []);
|
||||||
|
[_, citationInfo] = citeprocJS.processCitationCluster(citation2, [[citation1.citationID, 1]], []);
|
||||||
|
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
let CRSCitation = updateSummary.clusters[i][1];
|
||||||
|
let CJSCitation = citationInfo[i][1];
|
||||||
|
Zotero.debug(`\nciteproc-js: ${CJSCitation}\nciteproc-rs: ${CRSCitation}`, 2);
|
||||||
|
assert.equal(CJSCitation, CRSCitation, `citations #${i} are equal`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let CRSBibl = Zotero.Cite.makeFormattedBibliography(citeprocRS, 'text');
|
||||||
|
let CJSBibl = Zotero.Cite.makeFormattedBibliography(citeprocJS, 'text');
|
||||||
|
assert.deepEqual(CJSBibl, CRSBibl, 'bibliographies are equal');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Chicago note-bibliography does not perform last name disambiguation
|
||||||
|
describe('with chicago-author-date.csl', function () {
|
||||||
|
before(function () {
|
||||||
|
style = Zotero.Styles.get(chicagoAuthorDateStyleID);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should perform last name disambiguation", function () {
|
||||||
|
assertProducedCitationsAreEqual(createACitation([item1, item2SameLastName]));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue