Skip to content

Commit

Permalink
switchable citeproc: fix copy & export
Browse files Browse the repository at this point in the history
  • Loading branch information
tnajdek committed Jun 8, 2021
1 parent ffea3f8 commit 53f09ba
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 42 deletions.
2 changes: 1 addition & 1 deletion src/js/cite.js
Expand Up @@ -131,7 +131,7 @@ const formatBibLegacy = (bib) => {
};

const getBibliographyFormatParameters = bibliographyMeta =>
getBibliographyFormatParametersLegacy([metaCiteprocRStoJS(bibliographyMeta)]);
getBibliographyFormatParametersLegacy([CiteprocWrapper.metaCiteprocRStoJS(bibliographyMeta)]);

/**
* copied from https://github.com/zotero/zotero/blob/1f5639da4297ac20fd21223d2004a7cfeef72e21/chrome/content/zotero/xpcom/cite.js#L43
Expand Down
28 changes: 18 additions & 10 deletions src/js/citeproc-wrapper.js
Expand Up @@ -73,6 +73,7 @@ class CiteprocWrapper {
retrieveItem: itemId => this.itemsStore[itemId],
// uppercase_subtitles: isUppercaseSubtitlesStyle(style) // TODO
}, opts.style, opts.lang);
this.driver.setOutputFormat(opts.format);
} else {
this.driver = engine;
}
Expand All @@ -81,22 +82,25 @@ class CiteprocWrapper {
batchedUpdates() {
if(this.isLegacy) {
// TODO: implement for citeproc JS
const [meta, items] = this.driver.makeBibliography();
const updatedEntries = meta.entry_ids.reduce((acc, id, index) => {
acc[id] = items[index];
return acc;
}, {});
const legacyDriverBib = this.driver.makeBibliography();
var bibliography = null;

if(legacyDriverBib) {
const [meta, items] = legacyDriverBib;
const updatedEntries = meta.entry_ids.reduce((acc, id, index) => {
acc[id] = items[index];
return acc;
}, {});

bibliography = { entryIds: meta?.entry_ids, updatedEntries };
}

const bibliography = { entryIds: meta.entry_ids, updatedEntries };
const clusters = this.driver.rebuildProcessorState(
this.clustersStore.map(cluster => ({
citationID: cluster.id,
citationItems: cluster.cites
}))
).reduce((acc, cluster) => {
acc[cluster[0]] = cluster[2];
return acc;
}, {});
).map(cluster => ([cluster[0], cluster[2]]));

return { bibliography, clusters };
} else {
Expand Down Expand Up @@ -290,6 +294,7 @@ class CiteprocWrapper {
retrieveItem: itemId => this.itemsStore[itemId],
// uppercase_subtitles: isUppercaseSubtitlesStyle(style) // TODO
}, style_text, this.opts.lang);
this.driver.setOutputFormat(this.opts.format);
} else {
return this.driver.setStyle(style_text).unwrap();
}
Expand Down Expand Up @@ -319,6 +324,9 @@ CiteprocWrapper.new = async ({ style, format = 'html', lang = null }, useLegacy
try {
if(useLegacy) {
const CSL = await getCSL();
if(format === 'plain') {
format = 'text';
}
return new CiteprocWrapper(true, CSL, { style, format, lang });
} else {
if(!Driver) {
Expand Down
29 changes: 11 additions & 18 deletions src/js/components/container.jsx
Expand Up @@ -4,9 +4,9 @@ import { useParams, useLocation, useHistory } from "react-router-dom";
import copy from 'copy-to-clipboard';
import SmoothScroll from 'smooth-scroll';

import { calcOffset, dedupMultipleChoiceItems, fetchFromPermalink, getOneTimeBibliographyOrFallback,
getExpandedCitationStyles, getCiteproc, getItemsCSL, isLikeUrl, parseIdentifier,
processMultipleChoiceItems, processSentenceCaseAPAItems, retrieveIndependentStyle,
import { calcOffset, dedupMultipleChoiceItems, ensureNoBlankItems, fetchFromPermalink,
getOneTimeBibliographyOrFallback, getExpandedCitationStyles, getCiteproc, getItemsCSL, isLikeUrl,
parseIdentifier, processMultipleChoiceItems, processSentenceCaseAPAItems, retrieveIndependentStyle,
retrieveStylesData, saveToPermalink, validateItem, validateUrl } from '../utils';
import { coreCitationStyles } from '../../../data/citation-styles-data.json';
import defaults from '../constants/defaults';
Expand Down Expand Up @@ -110,7 +110,7 @@ const BibWebContainer = props => {
//TODO: optimise in bib
const itemCSL = bib.current.itemsCSL.find(icsl => icsl.id === item.key)

citeproc.current.insertReference(itemCSL);
citeproc.current.insertReference(ensureNoBlankItems([itemCSL])[0]);
citeproc.current.insertCluster(({ id: itemCSL.id, cites: [ { id: itemCSL.id } ] }));
citeproc.current.setClusterOrder(bib.current.itemsRaw.map(item => ({ id: item.key })));
}, [displayFirstCitationMessage, isSentenceCaseStyle]);
Expand Down Expand Up @@ -152,11 +152,10 @@ const BibWebContainer = props => {
citeproc.current.setStyle(citationStyleXml);
} else {
citeproc.current = await getCiteproc(citationStyleXml);
console.log(citeproc.current);
}

citeproc.current.includeUncited("All");
citeproc.current.insertReferences(bib.current.itemsCSL);
citeproc.current.insertReferences(ensureNoBlankItems(bib.current.itemsCSL));

// we also init every single item as a separate cluster for fallback rendering
citeproc.current.initClusters(
Expand All @@ -167,11 +166,9 @@ const BibWebContainer = props => {
const itemsLookup = bib.current.itemsRaw.reduce((acc, item) => { acc[item.key] = item; return acc }, {});

if(styleHasBibliography) {
setBibliography({
items: citeproc.current.makeBibliography(),
meta: citeproc.current.bibliographyMeta(),
lookup: itemsLookup
});
const items = citeproc.current.makeBibliography();
const meta = citeproc.current.bibliographyMeta();
setBibliography({ items, meta, lookup: itemsLookup });
} else {
const render = citeproc.current.fullRender();
setBibliography({
Expand Down Expand Up @@ -215,10 +212,6 @@ const BibWebContainer = props => {
}, [citationStyles, config, handleError, history, remoteId]);

const getCopyData = useCallback(async format => {
if(format === 'text') {
//NOTE: citeprocRS uses 'plain', citeprocJS uses 'text';
format = 'plain';
}
const { bibliographyItems, bibliographyMeta } = await getOneTimeBibliographyOrFallback(
bib.current.itemsCSL, citationStyleXml, styleHasBibliography, format
);
Expand All @@ -230,6 +223,7 @@ const BibWebContainer = props => {
formatFallback(bibliographyItems) :
bibliographyItems.map(i => i.value).join('\n');


if(exportFormats[format].include) {
copyDataInclude.current = [
{
Expand Down Expand Up @@ -292,7 +286,6 @@ const BibWebContainer = props => {
const diff = citeproc.current.batchedUpdates();
const itemsLookup = bib.current.itemsRaw.reduce((acc, item) => { acc[item.key] = item; return acc }, {});

console.log({ diff });

if(bib.current.itemsRaw.length === 0) {
setBibliography({ items: [], meta: null, lookup: {} });
Expand Down Expand Up @@ -517,7 +510,7 @@ const BibWebContainer = props => {
bib.current.updateItem(index, updatedItem);
setEditorItem(updatedItem);

citeproc.current.resetReferences(bib.current.itemsCSL);
citeproc.current.resetReferences(ensureNoBlankItems(bib.current.itemsCSL));
updateBibliography();

// if edited item is itemUnderReview, update it as well
Expand Down Expand Up @@ -838,7 +831,7 @@ const BibWebContainer = props => {
if(!isReadOnly && document.visibilityState === 'visible') {
const storageCitationStyle = localStorage.getItem('zotero-bib-citation-style');
bib.current.reloadItems();
citeproc.current.resetReferences(bib.current.itemsCSL);
citeproc.current.resetReferences(ensureNoBlankItems(bib.current.itemsCSL));
if(storageCitationStyle === citationStyle) {
updateBibliography();
} else {
Expand Down
6 changes: 3 additions & 3 deletions src/js/components/export-tools.jsx
Expand Up @@ -88,7 +88,7 @@ class ExportDialog extends React.Component {
handleCopyToClipboardClick() {
// explicitely hide the dropdown
this.setState({ 'isDropdownOpen': false });
this.handleCopy('text');
this.handleCopy('plain');
}

renderMenuOption(format) {
Expand Down Expand Up @@ -120,7 +120,7 @@ class ExportDialog extends React.Component {
}

render() {
const isCopied = this.state.clipboardConfirmations['text'];
const isCopied = this.state.clipboardConfirmations['plain'];
return (
<div className="export-tools">
<Dropdown
Expand All @@ -134,7 +134,7 @@ class ExportDialog extends React.Component {
onClick={ this.handleCopyToClipboardClick.bind(this) }
>
<span className={ cx('inline-feedback', { 'active': isCopied }) }>
<span className="default-text" aria-hidden={ !isCopied }>{ exportFormats['text'].label }</span>
<span className="default-text" aria-hidden={ !isCopied }>{ exportFormats['plain'].label }</span>
<span className="shorter feedback" aria-hidden={ isCopied }>Copied!</span>
</span>
</Button>
Expand Down
10 changes: 1 addition & 9 deletions src/js/constants/export-formats.js
Expand Up @@ -6,15 +6,7 @@ export default {
isDownloadable: false,
isCopyable: true
},
'text': {
extension: 'txt',
mime: 'text/plain',
label: 'Copy to Clipboard',
include: 'html',
isDownloadable: false,
isCopyable: true
},
'plain': { // same as text but for citeprocRS
'plain': {
extension: 'txt',
mime: 'text/plain',
label: 'Copy to Clipboard',
Expand Down
15 changes: 14 additions & 1 deletion src/js/utils.jsx
Expand Up @@ -62,6 +62,18 @@ var Driver = null;

import CiteprocWrapper from './citeproc-wrapper';

const ensureNoBlankItems = itemsCSL => itemsCSL.map(item => {
if(!('author' in item) && !('title' in item) && !('issued' in item)) {
// there is a risk of this item being skipped by citeproc in makeBibliography so we inject
// title to make sure it can be edited in bib-web
return {
...item,
title: 'Untitled'
};
} else {
return item;
}
});

//TODO: retrieveItem below contains some logic that has not been ported to the wrapper
const getCiteproc = async (style, format = 'html') => {
Expand Down Expand Up @@ -350,8 +362,8 @@ const getOneTimeBibliographyOrFallback = async (itemsCSL, citationStyleXml, styl
citeproc.insertReferences(itemsCSL);

if(styleHasBibliography) {
bibliographyMeta = citeproc.bibliographyMeta();
bibliographyItems = citeproc.makeBibliography();
bibliographyMeta = citeproc.bibliographyMeta();
} else {
citeproc.initClusters(
itemsCSL.map(item => ({ id: item.id, cites: [ { id: item.id } ] }))
Expand Down Expand Up @@ -687,6 +699,7 @@ const getItemsCSL = items => {
export {
calcOffset,
dedupMultipleChoiceItems,
ensureNoBlankItems,
fetchFromPermalink,
fetchWithCachedFallback,
getOneTimeBibliographyOrFallback,
Expand Down

0 comments on commit 53f09ba

Please sign in to comment.