Merge pull request #2214 from mrtcode/notes-export
Markdown Note Export
This commit is contained in:
commit
0a7eebbab4
19 changed files with 392 additions and 250 deletions
|
@ -49,8 +49,7 @@ var Zotero_File_Interface_Export = new function() {
|
|||
|
||||
var addedOptions = new Object();
|
||||
|
||||
var translators = window.arguments[0].translators;
|
||||
translators.sort(function(a, b) { return a.label.localeCompare(b.label) });
|
||||
var { translators, exportingNotes } = window.arguments[0];
|
||||
|
||||
// get format popup
|
||||
var formatPopup = document.getElementById("format-popup");
|
||||
|
@ -58,7 +57,9 @@ var Zotero_File_Interface_Export = new function() {
|
|||
var optionsBox = document.getElementById("translator-options");
|
||||
var charsetBox = document.getElementById("charset-box");
|
||||
|
||||
var selectedTranslator = Zotero.Prefs.get("export.lastTranslator");
|
||||
var selectedTranslator = Zotero.Prefs.get(
|
||||
exportingNotes ? "export.lastNoteTranslator" : "export.lastTranslator"
|
||||
);
|
||||
|
||||
// add styles to format popup
|
||||
for(var i in translators) {
|
||||
|
@ -72,7 +73,12 @@ var Zotero_File_Interface_Export = new function() {
|
|||
// presented to the user
|
||||
// get readable name for option
|
||||
try {
|
||||
var optionLabel = Zotero.getString("exportOptions."+option);
|
||||
if (option == 'includeAppLinks') {
|
||||
var optionLabel = Zotero.getString("exportOptions." + option, Zotero.appName);
|
||||
}
|
||||
else {
|
||||
var optionLabel = Zotero.getString("exportOptions." + option);
|
||||
}
|
||||
} catch(e) {
|
||||
var optionLabel = option;
|
||||
}
|
||||
|
@ -121,7 +127,9 @@ var Zotero_File_Interface_Export = new function() {
|
|||
_charsets = Zotero_Charset_Menu.populate(document.getElementById(OPTION_PREFIX+"exportCharset"), true);
|
||||
}
|
||||
|
||||
this.updateOptions(Zotero.Prefs.get("export.translatorSettings"));
|
||||
this.updateOptions(Zotero.Prefs.get(
|
||||
exportingNotes ? "export.noteTranslatorSettings" : "export.translatorSettings"
|
||||
));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -224,7 +232,10 @@ var Zotero_File_Interface_Export = new function() {
|
|||
window.arguments[0].selectedTranslator = window.arguments[0].translators[index];
|
||||
|
||||
// save selected translator
|
||||
Zotero.Prefs.set("export.lastTranslator", window.arguments[0].translators[index].translatorID);
|
||||
Zotero.Prefs.set(
|
||||
window.arguments[0].exportingNotes ? "export.lastNoteTranslator" : "export.lastTranslator",
|
||||
window.arguments[0].translators[index].translatorID
|
||||
);
|
||||
|
||||
// set options on selected translator and generate optionString
|
||||
var optionsAvailable = window.arguments[0].selectedTranslator.displayOptions;
|
||||
|
@ -253,7 +264,10 @@ var Zotero_File_Interface_Export = new function() {
|
|||
|
||||
// save options
|
||||
var optionString = JSON.stringify(displayOptions);
|
||||
Zotero.Prefs.set("export.translatorSettings", optionString);
|
||||
Zotero.Prefs.set(
|
||||
window.arguments[0].exportingNotes ? "export.noteTranslatorSettings" : "export.translatorSettings",
|
||||
optionString
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -49,9 +49,46 @@ var Zotero_File_Exporter = function() {
|
|||
Zotero_File_Exporter.prototype.save = async function () {
|
||||
var translation = new Zotero.Translate.Export();
|
||||
var translators = await translation.getTranslators();
|
||||
|
||||
if (!this.items) {
|
||||
return;
|
||||
}
|
||||
|
||||
let exportingNotes = this.items.every(item => item.isNote() || item.isAttachment());
|
||||
// Keep only note export and Zotero RDF translators, if all items are notes or attachments
|
||||
if (exportingNotes) {
|
||||
translators = translators.filter((translator) => {
|
||||
return (
|
||||
translator.translatorID === '14763d24-8ba0-45df-8f52-b8d1108e7ac9'
|
||||
|| translator.configOptions && translator.configOptions.noteTranslator
|
||||
);
|
||||
});
|
||||
}
|
||||
// Otherwise exclude note export translators
|
||||
else {
|
||||
translators = translators.filter(t => !t.configOptions || !t.configOptions.noteTranslator);
|
||||
}
|
||||
|
||||
translators.sort((a, b) => a.label.localeCompare(b.label));
|
||||
|
||||
// Remove "Note" prefix from Note Markdown and Note HTML translators
|
||||
let markdownTranslator = translators.find(
|
||||
t => t.translatorID == Zotero.Translators.TRANSLATOR_ID_NOTE_MARKDOWN
|
||||
);
|
||||
if (markdownTranslator) {
|
||||
markdownTranslator.label = 'Markdown';
|
||||
// Move Note Markdown translator to the top
|
||||
translators.unshift(...translators.splice(translators.indexOf(markdownTranslator), 1));
|
||||
}
|
||||
let htmlTranslator = translators.find(
|
||||
t => t.translatorID == Zotero.Translators.TRANSLATOR_ID_NOTE_HTML
|
||||
);
|
||||
if (htmlTranslator) {
|
||||
htmlTranslator.label = 'HTML';
|
||||
}
|
||||
|
||||
// present options dialog
|
||||
var io = {translators:translators}
|
||||
var io = { translators, exportingNotes };
|
||||
window.openDialog("chrome://zotero/content/exportOptions.xul",
|
||||
"_blank", "chrome,modal,centerscreen,resizable=no", io);
|
||||
if(!io.selectedTranslator) {
|
||||
|
@ -89,33 +126,34 @@ Zotero_File_Exporter.prototype.save = async function () {
|
|||
translation.setLibraryID(this.libraryID);
|
||||
}
|
||||
|
||||
async function _exportDone(obj, worked) {
|
||||
// Close the items exported indicator
|
||||
Zotero_File_Interface.Progress.close();
|
||||
|
||||
if (!worked) {
|
||||
Zotero.alert(
|
||||
null,
|
||||
Zotero.getString('general.error'),
|
||||
Zotero.getString('fileInterface.exportError')
|
||||
);
|
||||
Zotero_File_Interface.Progress.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
translation.setLocation(Zotero.File.pathToFile(fp.file));
|
||||
translation.setTranslator(io.selectedTranslator);
|
||||
translation.setDisplayOptions(io.displayOptions);
|
||||
translation.setHandler("itemDone", function () {
|
||||
Zotero.updateZoteroPaneProgressMeter(translation.getProgress());
|
||||
});
|
||||
translation.setHandler("done", this._exportDone);
|
||||
translation.setHandler("done", _exportDone);
|
||||
Zotero_File_Interface.Progress.show(
|
||||
Zotero.getString("fileInterface.itemsExported")
|
||||
);
|
||||
translation.translate()
|
||||
};
|
||||
|
||||
/*
|
||||
* Closes the items exported indicator
|
||||
*/
|
||||
Zotero_File_Exporter.prototype._exportDone = function(obj, worked) {
|
||||
Zotero_File_Interface.Progress.close();
|
||||
|
||||
if(!worked) {
|
||||
Zotero.alert(
|
||||
null,
|
||||
Zotero.getString('general.error'),
|
||||
Zotero.getString("fileInterface.exportError")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****Zotero_File_Interface****
|
||||
**
|
||||
|
@ -175,36 +213,91 @@ var Zotero_File_Interface = new function() {
|
|||
*/
|
||||
function exportItems() {
|
||||
var exporter = new Zotero_File_Exporter();
|
||||
|
||||
exporter.items = ZoteroPane_Local.getSelectedItems();
|
||||
let itemIDs = ZoteroPane_Local.getSelectedItems(true);
|
||||
// Get selected item IDs in the item tree order
|
||||
itemIDs = ZoteroPane_Local.getSortedItems(true).filter(id => itemIDs.includes(id));
|
||||
exporter.items = Zotero.Items.get(itemIDs);
|
||||
if(!exporter.items || !exporter.items.length) throw("no items currently selected");
|
||||
|
||||
exporter.save();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* exports items to clipboard
|
||||
*/
|
||||
function exportItemsToClipboard(items, translatorID) {
|
||||
var translation = new Zotero.Translate.Export();
|
||||
translation.setItems(items);
|
||||
translation.setTranslator(translatorID);
|
||||
translation.setHandler("done", _copyToClipboard);
|
||||
translation.translate();
|
||||
}
|
||||
|
||||
/*
|
||||
* handler when done exporting items to clipboard
|
||||
*/
|
||||
function _copyToClipboard(obj, worked) {
|
||||
if(!worked) {
|
||||
Zotero.alert(
|
||||
null, Zotero.getString('general.error'), Zotero.getString("fileInterface.exportError")
|
||||
);
|
||||
} else {
|
||||
Components.classes["@mozilla.org/widget/clipboardhelper;1"]
|
||||
.getService(Components.interfaces.nsIClipboardHelper)
|
||||
.copyString(obj.string.replace(/\r\n/g, "\n"));
|
||||
function _translate(items, translatorID, callback) {
|
||||
let translation = new Zotero.Translate.Export();
|
||||
translation.setItems(items.slice());
|
||||
translation.setTranslator(translatorID);
|
||||
translation.setHandler("done", callback);
|
||||
translation.translate();
|
||||
}
|
||||
|
||||
// If translating with virtual "Markdown + Rich Text" translator, use Note Markdown and
|
||||
// Note HTML instead
|
||||
if (translatorID == Zotero.Translators.TRANSLATOR_ID_MARKDOWN_AND_RICH_TEXT) {
|
||||
translatorID = Zotero.Translators.TRANSLATOR_ID_NOTE_MARKDOWN;
|
||||
_translate(items, translatorID, (obj, worked) => {
|
||||
if (!worked) {
|
||||
Zotero.log(Zotero.getString('fileInterface.exportError'), 'warning');
|
||||
return;
|
||||
}
|
||||
translatorID = Zotero.Translators.TRANSLATOR_ID_NOTE_HTML;
|
||||
_translate(items, translatorID, (obj2, worked) => {
|
||||
if (!worked) {
|
||||
Zotero.log(Zotero.getString('fileInterface.exportError'), 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
let text = obj.string.replace(/\r\n/g, '\n');
|
||||
let html = obj2.string.replace(/\r\n/g, '\n');
|
||||
|
||||
// copy to clipboard
|
||||
let transferable = Components.classes['@mozilla.org/widget/transferable;1']
|
||||
.createInstance(Components.interfaces.nsITransferable);
|
||||
let clipboardService = Components.classes['@mozilla.org/widget/clipboard;1']
|
||||
.getService(Components.interfaces.nsIClipboard);
|
||||
|
||||
// Add Text
|
||||
let str = Components.classes['@mozilla.org/supports-string;1']
|
||||
.createInstance(Components.interfaces.nsISupportsString);
|
||||
str.data = text;
|
||||
transferable.addDataFlavor('text/unicode');
|
||||
transferable.setTransferData('text/unicode', str, text.length * 2);
|
||||
|
||||
// Add HTML
|
||||
str = Components.classes['@mozilla.org/supports-string;1']
|
||||
.createInstance(Components.interfaces.nsISupportsString);
|
||||
str.data = html;
|
||||
transferable.addDataFlavor('text/html');
|
||||
transferable.setTransferData('text/html', str, html.length * 2);
|
||||
|
||||
clipboardService.setData(
|
||||
transferable, null, Components.interfaces.nsIClipboard.kGlobalClipboard
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
_translate(items, translatorID, (obj, worked) => {
|
||||
if (!worked) {
|
||||
Zotero.log(Zotero.getString('fileInterface.exportError'), 'warning');
|
||||
return;
|
||||
}
|
||||
let text = obj.string;
|
||||
// For Note HTML translator use body content only
|
||||
if (translatorID == Zotero.Translators.TRANSLATOR_ID_NOTE_HTML) {
|
||||
let parser = Components.classes['@mozilla.org/xmlextras/domparser;1']
|
||||
.createInstance(Components.interfaces.nsIDOMParser);
|
||||
let doc = parser.parseFromString(text, 'text/html');
|
||||
text = doc.body.innerHTML;
|
||||
}
|
||||
Components.classes['@mozilla.org/widget/clipboardhelper;1']
|
||||
.getService(Components.interfaces.nsIClipboardHelper)
|
||||
.copyString(text.replace(/\r\n/g, '\n'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1891,6 +1891,8 @@ var ItemTree = class ItemTree extends LibraryTree {
|
|||
event.dataTransfer.setDragImage(this._dragImageContainer, 0, 0);
|
||||
|
||||
var itemIDs = this.getSelectedItems(true);
|
||||
// Get selected item IDs in the item tree order
|
||||
itemIDs = this.getSortedItems(true).filter(id => itemIDs.includes(id));
|
||||
event.dataTransfer.setData("zotero/item", itemIDs);
|
||||
|
||||
var items = Zotero.Items.get(itemIDs);
|
||||
|
@ -1946,22 +1948,53 @@ var ItemTree = class ItemTree extends LibraryTree {
|
|||
// Get Quick Copy format for current URL (set via /ping from connector)
|
||||
var format = Zotero.QuickCopy.getFormatFromURL(Zotero.QuickCopy.lastActiveURL);
|
||||
|
||||
Zotero.debug("Dragging with format " + format);
|
||||
|
||||
var exportCallback = function(obj, worked) {
|
||||
if (!worked) {
|
||||
Zotero.log(Zotero.getString("fileInterface.exportError"), 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
var text = obj.string.replace(/\r\n/g, "\n");
|
||||
event.dataTransfer.setData("text/plain", text);
|
||||
// If all items are notes, use one of the note export translators
|
||||
if (items.every(item => item.isNote())) {
|
||||
format = Zotero.QuickCopy.getNoteFormat();
|
||||
}
|
||||
|
||||
Zotero.debug("Dragging with format " + format);
|
||||
format = Zotero.QuickCopy.unserializeSetting(format);
|
||||
try {
|
||||
if (format.mode == 'export') {
|
||||
Zotero.QuickCopy.getContentFromItems(items, format, exportCallback);
|
||||
// If exporting with virtual "Markdown + Rich Text" translator, call Note Markdown
|
||||
// and Note HTML translators instead
|
||||
if (format.id === Zotero.Translators.TRANSLATOR_ID_MARKDOWN_AND_RICH_TEXT) {
|
||||
let markdownFormat = { mode: 'export', id: Zotero.Translators.TRANSLATOR_ID_NOTE_MARKDOWN };
|
||||
let htmlFormat = { mode: 'export', id: Zotero.Translators.TRANSLATOR_ID_NOTE_HTML };
|
||||
Zotero.QuickCopy.getContentFromItems(items, markdownFormat, (obj, worked) => {
|
||||
if (!worked) {
|
||||
Zotero.log(Zotero.getString('fileInterface.exportError'), 'warning');
|
||||
return;
|
||||
}
|
||||
Zotero.QuickCopy.getContentFromItems(items, htmlFormat, (obj2, worked) => {
|
||||
if (!worked) {
|
||||
Zotero.log(Zotero.getString('fileInterface.exportError'), 'warning');
|
||||
return;
|
||||
}
|
||||
event.dataTransfer.setData('text/plain', obj.string.replace(/\r\n/g, '\n'));
|
||||
event.dataTransfer.setData('text/html', obj2.string.replace(/\r\n/g, '\n'));
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
Zotero.QuickCopy.getContentFromItems(items, format, (obj, worked) => {
|
||||
if (!worked) {
|
||||
Zotero.log(Zotero.getString('fileInterface.exportError'), 'warning');
|
||||
return;
|
||||
}
|
||||
var text = obj.string.replace(/\r\n/g, '\n');
|
||||
// For Note HTML translator use body content only
|
||||
if (format.id == Zotero.Translators.TRANSLATOR_ID_NOTE_HTML) {
|
||||
// Use body content only
|
||||
let parser = Cc['@mozilla.org/xmlextras/domparser;1']
|
||||
.createInstance(Ci.nsIDOMParser);
|
||||
let doc = parser.parseFromString(text, 'text/html');
|
||||
text = doc.body.innerHTML;
|
||||
}
|
||||
event.dataTransfer.setData('text/plain', text);
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (format.mode == 'bibliography') {
|
||||
var content = Zotero.QuickCopy.getContentFromItems(items, format, null, event.shiftKey);
|
||||
|
|
|
@ -35,6 +35,7 @@ Zotero_Preferences.Export = {
|
|||
init: Zotero.Promise.coroutine(function* () {
|
||||
this.updateQuickCopyInstructions();
|
||||
yield this.populateQuickCopyList();
|
||||
yield this.populateNoteQuickCopyList();
|
||||
|
||||
var charsetMenu = document.getElementById("zotero-import-charsetMenu");
|
||||
var charsetMap = Zotero_Charset_Menu.populate(charsetMenu, false);
|
||||
|
@ -51,6 +52,8 @@ Zotero_Preferences.Export = {
|
|||
var collation = Zotero.getLocaleCollation();
|
||||
return collation.compareString(1, a.label, b.label);
|
||||
});
|
||||
// Exclude note export translators
|
||||
translators = translators.filter(x => !x.configOptions || !x.configOptions.noteTranslator);
|
||||
return translators;
|
||||
},
|
||||
|
||||
|
@ -82,6 +85,86 @@ Zotero_Preferences.Export = {
|
|||
}),
|
||||
|
||||
|
||||
/*
|
||||
* Builds the note Quick Copy drop-down from the current global pref
|
||||
*/
|
||||
populateNoteQuickCopyList: async function () {
|
||||
// Initialize default format drop-down
|
||||
var format = Zotero.Prefs.get("export.noteQuickCopy.setting");
|
||||
format = Zotero.QuickCopy.unserializeSetting(format);
|
||||
var menulist = document.getElementById("zotero-noteQuickCopy-menu");
|
||||
menulist.setAttribute('preference', "pref-noteQuickCopy-setting");
|
||||
|
||||
if (!format) {
|
||||
format = menulist.value;
|
||||
}
|
||||
|
||||
format = Zotero.QuickCopy.unserializeSetting(format);
|
||||
|
||||
menulist.selectedItem = null;
|
||||
menulist.removeAllItems();
|
||||
|
||||
var popup = document.createElement('menupopup');
|
||||
menulist.appendChild(popup);
|
||||
|
||||
// add export formats to list
|
||||
var translation = new Zotero.Translate("export");
|
||||
var translators = await translation.getTranslators();
|
||||
|
||||
translators.sort((a, b) => a.label.localeCompare(b.label));
|
||||
|
||||
// Remove "Note" prefix from Note HTML translator
|
||||
let htmlTranslator = translators.find(
|
||||
x => x.translatorID == Zotero.Translators.TRANSLATOR_ID_NOTE_HTML
|
||||
);
|
||||
if (htmlTranslator) {
|
||||
htmlTranslator.label = 'HTML';
|
||||
}
|
||||
|
||||
// Make sure virtual "Markdown + Rich Text" translator doesn't actually exist
|
||||
translators = translators.filter(
|
||||
x => x.translatorID != Zotero.Translators.TRANSLATOR_ID_MARKDOWN_AND_RICH_TEXT
|
||||
);
|
||||
|
||||
let markdownTranslatorIdx = translators.findIndex(
|
||||
x => x.translatorID == Zotero.Translators.TRANSLATOR_ID_NOTE_MARKDOWN
|
||||
);
|
||||
// Make sure we actually have both translators
|
||||
if (markdownTranslatorIdx != -1 && htmlTranslator) {
|
||||
// Exclude standalone Note Markdown translator
|
||||
translators.splice(markdownTranslatorIdx, 1);
|
||||
// Add virtual "Markdown + Rich Text" translator to the top
|
||||
translators.unshift({
|
||||
translatorID: Zotero.Translators.TRANSLATOR_ID_MARKDOWN_AND_RICH_TEXT,
|
||||
label: 'Markdown + ' + Zotero.getString('general.richText'),
|
||||
configOptions: {
|
||||
noteTranslator: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
translators.forEach(function (translator) {
|
||||
// Allow only note export translators
|
||||
if (!translator.configOptions || !translator.configOptions.noteTranslator) {
|
||||
return;
|
||||
}
|
||||
|
||||
var val = JSON.stringify({ mode: 'export', id: translator.translatorID });
|
||||
var itemNode = document.createElement('menuitem');
|
||||
itemNode.setAttribute('value', val);
|
||||
itemNode.setAttribute('label', translator.label);
|
||||
// itemNode.setAttribute('oncommand', 'Zotero_Preferences.Export.updateQuickCopyUI()');
|
||||
popup.appendChild(itemNode);
|
||||
|
||||
if (format.mode == 'export' && format.id == translator.translatorID) {
|
||||
menulist.selectedItem = itemNode;
|
||||
}
|
||||
});
|
||||
|
||||
menulist.click();
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
* Builds a Quick Copy drop-down
|
||||
*/
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
<preference id="pref-quickCopy-setting" name="extensions.zotero.export.quickCopy.setting" type="string"/>
|
||||
<preference id="pref-quickCopy-dragLimit" name="extensions.zotero.export.quickCopy.dragLimit" type="int"/>
|
||||
<preference id="pref-quickCopy-locale" name="extensions.zotero.export.quickCopy.locale" type="string"/>
|
||||
<preference id="pref-noteQuickCopy-setting" name="extensions.zotero.export.noteQuickCopy.setting" type="string"/>
|
||||
<preference id="pref-import-charset" name="extensions.zotero.import.charset" type="string"/>
|
||||
</preferences>
|
||||
|
||||
|
@ -53,7 +54,7 @@
|
|||
|
||||
<separator/>
|
||||
|
||||
<label value="&zotero.preferences.quickCopy.defaultFormat;" control="quickCopy-menu"/>
|
||||
<label value="&zotero.preferences.quickCopy.itemFormat;" control="quickCopy-menu"/>
|
||||
<menulist id="zotero-quickCopy-menu" label="&zotero.general.loading;"/>
|
||||
|
||||
<hbox align="center">
|
||||
|
@ -68,8 +69,13 @@
|
|||
|
||||
<separator/>
|
||||
|
||||
<label value="&zotero.preferences.quickCopy.noteFormat;" control="zotero-noteQuickCopy-menu"/>
|
||||
<menulist id="zotero-noteQuickCopy-menu" label="&zotero.general.loading;"/>
|
||||
|
||||
<separator/>
|
||||
|
||||
<label value="&zotero.preferences.quickCopy.siteEditor.setings;" control="quickCopy-siteSettings"/>
|
||||
<hbox class="virtualized-table-container" flex="1" height="300px">
|
||||
<hbox class="virtualized-table-container" flex="1" height="120px">
|
||||
<html:div id="quickCopy-siteSettings"/>
|
||||
</hbox>
|
||||
<separator class="thin"/>
|
||||
|
|
|
@ -306,42 +306,45 @@ const ZoteroStandalone = new function() {
|
|||
|
||||
|
||||
this.updateQuickCopyOptions = function () {
|
||||
var selected = false;
|
||||
var selected = [];
|
||||
|
||||
let win = Zotero.getMainWindow();
|
||||
if (win) {
|
||||
if (win.Zotero_Tabs.selectedID == 'zotero-pane') {
|
||||
try {
|
||||
selected = win.ZoteroPane
|
||||
.getSelectedItems()
|
||||
.filter(item => item.isRegularItem())
|
||||
.length;
|
||||
selected = win.ZoteroPane.getSelectedItems();
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
win.ZoteroPane.updateQuickCopyCommands(win.ZoteroPane.getSelectedItems());
|
||||
win.ZoteroPane.updateQuickCopyCommands(selected);
|
||||
}
|
||||
else {
|
||||
let reader = Zotero.Reader.getByTabID(win.Zotero_Tabs.selectedID);
|
||||
if (reader) {
|
||||
let item = Zotero.Items.get(reader.itemID);
|
||||
selected = !!item.parentItemID;
|
||||
selected = item.parentItem && [item.parentItem] || [];
|
||||
item = item.parentItem || item;
|
||||
win.ZoteroPane.updateQuickCopyCommands([item]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var format = Zotero.QuickCopy.getFormatFromURL(Zotero.QuickCopy.lastActiveURL);
|
||||
var exportingNotes = selected.every(item => item.isNote() || item.isAttachment());
|
||||
if (exportingNotes) {
|
||||
format = Zotero.QuickCopy.getNoteFormat();
|
||||
}
|
||||
format = Zotero.QuickCopy.unserializeSetting(format);
|
||||
|
||||
var copyCitation = document.getElementById('menu_copyCitation');
|
||||
var copyBibliography = document.getElementById('menu_copyBibliography');
|
||||
var copyExport = document.getElementById('menu_copyExport');
|
||||
var copyNote = document.getElementById('menu_copyNote');
|
||||
|
||||
copyCitation.hidden = !selected || format.mode != 'bibliography';
|
||||
copyBibliography.hidden = !selected || format.mode != 'bibliography';
|
||||
copyExport.hidden = !selected || format.mode != 'export';
|
||||
copyCitation.hidden = !selected.length || format.mode != 'bibliography';
|
||||
copyBibliography.hidden = !selected.length || format.mode != 'bibliography';
|
||||
copyExport.hidden = !selected.length || format.mode != 'export' || exportingNotes;
|
||||
copyNote.hidden = !selected.length || format.mode != 'export' || !exportingNotes;
|
||||
if (format.mode == 'export') {
|
||||
try {
|
||||
let obj = Zotero.Translators.get(format.id);
|
||||
|
|
|
@ -210,6 +210,11 @@
|
|||
key="key_copyBibliography"
|
||||
command="cmd_zotero_copyBibliography"
|
||||
hidden="true"/>
|
||||
<menuitem id="menu_copyNote"
|
||||
label="©NoteCmd.label;"
|
||||
command="cmd_zotero_copyBibliography"
|
||||
key="key_copyBibliography"
|
||||
hidden="true"/>
|
||||
<menuitem id="menu_paste"/>
|
||||
<menuitem id="menu_delete"/>
|
||||
<menuseparator class="menu-type-library"/>
|
||||
|
|
|
@ -43,6 +43,10 @@ Zotero.QuickCopy = new function() {
|
|||
this._prefObserverID = Zotero.Prefs.registerObserver(
|
||||
"export.quickCopy.setting", _loadOutputFormat
|
||||
);
|
||||
|
||||
this._prefObserverID = Zotero.Prefs.registerObserver(
|
||||
"export.noteQuickCopy.setting", _loadNoteOutputFormat
|
||||
);
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
|
@ -59,6 +63,7 @@ Zotero.QuickCopy = new function() {
|
|||
_initPromise = Zotero.Promise.each(
|
||||
[
|
||||
() => _loadOutputFormat(),
|
||||
() => _loadNoteOutputFormat(),
|
||||
() => this.loadSiteSettings()
|
||||
],
|
||||
f => f()
|
||||
|
@ -157,6 +162,11 @@ Zotero.QuickCopy = new function() {
|
|||
return '';
|
||||
});
|
||||
|
||||
this.getNoteFormat = function () {
|
||||
var pref = Zotero.Prefs.get('export.noteQuickCopy.setting');
|
||||
pref = JSON.stringify(this.unserializeSetting(pref));
|
||||
return pref;
|
||||
};
|
||||
|
||||
this.getFormatFromURL = function(url) {
|
||||
var quickCopyPref = Zotero.Prefs.get("export.quickCopy.setting");
|
||||
|
@ -256,167 +266,15 @@ Zotero.QuickCopy = new function() {
|
|||
if (format.mode == 'export') {
|
||||
var translation = new Zotero.Translate.Export;
|
||||
translation.noWait = true; // needed not to break drags
|
||||
translation.setItems(items);
|
||||
// Allow to reuse items array
|
||||
translation.setItems(items.slice());
|
||||
translation.setTranslator(format.id);
|
||||
translation.setHandler("done", callback);
|
||||
translation.translate();
|
||||
return true;
|
||||
}
|
||||
else if (format.mode == 'bibliography') {
|
||||
// Move notes to separate array
|
||||
var allNotes = true;
|
||||
var notes = [];
|
||||
for (var i=0; i<items.length; i++) {
|
||||
if (items[i].isNote()) {
|
||||
notes.push(items.splice(i, 1)[0]);
|
||||
i--;
|
||||
}
|
||||
else {
|
||||
allNotes = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If all notes, export full content
|
||||
if (allNotes) {
|
||||
var content = [];
|
||||
let parser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
|
||||
.createInstance(Components.interfaces.nsIDOMParser);
|
||||
let docHTML = '<html><body><div class="zotero-notes"/></body></html>';
|
||||
let doc = parser.parseFromString(docHTML, 'text/html');
|
||||
let textDoc = parser.parseFromString(docHTML, 'text/html');
|
||||
let container = doc.body.firstChild;
|
||||
let textContainer = textDoc.body.firstChild;
|
||||
|
||||
for (var i=0; i<notes.length; i++) {
|
||||
var div = doc.createElement("div");
|
||||
div.className = "zotero-note";
|
||||
// AMO reviewer: This documented is never rendered (and the inserted markup
|
||||
// is sanitized anyway)
|
||||
div.insertAdjacentHTML('afterbegin', notes[i].note);
|
||||
container.appendChild(div);
|
||||
textContainer.appendChild(textDoc.importNode(div, true));
|
||||
}
|
||||
|
||||
// Raw HTML output
|
||||
var html = container.outerHTML;
|
||||
|
||||
// Add placeholders for newlines between notes
|
||||
if (notes.length > 1) {
|
||||
var divs = Zotero.Utilities.xpath(container, "div"),
|
||||
textDivs = Zotero.Utilities.xpath(textContainer, "div");
|
||||
for (var i=1, len=divs.length; i<len; i++) {
|
||||
var p = doc.createElement("p");
|
||||
p.appendChild(doc.createTextNode("--------------------------------------------------"));
|
||||
container.insertBefore(p, divs[i]);
|
||||
textContainer.insertBefore(textDoc.importNode(p, true), textDivs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const BLOCKQUOTE_PREFS = {
|
||||
'export.quickCopy.quoteBlockquotes.richText':doc,
|
||||
'export.quickCopy.quoteBlockquotes.plainText':textDoc
|
||||
};
|
||||
for(var pref in BLOCKQUOTE_PREFS) {
|
||||
if (Zotero.Prefs.get(pref)) {
|
||||
var currentDoc = BLOCKQUOTE_PREFS[pref];
|
||||
// Add quotes around blockquote paragraphs
|
||||
var addOpenQuote = Zotero.Utilities.xpath(currentDoc, "//blockquote/p[1]"),
|
||||
addCloseQuote = Zotero.Utilities.xpath(currentDoc, "//blockquote/p[last()]");
|
||||
for(var i=0; i<addOpenQuote.length; i++) {
|
||||
addOpenQuote[i].insertBefore(currentDoc.createTextNode("\u201c"),
|
||||
addOpenQuote[i].firstChild);
|
||||
}
|
||||
for(var i=0; i<addCloseQuote.length; i++) {
|
||||
addCloseQuote[i].appendChild(currentDoc.createTextNode("\u201d"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Text-only adjustments
|
||||
//
|
||||
|
||||
// Replace span styles with characters
|
||||
var spans = textDoc.getElementsByTagName("span");
|
||||
for(var i=0; i<spans.length; i++) {
|
||||
var span = spans[i];
|
||||
if(span.style.textDecoration == "underline") {
|
||||
span.insertBefore(textDoc.createTextNode("_"), span.firstChild);
|
||||
span.appendChild(textDoc.createTextNode("_"));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// And add spaces for indents
|
||||
//
|
||||
// Placeholder for 4 spaces in final output
|
||||
const ZTAB = "%%ZOTEROTAB%%";
|
||||
var ps = textDoc.getElementsByTagName("p");
|
||||
for(var i=0; i<ps.length; i++) {
|
||||
var p = ps[i],
|
||||
paddingLeft = p.style.paddingLeft;
|
||||
if(paddingLeft && paddingLeft.substr(paddingLeft.length-2) === "px") {
|
||||
var paddingPx = parseInt(paddingLeft, 10),
|
||||
ztabs = "";
|
||||
for (let j = 30; j <= paddingPx; j += 30) ztabs += ZTAB;
|
||||
p.insertBefore(textDoc.createTextNode(ztabs), p.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
// Use plaintext serializer to output formatted text
|
||||
var docEncoder = Components.classes["@mozilla.org/layout/documentEncoder;1?type=text/html"]
|
||||
.createInstance(Components.interfaces.nsIDocumentEncoder);
|
||||
docEncoder.init(textDoc, "text/plain", docEncoder.OutputFormatted);
|
||||
var text = docEncoder.encodeToString().trim().replace(ZTAB, " ", "g");
|
||||
|
||||
//
|
||||
// Adjustments for the HTML copied to the clipboard
|
||||
//
|
||||
|
||||
// Everything seems to like margin-left better than padding-left
|
||||
var ps = Zotero.Utilities.xpath(doc, "p");
|
||||
for(var i=0; i<ps.length; i++) {
|
||||
var p = ps[i];
|
||||
if(p.style.paddingLeft) {
|
||||
p.style.marginLeft = p.style.paddingLeft;
|
||||
p.style.paddingLeft = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Word and TextEdit don't indent blockquotes on their own and need this
|
||||
//
|
||||
// OO gets it right, so this results in an extra indent
|
||||
if (Zotero.Prefs.get('export.quickCopy.compatibility.indentBlockquotes')) {
|
||||
var ps = Zotero.Utilities.xpath(doc, "//blockquote/p");
|
||||
for(var i=0; i<ps.length; i++) ps[i].style.marginLeft = "30px";
|
||||
}
|
||||
|
||||
// Add Word Normal style to paragraphs and add double-spacing
|
||||
//
|
||||
// OO inserts the conditional style code as a document comment
|
||||
if (Zotero.Prefs.get('export.quickCopy.compatibility.word')) {
|
||||
var ps = doc.getElementsByTagName("p");
|
||||
for (var i=0; i<ps.length; i++) ps[i].className = "msoNormal";
|
||||
var copyHTML = "<!--[if gte mso 0]>"
|
||||
+ "<style>"
|
||||
+ "p { margin-top:.1pt;margin-right:0in;margin-bottom:.1pt;margin-left:0in; line-height: 200%; }"
|
||||
+ "li { margin-top:.1pt;margin-right:0in;margin-bottom:.1pt;margin-left:0in; line-height: 200%; }"
|
||||
+ "blockquote p { margin-left: 11px; margin-right: 11px }"
|
||||
+ "</style>"
|
||||
+ "<![endif]-->\n"
|
||||
+ container.outerHTML;
|
||||
}
|
||||
else {
|
||||
var copyHTML = container.outerHTML;
|
||||
}
|
||||
|
||||
var content = {
|
||||
text: format.contentType == "html" ? html : text,
|
||||
html: copyHTML
|
||||
};
|
||||
|
||||
return content;
|
||||
}
|
||||
items = items.filter(item => !item.isNote());
|
||||
|
||||
// determine locale preference
|
||||
var locale = format.locale ? format.locale : Zotero.Prefs.get('export.quickCopy.locale');
|
||||
|
@ -458,6 +316,20 @@ Zotero.QuickCopy = new function() {
|
|||
});
|
||||
|
||||
|
||||
var _loadNoteOutputFormat = async function () {
|
||||
var format = Zotero.Prefs.get("export.noteQuickCopy.setting");
|
||||
format = Zotero.QuickCopy.unserializeSetting(format);
|
||||
// If virtual "Markdown + Rich Text" translator is selected, preload Note Markdown and
|
||||
// Note HTML translators
|
||||
if (format.id == Zotero.Translators.TRANSLATOR_ID_MARKDOWN_AND_RICH_TEXT) {
|
||||
await _preloadFormat({ mode: 'export', id: Zotero.Translators.TRANSLATOR_ID_NOTE_MARKDOWN });
|
||||
await _preloadFormat({ mode: 'export', id: Zotero.Translators.TRANSLATOR_ID_NOTE_HTML });
|
||||
return;
|
||||
}
|
||||
return _preloadFormat(format);
|
||||
};
|
||||
|
||||
|
||||
var _preloadFormat = async function (format) {
|
||||
format = Zotero.QuickCopy.unserializeSetting(format);
|
||||
if (format.mode == 'export') {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 85b39a5be5bb59c5ee5e7447609273a29ea0b799
|
||||
Subproject commit b75bc2550ae2df3bb307e7abf0d3abad96f79c82
|
|
@ -809,9 +809,20 @@ Zotero.Translate.IO.Write.prototype = {
|
|||
this._charset = charset;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a function to modify data on each write()
|
||||
*/
|
||||
setDataProcessor: function (processor) {
|
||||
this._processor = processor;
|
||||
},
|
||||
|
||||
"write":function(data) {
|
||||
if(!this._charset) this.setCharacterSet("UTF-8");
|
||||
|
||||
if (this._processor) {
|
||||
data = this._processor(data);
|
||||
}
|
||||
|
||||
if(!this._writtenToStream && this._charset.substr(this._charset.length-4) == "xBOM"
|
||||
&& BOMs[this._charset.substr(0, this._charset.length-4).toUpperCase()]) {
|
||||
// If stream has not yet been written to, and a UTF type has been selected, write BOM
|
||||
|
|
|
@ -1014,7 +1014,10 @@ Zotero.Translate.ItemGetter = function() {
|
|||
Zotero.Translate.ItemGetter.prototype = {
|
||||
setItems: function (items) {
|
||||
this._itemsLeft = items;
|
||||
this._itemsLeft.sort((a, b) => a.id - b.id);
|
||||
// Don't sort items if doing notes export
|
||||
if (!items.every(item => item.isNote() || item.isAttachment())) {
|
||||
this._itemsLeft.sort((a, b) => a.id - b.id);
|
||||
}
|
||||
this.numItems = this._itemsLeft.length;
|
||||
},
|
||||
|
||||
|
|
|
@ -34,6 +34,10 @@ Zotero.Translators = new function() {
|
|||
var _initialized = false;
|
||||
var _initializationDeferred = false;
|
||||
|
||||
this.TRANSLATOR_ID_MARKDOWN_AND_RICH_TEXT = 'a45eca67-1ee8-45e5-b4c6-23fb8a852873';
|
||||
this.TRANSLATOR_ID_NOTE_MARKDOWN = '1412e9e2-51e1-42ec-aa35-e036a895534b';
|
||||
this.TRANSLATOR_ID_NOTE_HTML = '897a81c2-9f60-4bec-ae6b-85a5030b8be5';
|
||||
|
||||
/**
|
||||
* Initializes translator cache, loading all translator metadata into memory
|
||||
*
|
||||
|
|
|
@ -1605,18 +1605,28 @@ var ZoteroPane = new function()
|
|||
|
||||
/**
|
||||
* Update the <command> elements that control the shortcut keys and the enabled state of the
|
||||
* "Copy Citation"/"Copy Bibliography"/"Copy as" menu options. When disabled, the shortcuts are
|
||||
* "Copy Citation"/"Copy Bibliography"/"Copy as"/"Copy Note" menu options. When disabled, the shortcuts are
|
||||
* still caught in handleKeyPress so that we can show an alert about not having references selected.
|
||||
*/
|
||||
this.updateQuickCopyCommands = function (selectedItems) {
|
||||
var format = Zotero.QuickCopy.getFormatFromURL(Zotero.QuickCopy.lastActiveURL);
|
||||
format = Zotero.QuickCopy.unserializeSetting(format);
|
||||
if (format.mode == 'bibliography') {
|
||||
var canCopy = selectedItems.some(item => item.isRegularItem());
|
||||
let canCopy = false;
|
||||
// If all items are notes/attachments and at least one note is not empty
|
||||
if (selectedItems.every(item => item.isNote() || item.isAttachment())) {
|
||||
if (selectedItems.some(item => item.note)) {
|
||||
canCopy = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var canCopy = true;
|
||||
let format = Zotero.QuickCopy.getFormatFromURL(Zotero.QuickCopy.lastActiveURL);
|
||||
format = Zotero.QuickCopy.unserializeSetting(format);
|
||||
if (format.mode == 'bibliography') {
|
||||
canCopy = selectedItems.some(item => item.isRegularItem());
|
||||
}
|
||||
else {
|
||||
canCopy = true;
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('cmd_zotero_copyCitation').setAttribute('disabled', !canCopy);
|
||||
document.getElementById('cmd_zotero_copyBibliography').setAttribute('disabled', !canCopy);
|
||||
};
|
||||
|
@ -2075,7 +2085,10 @@ var ZoteroPane = new function()
|
|||
this.copySelectedItemsToClipboard = function (asCitations) {
|
||||
var items = [];
|
||||
if (Zotero_Tabs.selectedID == 'zotero-pane') {
|
||||
items = this.getSelectedItems();
|
||||
let itemIDs = this.getSelectedItems(true);
|
||||
// Get selected item IDs in the item tree order
|
||||
itemIDs = this.getSortedItems(true).filter(id => itemIDs.includes(id));
|
||||
items = Zotero.Items.get(itemIDs);
|
||||
}
|
||||
else {
|
||||
var reader = Zotero.Reader.getByTabID(Zotero_Tabs.selectedID);
|
||||
|
@ -2092,6 +2105,9 @@ var ZoteroPane = new function()
|
|||
}
|
||||
|
||||
var format = Zotero.QuickCopy.getFormatFromURL(Zotero.QuickCopy.lastActiveURL);
|
||||
if (items.every(item => item.isNote() || item.isAttachment())) {
|
||||
format = Zotero.QuickCopy.getNoteFormat();
|
||||
}
|
||||
format = Zotero.QuickCopy.unserializeSetting(format);
|
||||
|
||||
// In bibliography mode, remove notes and attachments
|
||||
|
@ -2966,6 +2982,12 @@ var ZoteroPane = new function()
|
|||
disable.push(m.showInLibrary, m.duplicateItem, m.removeItems,
|
||||
m.moveToTrash, m.deleteFromLibrary, m.exportItems, m.createBib, m.loadReport);
|
||||
}
|
||||
|
||||
if (!disable.includes(m.exportItems)
|
||||
&& items.every(item => item.isNote() || item.isAttachment())
|
||||
&& !items.some(item => item.note)) {
|
||||
disable.push(m.exportItems);
|
||||
}
|
||||
|
||||
if ((!collectionTreeRow.editable || collectionTreeRow.isPublications()) && !collectionTreeRow.isFeed()) {
|
||||
for (let i in m) {
|
||||
|
|
|
@ -104,7 +104,8 @@
|
|||
<!ENTITY zotero.preferences.export.citePaperJournalArticleURL.description "When this option is disabled, Zotero includes URLs when citing journal, magazine, and newspaper articles only if the article does not have a page range specified.">
|
||||
|
||||
<!ENTITY zotero.preferences.quickCopy.caption "Quick Copy">
|
||||
<!ENTITY zotero.preferences.quickCopy.defaultFormat "Default Format:">
|
||||
<!ENTITY zotero.preferences.quickCopy.itemFormat "Item Format:">
|
||||
<!ENTITY zotero.preferences.quickCopy.noteFormat "Note Format:">
|
||||
<!ENTITY zotero.preferences.quickCopy.copyAsHTML "Copy as HTML">
|
||||
<!ENTITY zotero.preferences.quickCopy.siteEditor.setings "Site-Specific Settings:">
|
||||
<!ENTITY zotero.preferences.quickCopy.siteEditor.domainPath "Domain/Path">
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
<!--EDIT MENU-->
|
||||
<!ENTITY copyCitationCmd.label "Copy Citation">
|
||||
<!ENTITY copyBibliographyCmd.label "Copy Bibliography">
|
||||
<!ENTITY copyNoteCmd.label "Copy Note">
|
||||
|
||||
<!ENTITY bidiSwitchPageDirectionItem.label "Switch Page Direction">
|
||||
<!ENTITY bidiSwitchPageDirectionItem.accesskey "g">
|
||||
|
|
|
@ -87,6 +87,7 @@ general.languages = Languages
|
|||
general.default = Default
|
||||
general.custom = Custom
|
||||
general.loading = Loading…
|
||||
general.richText = Rich Text
|
||||
|
||||
general.yellow = Yellow
|
||||
general.red = Red
|
||||
|
@ -826,6 +827,7 @@ fulltext.indexState.queued = Queued
|
|||
exportOptions.exportNotes = Export Notes
|
||||
exportOptions.exportFileData = Export Files
|
||||
exportOptions.includeAnnotations = Include Annotations
|
||||
exportOptions.includeAppLinks = Include %S Links
|
||||
exportOptions.useJournalAbbreviation = Use Journal Abbreviation
|
||||
charset.UTF8withoutBOM = Unicode (UTF-8 without BOM)
|
||||
charset.autoDetect = (auto detect)
|
||||
|
|
|
@ -109,6 +109,8 @@ pref("extensions.zotero.report.combineChildItems", true);
|
|||
// Export and citation settings
|
||||
pref("extensions.zotero.export.lastTranslator", "14763d24-8ba0-45df-8f52-b8d1108e7ac9");
|
||||
pref("extensions.zotero.export.translatorSettings", "true,false");
|
||||
pref("extensions.zotero.export.lastNoteTranslator", "1412e9e2-51e1-42ec-aa35-e036a895534b");
|
||||
pref("extensions.zotero.export.noteTranslatorSettings", "");
|
||||
pref("extensions.zotero.export.lastStyle", "http://www.zotero.org/styles/chicago-note-bibliography");
|
||||
pref("extensions.zotero.export.bibliographySettings", "save-as-rtf");
|
||||
pref("extensions.zotero.export.displayCharsetOption", true);
|
||||
|
@ -121,10 +123,8 @@ pref("extensions.zotero.rtfScan.lastOutputFile", "");
|
|||
|
||||
pref("extensions.zotero.export.quickCopy.setting", "bibliography=http://www.zotero.org/styles/chicago-note-bibliography");
|
||||
pref("extensions.zotero.export.quickCopy.dragLimit", 50);
|
||||
pref("extensions.zotero.export.quickCopy.quoteBlockquotes.plainText", true);
|
||||
pref("extensions.zotero.export.quickCopy.quoteBlockquotes.richText", true);
|
||||
pref("extensions.zotero.export.quickCopy.compatibility.indentBlockquotes", true);
|
||||
pref("extensions.zotero.export.quickCopy.compatibility.word", false);
|
||||
|
||||
pref("extensions.zotero.export.noteQuickCopy.setting", '{"mode": "export", "id": "a45eca67-1ee8-45e5-b4c6-23fb8a852873"}');
|
||||
|
||||
// Integration settings
|
||||
pref("extensions.zotero.integration.port", 50001);
|
||||
|
|
|
@ -73,17 +73,6 @@ describe("Zotero.QuickCopy", function() {
|
|||
assert.isTrue(worked);
|
||||
assert.isTrue(content.trim().startsWith('@'));
|
||||
});
|
||||
|
||||
it("should copy note content", async function () {
|
||||
var item = await createDataObject('item', { itemType: 'note', note: '<p>Foo</p>' });
|
||||
|
||||
var format = 'bibliography=http://www.zotero.org/styles/apa';
|
||||
Zotero.Prefs.set(prefName, format);
|
||||
|
||||
var content = Zotero.QuickCopy.getContentFromItems([item], format);
|
||||
assert.propertyVal(content, 'text', 'Foo');
|
||||
assert.propertyVal(content, 'html', '<div class=\"zotero-notes\"><div class=\"zotero-note\"><p>Foo</p></div></div>');
|
||||
});
|
||||
});
|
||||
|
||||
it("should generate bibliography in default locale if Quick Copy locale not set", async function () {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit d652a4de827b2ce25b6fac69f2e3e6e37cb74488
|
||||
Subproject commit be5fc1633d0473bd662c35e887564a02abac7874
|
Loading…
Reference in a new issue