Add import option for storing or linking files
This allows files in Mendeley imports to be stored and files in RIS/BibTeX/etc. to be linked. Closes #329
This commit is contained in:
parent
70a8bce739
commit
04779d8d1c
11 changed files with 181 additions and 22 deletions
|
@ -296,6 +296,7 @@ var Zotero_File_Interface = new function() {
|
|||
* @param {nsIFile|string|null} [options.file=null] - File to import, or none to show a filepicker
|
||||
* @param {Boolean} [options.addToLibraryRoot=false]
|
||||
* @param {Boolean} [options.createNewCollection=true] - Put items in a new collection
|
||||
* @param {Boolean} [options.linkFiles=false] - Link to files instead of storing them
|
||||
* @param {Function} [options.onBeforeImport] - Callback to receive translation object, useful
|
||||
* for displaying progress in a different way. This also causes an error to be throw
|
||||
* instead of shown in the main window.
|
||||
|
@ -315,6 +316,7 @@ var Zotero_File_Interface = new function() {
|
|||
var file = options.file ? Zotero.File.pathToFile(options.file) : null;
|
||||
var createNewCollection = options.createNewCollection;
|
||||
var addToLibraryRoot = options.addToLibraryRoot;
|
||||
var linkFiles = options.linkFiles;
|
||||
var onBeforeImport = options.onBeforeImport;
|
||||
|
||||
if (createNewCollection === undefined && !addToLibraryRoot) {
|
||||
|
@ -359,6 +361,7 @@ var Zotero_File_Interface = new function() {
|
|||
translation,
|
||||
createNewCollection,
|
||||
addToLibraryRoot,
|
||||
linkFiles,
|
||||
defaultNewCollectionPrefix,
|
||||
onBeforeImport
|
||||
});
|
||||
|
@ -412,6 +415,7 @@ var Zotero_File_Interface = new function() {
|
|||
var translation = options.translation;
|
||||
var addToLibraryRoot = options.addToLibraryRoot;
|
||||
var createNewCollection = options.createNewCollection;
|
||||
var linkFiles = options.linkFiles;
|
||||
var defaultNewCollectionPrefix = options.defaultNewCollectionPrefix;
|
||||
var onBeforeImport = options.onBeforeImport;
|
||||
|
||||
|
@ -518,7 +522,8 @@ var Zotero_File_Interface = new function() {
|
|||
try {
|
||||
yield translation.translate({
|
||||
libraryID,
|
||||
collections: importCollection ? [importCollection.id] : null
|
||||
collections: importCollection ? [importCollection.id] : null,
|
||||
linkFiles
|
||||
});
|
||||
} catch(e) {
|
||||
if (!showProgressWindow) {
|
||||
|
|
|
@ -31,6 +31,17 @@ var Zotero_Import_Wizard = {
|
|||
}
|
||||
}
|
||||
|
||||
// Update labels
|
||||
document.getElementById('file-handling-store').label = Zotero.getString(
|
||||
'import.fileHandling.store',
|
||||
Zotero.appName
|
||||
);
|
||||
document.getElementById('file-handling-link').label = Zotero.getString('import.fileHandling.link');
|
||||
document.getElementById('file-handling-description').textContent = Zotero.getString(
|
||||
'import.fileHandling.description',
|
||||
Zotero.appName
|
||||
);
|
||||
|
||||
Zotero.Translators.init(); // async
|
||||
},
|
||||
|
||||
|
@ -160,20 +171,6 @@ var Zotero_Import_Wizard = {
|
|||
},
|
||||
|
||||
|
||||
onImportStart: async function () {
|
||||
if (!this._file) {
|
||||
let index = document.getElementById('file-list').selectedIndex;
|
||||
this._file = this._dbs[index].path;
|
||||
}
|
||||
this._disableCancel();
|
||||
this._wizard.canRewind = false;
|
||||
this._wizard.canAdvance = false;
|
||||
await this.doImport({
|
||||
createNewCollection: document.getElementById('create-collection-checkbox').hasAttribute('checked')
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
onBeforeImport: async function (translation) {
|
||||
// Unrecognized translator
|
||||
if (!translation) {
|
||||
|
@ -196,12 +193,22 @@ var Zotero_Import_Wizard = {
|
|||
},
|
||||
|
||||
|
||||
doImport: async function (options) {
|
||||
onImportStart: async function () {
|
||||
if (!this._file) {
|
||||
let index = document.getElementById('file-list').selectedIndex;
|
||||
this._file = this._dbs[index].path;
|
||||
}
|
||||
this._disableCancel();
|
||||
this._wizard.canRewind = false;
|
||||
this._wizard.canAdvance = false;
|
||||
|
||||
try {
|
||||
let result = await Zotero_File_Interface.importFile({
|
||||
file: this._file,
|
||||
onBeforeImport: this.onBeforeImport.bind(this),
|
||||
addToLibraryRoot: !options.createNewCollection
|
||||
addToLibraryRoot: !document.getElementById('create-collection-checkbox')
|
||||
.hasAttribute('checked'),
|
||||
linkFiles: document.getElementById('file-handling-radio').selectedIndex == 1
|
||||
});
|
||||
|
||||
// Cancelled by user or due to error
|
||||
|
|
|
@ -54,6 +54,16 @@
|
|||
onpagerewound="return Zotero_Import_Wizard.goToStart()"
|
||||
onpageadvanced="Zotero_Import_Wizard.onImportStart()">
|
||||
<checkbox id="create-collection-checkbox" label="&zotero.import.createCollection;" checked="true" />
|
||||
|
||||
<vbox id="file-handling-options">
|
||||
<label control="file-handling-radio" value="&zotero.import.fileHandling;"/>
|
||||
<radiogroup id="file-handling-radio">
|
||||
<radio id="file-handling-store" selected="true"/>
|
||||
<radio id="file-handling-link"/>
|
||||
</radiogroup>
|
||||
<description id="file-handling-description"/>
|
||||
</vbox>
|
||||
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage pageid="page-progress"
|
||||
|
|
|
@ -6,6 +6,7 @@ Services.scriptloader.loadSubScript("chrome://zotero/content/include.js");
|
|||
|
||||
var Zotero_Import_Mendeley = function () {
|
||||
this.createNewCollection = null;
|
||||
this.linkFiles = null;
|
||||
this.newItems = [];
|
||||
|
||||
this._db;
|
||||
|
@ -39,7 +40,9 @@ Zotero_Import_Mendeley.prototype.getTranslators = async function () {
|
|||
|
||||
Zotero_Import_Mendeley.prototype.setTranslator = function () {};
|
||||
|
||||
Zotero_Import_Mendeley.prototype.translate = async function (options) {
|
||||
Zotero_Import_Mendeley.prototype.translate = async function (options = {}) {
|
||||
this._linkFiles = options.linkFiles;
|
||||
|
||||
if (true) {
|
||||
Services.scriptloader.loadSubScript("chrome://zotero/content/import/mendeley/mendeleySchemaMap.js");
|
||||
}
|
||||
|
@ -987,8 +990,8 @@ Zotero_Import_Mendeley.prototype._saveFilesAndAnnotations = async function (file
|
|||
parentItemID,
|
||||
file: realPath
|
||||
};
|
||||
// If file is in Mendeley downloads folder, import it
|
||||
if (this._isDownloadedFile(path)) {
|
||||
// If we're not set to link files or file is in Mendeley downloads folder, import it
|
||||
if (!this._linkFiles || this._isDownloadedFile(path)) {
|
||||
if (file.url) {
|
||||
options.title = file.title;
|
||||
options.url = file.url;
|
||||
|
|
|
@ -152,6 +152,8 @@ Zotero.Attachments = new function(){
|
|||
* @param {nsIFile|String} options.file - File to add
|
||||
* @param {Integer[]|String[]} [options.parentItemID] - Parent item to add item to
|
||||
* @param {Integer[]} [options.collections] - Collection keys or ids to add new item to
|
||||
* @param {String} [options.contentType] - Content type
|
||||
* @param {String} [options.charset] - Character set
|
||||
* @param {Object} [options.saveOptions] - Options to pass to Zotero.Item::save()
|
||||
* @return {Promise<Zotero.Item>}
|
||||
*/
|
||||
|
@ -161,6 +163,8 @@ Zotero.Attachments = new function(){
|
|||
var file = Zotero.File.pathToFile(options.file);
|
||||
var parentItemID = options.parentItemID;
|
||||
var collections = options.collections;
|
||||
var contentType = options.contentType || (yield Zotero.MIME.getMIMETypeFromFile(file));
|
||||
var charset = options.charset;
|
||||
var saveOptions = options.saveOptions;
|
||||
|
||||
if (parentItemID && collections) {
|
||||
|
@ -168,12 +172,12 @@ Zotero.Attachments = new function(){
|
|||
}
|
||||
|
||||
var title = file.leafName;
|
||||
var contentType = yield Zotero.MIME.getMIMETypeFromFile(file);
|
||||
var item = yield _addToDB({
|
||||
file,
|
||||
title,
|
||||
linkMode: this.LINK_MODE_LINKED_FILE,
|
||||
contentType,
|
||||
charset,
|
||||
parentItemID,
|
||||
collections,
|
||||
saveOptions
|
||||
|
|
|
@ -1282,6 +1282,7 @@ Zotero.Translate.Base.prototype = {
|
|||
* or NULL for default library;
|
||||
* if FALSE, don't save items
|
||||
* @param {Boolean} [saveAttachments=true] Exclude attachments (e.g., snapshots) on import
|
||||
* @param {Boolean} [linkFiles=false] - Save linked files instead of stored files
|
||||
* @returns {Promise} Promise resolved with saved items
|
||||
* when translation complete
|
||||
*/
|
||||
|
@ -1321,6 +1322,7 @@ Zotero.Translate.Base.prototype = {
|
|||
}
|
||||
this._collections = options.collections;
|
||||
this._saveAttachments = options.saveAttachments === undefined || options.saveAttachments;
|
||||
this._linkFiles = options.linkFiles;
|
||||
this._forceTagType = options.forceTagType;
|
||||
this._saveOptions = options.saveOptions;
|
||||
|
||||
|
@ -2431,6 +2433,7 @@ Zotero.Translate.Import.prototype._prepareTranslation = Zotero.Promise.method(fu
|
|||
collections: this._collections,
|
||||
forceTagType: this._forceTagType,
|
||||
attachmentMode: Zotero.Translate.ItemSaver[(this._saveAttachments ? "ATTACHMENT_MODE_FILE" : "ATTACHMENT_MODE_IGNORE")],
|
||||
linkFiles: this._linkFiles,
|
||||
baseURI,
|
||||
saveOptions: Object.assign(
|
||||
{
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
* <li>libraryID - ID of library in which items should be saved</li>
|
||||
* <li>collections - New collections to create (used during Import translation</li>
|
||||
* <li>attachmentMode - One of Zotero.Translate.ItemSaver.ATTACHMENT_* specifying how attachments should be saved</li>
|
||||
* <li>linkFiles - Save attachments as linked files instead of stored files</li>
|
||||
* <li>forceTagType - Force tags to specified tag type</li>
|
||||
* <li>cookieSandbox - Cookie sandbox for attachment requests</li>
|
||||
* <li>proxy - A proxy to deproxify item URLs</li>
|
||||
|
@ -53,6 +54,7 @@ Zotero.Translate.ItemSaver = function(options) {
|
|||
// If group filesEditable==false, don't save attachments
|
||||
this.attachmentMode = Zotero.Libraries.get(this._libraryID).filesEditable ? options.attachmentMode :
|
||||
Zotero.Translate.ItemSaver.ATTACHMENT_MODE_IGNORE;
|
||||
this._linkFiles = options.linkFiles;
|
||||
this._forceTagType = options.forceTagType;
|
||||
this._referrer = options.referrer;
|
||||
this._cookieSandbox = options.cookieSandbox;
|
||||
|
@ -605,7 +607,24 @@ Zotero.Translate.ItemSaver.prototype = {
|
|||
title: attachment.title || undefined,
|
||||
collections: !parentItemID ? this._collections : undefined
|
||||
});
|
||||
} else {
|
||||
}
|
||||
else if (this._linkFiles
|
||||
// Don't link if it's a path to the current storage directory
|
||||
&& !Zotero.File.directoryContains(Zotero.DataDirectory.getSubdirectory('storage'), file.path)) {
|
||||
attachment.linkMode = "linked_file";
|
||||
newItem = yield Zotero.Attachments.linkFromFile({
|
||||
file,
|
||||
parentItemID,
|
||||
collections: !parentItemID ? this._collections : undefined
|
||||
});
|
||||
if (attachment.title) {
|
||||
newItem.setField("title", attachment.title);
|
||||
}
|
||||
if (attachment.url) {
|
||||
newItem.setNote(attachment.url);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (attachment.url) {
|
||||
attachment.linkMode = "imported_url";
|
||||
newItem = yield Zotero.Attachments.importSnapshotFromFile({
|
||||
|
|
|
@ -203,6 +203,7 @@
|
|||
<!ENTITY zotero.import.lastModified "Last Modified">
|
||||
<!ENTITY zotero.import.size "Size">
|
||||
<!ENTITY zotero.import.createCollection "Place imported collections and items into new collection">
|
||||
<!ENTITY zotero.import.fileHandling "File Handling">
|
||||
|
||||
<!ENTITY zotero.exportOptions.title "Export…">
|
||||
<!ENTITY zotero.exportOptions.format.label "Format:">
|
||||
|
|
|
@ -722,6 +722,10 @@ fileInterface.exportError = An error occurred while trying to export the selecte
|
|||
fileInterface.importOPML = Import Feeds from OPML
|
||||
fileInterface.OPMLFeedFilter = OPML Feed List
|
||||
|
||||
import.fileHandling.store = Copy files to the %S storage folder
|
||||
import.fileHandling.link = Link to files in original location
|
||||
import.fileHandling.description = Linked files cannot be synced by %S.
|
||||
|
||||
quickCopy.copyAs = Copy as %S
|
||||
|
||||
quickSearch.mode.titleCreatorYear = Title, Creator, Year
|
||||
|
|
|
@ -33,10 +33,32 @@ wizard[currentpageid="page-file-list"] .wizard-header {
|
|||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
#file-handling-options {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
#file-handling-options > label {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#file-handling-options radiogroup {
|
||||
font-size: 13px;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
#file-handling-options description {
|
||||
margin-top: .6em;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
listbox, #result-description, #result-description-html {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#result-description-html {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
#result-description-html a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
|
|
@ -505,6 +505,87 @@ describe("Zotero.Translate", function() {
|
|||
assert.equal(attachments[1].attachmentLinkMode, Zotero.Attachments.LINK_MODE_LINKED_URL);
|
||||
});
|
||||
|
||||
it("import translators should save linked-file attachments with linkFiles: true", async function () {
|
||||
var testDir = getTestDataDirectory().path;
|
||||
var file1 = OS.Path.join(testDir, 'test.pdf');
|
||||
var file2 = OS.Path.join(testDir, 'test.html');
|
||||
var file2URL = "http://example.com";
|
||||
var json = [
|
||||
{
|
||||
itemType: "journalArticle",
|
||||
title: "Parent Item",
|
||||
attachments: [
|
||||
{
|
||||
title: "PDF",
|
||||
mimeType: "application/pdf",
|
||||
path: file1
|
||||
},
|
||||
{
|
||||
title: "Snapshot",
|
||||
mimeType: "text/html",
|
||||
charset: "utf-8",
|
||||
url: file2URL,
|
||||
path: file2
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
var newItems = itemsArrayToObject(
|
||||
await saveItemsThroughTranslator(
|
||||
"import",
|
||||
json,
|
||||
{
|
||||
linkFiles: true
|
||||
}
|
||||
)
|
||||
);
|
||||
var attachmentIDs = newItems["Parent Item"].getAttachments();
|
||||
assert.lengthOf(attachmentIDs, 2);
|
||||
var attachments = await Zotero.Items.getAsync(attachmentIDs);
|
||||
assert.equal(attachments[0].attachmentLinkMode, Zotero.Attachments.LINK_MODE_LINKED_FILE);
|
||||
assert.equal(attachments[0].attachmentContentType, 'application/pdf');
|
||||
assert.equal(attachments[1].attachmentLinkMode, Zotero.Attachments.LINK_MODE_LINKED_FILE);
|
||||
assert.equal(attachments[1].attachmentContentType, 'text/html');
|
||||
assert.equal(attachments[1].attachmentCharset, 'utf-8');
|
||||
assert.equal(attachments[1].getNote(), file2URL);
|
||||
});
|
||||
|
||||
it("import translators shouldn't save linked-file attachment with linkFiles: true if path is within current storage directory", async function () {
|
||||
var attachment = await importFileAttachment('test.png');
|
||||
var path = attachment.getFilePath();
|
||||
var json = [
|
||||
{
|
||||
itemType: "journalArticle",
|
||||
title: "Parent Item",
|
||||
attachments: [
|
||||
{
|
||||
title: "PDF",
|
||||
mimeType: "application/pdf",
|
||||
path
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
var newItems = itemsArrayToObject(
|
||||
await saveItemsThroughTranslator(
|
||||
"import",
|
||||
json,
|
||||
{
|
||||
linkFiles: true
|
||||
}
|
||||
)
|
||||
);
|
||||
var attachmentIDs = newItems["Parent Item"].getAttachments();
|
||||
assert.lengthOf(attachmentIDs, 1);
|
||||
var attachments = await Zotero.Items.getAsync(attachmentIDs);
|
||||
assert.equal(attachments[0].attachmentLinkMode, Zotero.Attachments.LINK_MODE_IMPORTED_FILE);
|
||||
var newPath = attachments[0].getFilePath();
|
||||
assert.ok(newPath);
|
||||
assert.notEqual(newPath, path);
|
||||
});
|
||||
|
||||
it('web translators should set accessDate to current date', function* () {
|
||||
let myItem = {
|
||||
"itemType":"webpage",
|
||||
|
|
Loading…
Add table
Reference in a new issue