Skip to content

Instantly share code, notes, and snippets.

@retorquere
Created April 10, 2019 10:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save retorquere/8287afa5243bfb72bf14cbb2593a39ff to your computer and use it in GitHub Desktop.
Save retorquere/8287afa5243bfb72bf14cbb2593a39ff to your computer and use it in GitHub Desktop.
{
"translatorID": "7ddf943e-8729-4764-ae1e-654b56822d90",
"label": "SeekTable FODS",
"description": "Exports items to FODS with one row per tag/collection/creator permutation",
"creator": "Emiliano Heyns",
"target": "fods",
"minVersion": "4.0.27",
"maxVersion": "",
"configOptions": {
"getCollections": true
},
"displayOptions": {
"exportNotes": true,
"Bundle automatic tags": true
},
"translatorType": 2,
"browserSupport": "gcsv",
"priority": 99,
"inRepository": false,
"lastUpdated": "2019-04-10 10:47:17"
}
// version: 0.0.12
const aliases = Object.entries({
bookTitle: 'publicationTitle',
thesisType: 'type',
university: 'publisher',
letterType: 'type',
manuscriptType: 'type',
interviewMedium: 'medium',
distributor: 'publisher',
videoRecordingFormat: 'medium',
genre: 'type',
artworkMedium: 'medium',
websiteType: 'type',
websiteTitle: 'publicationTitle',
institution: 'publisher',
reportType: 'type',
reportNumber: 'number',
billNumber: 'number',
codeVolume: 'volume',
codePages: 'pages',
dateDecided: 'date',
reporterVolume: 'volume',
firstPage: 'pages',
caseName: 'title',
docketNumber: 'number',
documentNumber: 'number',
patentNumber: 'number',
issueDate: 'date',
dateEnacted: 'date',
publicLawNumber: 'number',
nameOfAct: 'title',
subject: 'title',
mapType: 'type',
blogTitle: 'publicationTitle',
postType: 'type',
forumTitle: 'publicationTitle',
audioRecordingFormat: 'medium',
label: 'publisher',
presentationType: 'type',
studio: 'publisher',
network: 'publisher',
episodeNumber: 'number',
programTitle: 'publicationTitle',
audioFileType: 'medium',
company: 'publisher',
proceedingsTitle: 'publicationTitle',
encyclopediaTitle: 'publicationTitle',
dictionaryTitle: 'publicationTitle',
});
function make_cell(value) {
if (typeof value === 'number')
value = `${value}`;
if (!value)
value = '';
const entity = {
'"': '"',
"'": ''',
'<': '&lt;',
'>': '&gt;',
'&': '&amp;',
};
value = value.split('\n').map(text => `<text:p>${text.replace(/[<>"'&]/g, c => entity[c])}</text:p>`).join('');
return `<table:table-cell office:value-type="string" calcext:value-type="string">${value}</table:table-cell>`;
}
function make_row(cells) {
return `<table:table-row>${cells.map(make_cell).join('')}</table:table-row>`;
}
function makeGenerator(type) {
const next = Zotero[`next${type}`].bind(Zotero);
return function* () {
let obj;
while (obj = next()) {
yield obj;
}
};
}
const getCollections = makeGenerator('Collection');
const getItems = makeGenerator('Item');
function assign_path(collection, collections) {
if (!collection)
return [];
if (collection.parent && !collections[collection.parent])
collection.parent = false;
collection.path = collection.path || assign_path(collections[collection.parent], collections).concat(collection.name);
return collection.path.slice();
}
function doExport() {
const collections = {};
for (const collection of getCollections()) {
const children = collection.children || collection.descendents || [];
const key = (collection.primary ? collection.primary : collection).key;
collections[key] = {
id: collection.id,
key,
parent: collection.fields.parentKey,
name: collection.name,
items: collection.childItems,
collections: children.filter(coll => coll.type === 'collection').map(coll => coll.key),
};
}
for (const collection of Object.values(collections)) {
assign_path(collection, collections);
}
const bundle_automatic_tags = Zotero.getOption('Bundle automatic tags');
let bundle_automatic_tags_sep = ', ';
if (bundle_automatic_tags) {
bundle_automatic_tags_sep = Zotero.getHiddenPref('SeekTable.delimiter.automatic_tags');
if (!bundle_automatic_tags_sep || bundle_automatic_tags_sep.toLowerCase() === 'comma') {
bundle_automatic_tags_sep = ', ';
}
else if (bundle_automatic_tags_sep.match(/^(cr|lf)+$/i)) {
bundle_automatic_tags_sep = bundle_automatic_tags_sep.replace(/cr/ig, '\r').replace(/lf/ig, '\n');
}
else {
Zotero.debug(`using verbatim SeekTable.delimiter.automatic_tags ${JSON.stringify(bundle_automatic_tags_sep)}`);
}
}
const items = [];
for (const item of getItems()) {
if (item.itemType === 'attachment')
continue;
if (item.itemType === 'note') {
item.notes = item.note ? [{ note: item.note }] : [];
delete item.notes;
}
for (const [alias, field] of aliases) {
if (typeof item[alias] !== 'undefined') {
item[field] = item[alias];
delete item[alias];
}
}
delete item.attachments;
delete item.uri;
delete item.relations;
delete item.version;
delete item.citekey;
delete item.itemID;
delete item.key;
delete item.libraryID;
item.creators = (item.creators || []).map(creator => creator.name ? creator.name : [creator.lastName, creator.firstName].filter(name => name).join(', ')).join('; ');
if (!item.url && item.DOI)
item.url = `${item.DOI.startsWith('http') ? '' : 'http://doi.org/'}${item.DOI}`;
if (!item.notes) {
item.notes = '';
}
else if (item.notes.length === 1) {
item.notes = item.notes[0].note;
}
else {
item.notes = item.notes.map(note => `<div>${note.note}</div>`).join('');
}
item.notes = item.notes.replace(/[\r\n]+/g, ' ').replace(/\u00A0/g, ' ');
item.extra = (item.extra || '').replace(/[\r\n]+/g, ' ').replace(/\u00A0/g, ' ');
item.year = null;
if (item.date) {
const date = Zotero.Utilities.strToDate(item.date);
if (date)
item.year = date.year;
item.date = Zotero.Utilities.strToISO(item.date) || item.date;
}
const collection_paths = (item.collections || []).map(key => collections[key] ? collections[key].path.join(', ') : '').filter(coll => coll);
if (!collection_paths.length)
collection_paths.push('');
delete item.collections;
const tags = {
manual: (item.tags || []).filter(tag => tag.type !== 1).map(tag => tag.tag),
automatic: (item.tags || []).filter(tag => tag.type === 1).map(tag => tag.tag),
};
for (const type of Object.keys(tags)) {
if (!tags[type].length)
tags[type].push('');
}
delete item.tags;
if (bundle_automatic_tags) {
item.automatic_tags = tags.automatic.join(bundle_automatic_tags_sep);
for (const collection of collection_paths) {
for (const tag of tags.manual) {
items.push(Object.assign({}, item, { tag, collection }));
}
}
}
else {
for (const collection of collection_paths) {
for (const tag of tags.manual) {
for (const automatic_tag of tags.automatic) {
items.push(Object.assign({}, item, { tag, automatic_tag, collection }));
}
}
}
}
}
const headers = [];
for (const item of items) {
for (const header of Object.keys(item)) {
if (!headers.includes(header))
headers.push(header);
}
}
headers.sort();
Zotero.write(`
<?xml version='1.0' encoding='UTF-8'?>
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.spreadsheet">
<office:body>
<office:spreadsheet>
<table:calculation-settings table:automatic-find-labels="false" table:use-regular-expressions="false" table:use-wildcards="true"/>
<table:table table:name="My Library">
`.trim());
for (const header of headers) {
Zotero.write('<table:table-column/>');
}
Zotero.write(make_row(headers));
for (const item of items) {
Zotero.write(make_row(headers.map(header => item[header])));
}
Zotero.write(`
</table:table>
</office:spreadsheet>
</office:body>
</office:document>
`);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment