Add "Convert Linked Files to Stored Files…" menu option
In new File → Manage Attachments submenu Closes #1637
This commit is contained in:
parent
eca2822651
commit
bb59429664
11 changed files with 417 additions and 61 deletions
|
@ -91,6 +91,23 @@ const ZoteroStandalone = new function() {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
this.onFileMenuOpen = function () {
|
||||
var active = false;
|
||||
try {
|
||||
let zp = Zotero.getActiveZoteroPane();
|
||||
if (zp) {
|
||||
active = !!zp.getSelectedItems().filter((item) => {
|
||||
return item.isAttachment()
|
||||
|| (item.isRegularItem() && item.getAttachments().length);
|
||||
}).length;
|
||||
}
|
||||
}
|
||||
catch (e) {}
|
||||
this.updateMenuItemEnabled('manage-attachments-menu', active);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Builds new item menu
|
||||
*/
|
||||
|
@ -138,6 +155,43 @@ const ZoteroStandalone = new function() {
|
|||
}
|
||||
|
||||
|
||||
this.onManageAttachmentsMenuOpen = function () {
|
||||
// Convert Linked Files to Stored Files
|
||||
var active = false;
|
||||
try {
|
||||
let zp = Zotero.getActiveZoteroPane();
|
||||
if (zp) {
|
||||
active = !!zp.getSelectedItems().filter((item) => {
|
||||
return item.isLinkedFileAttachment()
|
||||
|| (item.isRegularItem()
|
||||
&& item.getAttachments()
|
||||
.map(id => Zotero.Items.get(id))
|
||||
.some(att => att.isLinkedFileAttachment()));
|
||||
}).length;
|
||||
}
|
||||
}
|
||||
catch (e) {}
|
||||
this.updateMenuItemEnabled('file-menuitem-convert-to-stored', active);
|
||||
};
|
||||
|
||||
|
||||
this.onManageAttachmentsMenuItemClick = function (event) {
|
||||
var menuitem = event.originalTarget;
|
||||
var id = menuitem.id;
|
||||
var prefix = 'file-menuitem-';
|
||||
if (menuitem.disabled || !id.startsWith(prefix)) {
|
||||
return;
|
||||
}
|
||||
id = id.substr(prefix.length);
|
||||
|
||||
switch (id) {
|
||||
case 'convert-to-stored':
|
||||
ZoteroPane.convertLinkedFilesToStoredFiles();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.updateQuickCopyOptions = function () {
|
||||
var selected = false;
|
||||
try {
|
||||
|
@ -181,28 +235,28 @@ const ZoteroStandalone = new function() {
|
|||
this.onViewMenuOpen = function () {
|
||||
// Layout mode
|
||||
var mode = Zotero.Prefs.get('layout');
|
||||
this.updateMenuItemCheckmark('standard', mode != 'stacked');
|
||||
this.updateMenuItemCheckmark('stacked', mode == 'stacked');
|
||||
this.updateMenuItemCheckmark('view-menuitem-standard', mode != 'stacked');
|
||||
this.updateMenuItemCheckmark('view-menuitem-stacked', mode == 'stacked');
|
||||
|
||||
// Panes
|
||||
this.updateMenuItemCheckmark(
|
||||
'collections-pane',
|
||||
'view-menuitem-collections-pane',
|
||||
document.getElementById('zotero-collections-pane').getAttribute('collapsed') != 'true'
|
||||
);
|
||||
this.updateMenuItemCheckmark(
|
||||
'item-pane',
|
||||
'view-menuitem-item-pane',
|
||||
document.getElementById('zotero-item-pane').getAttribute('collapsed') != 'true'
|
||||
);
|
||||
this.updateMenuItemCheckmark(
|
||||
'tag-selector',
|
||||
'view-menuitem-tag-selector',
|
||||
document.getElementById('zotero-tag-selector-container').getAttribute('collapsed') != 'true'
|
||||
);
|
||||
|
||||
// Font size
|
||||
var fontSize = Zotero.Prefs.get('fontSize');
|
||||
this.updateMenuItemDisabled('font-size-bigger', fontSize >= FONT_SIZES[FONT_SIZES.length - 1]);
|
||||
this.updateMenuItemDisabled('font-size-smaller', fontSize <= FONT_SIZES[0]);
|
||||
this.updateMenuItemDisabled('font-size-reset', fontSize == FONT_SIZES[0]);
|
||||
this.updateMenuItemEnabled('view-menuitem-font-size-bigger', fontSize < FONT_SIZES[FONT_SIZES.length - 1]);
|
||||
this.updateMenuItemEnabled('view-menuitem-font-size-smaller', fontSize > FONT_SIZES[0]);
|
||||
this.updateMenuItemEnabled('view-menuitem-font-size-reset', fontSize != FONT_SIZES[0]);
|
||||
|
||||
var noteFontSize = Zotero.Prefs.get('note.fontSize');
|
||||
for (let menuitem of document.querySelectorAll(`#note-font-size-menu menuitem`)) {
|
||||
|
@ -213,46 +267,27 @@ const ZoteroStandalone = new function() {
|
|||
menuitem.removeAttribute('checked');
|
||||
}
|
||||
}
|
||||
this.updateMenuItemDisabled('note-font-size-reset', noteFontSize == NOTE_FONT_SIZE_DEFAULT);
|
||||
this.updateMenuItemEnabled(
|
||||
'view-menuitem-note-font-size-reset',
|
||||
noteFontSize != NOTE_FONT_SIZE_DEFAULT
|
||||
);
|
||||
|
||||
// Recursive collections
|
||||
this.updateMenuItemCheckmark('recursive-collections', Zotero.Prefs.get('recursiveCollections'));
|
||||
this.updateMenuItemCheckmark(
|
||||
'view-menuitem-recursive-collections',
|
||||
Zotero.Prefs.get('recursiveCollections')
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
this.updateMenuItemCheckmark = function (idSuffix, checked) {
|
||||
var id = 'view-menuitem-' + idSuffix;
|
||||
var menuitem = document.getElementById(id);
|
||||
if (checked) {
|
||||
menuitem.setAttribute('checked', true);
|
||||
}
|
||||
else {
|
||||
menuitem.removeAttribute('checked');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.updateMenuItemDisabled = function (idSuffix, disabled) {
|
||||
var id = 'view-menuitem-' + idSuffix;
|
||||
var menuitem = document.getElementById(id);
|
||||
if (disabled) {
|
||||
menuitem.setAttribute('disabled', true);
|
||||
}
|
||||
else {
|
||||
menuitem.removeAttribute('disabled');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.updateViewOption = function (event) {
|
||||
this.onViewMenuItemClick = function (event) {
|
||||
var menuitem = event.originalTarget;
|
||||
var id = menuitem.id;
|
||||
|
||||
if (menuitem.disabled || !id.startsWith('view-menuitem-')) {
|
||||
var prefix = 'view-menuitem-';
|
||||
if (menuitem.disabled || !id.startsWith(prefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
id = id.substr(14);
|
||||
id = id.substr(prefix.length);
|
||||
|
||||
switch (id) {
|
||||
case 'standard':
|
||||
|
@ -328,6 +363,28 @@ const ZoteroStandalone = new function() {
|
|||
};
|
||||
|
||||
|
||||
this.updateMenuItemCheckmark = function (id, checked) {
|
||||
var menuitem = document.getElementById(id);
|
||||
if (checked) {
|
||||
menuitem.setAttribute('checked', true);
|
||||
}
|
||||
else {
|
||||
menuitem.removeAttribute('checked');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.updateMenuItemEnabled = function (id, enabled) {
|
||||
var menuitem = document.getElementById(id);
|
||||
if (enabled) {
|
||||
menuitem.removeAttribute('disabled');
|
||||
}
|
||||
else {
|
||||
menuitem.setAttribute('disabled', true);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.toggleBooleanPref = function (pref) {
|
||||
Zotero.Prefs.set(pref, !Zotero.Prefs.get(pref));
|
||||
};
|
||||
|
|
|
@ -120,7 +120,8 @@
|
|||
<toolbaritem id="menubar-items" align="center">
|
||||
<menubar id="main-menubar"
|
||||
style="border:0px;padding:0px;margin:0px;-moz-appearance:none">
|
||||
<menu id="fileMenu" label="&fileMenu.label;" accesskey="&fileMenu.accesskey;">
|
||||
<menu id="fileMenu" label="&fileMenu.label;" accesskey="&fileMenu.accesskey;"
|
||||
onpopupshowing="ZoteroStandalone.onFileMenuOpen()">
|
||||
<menupopup id="menu_FilePopup">
|
||||
<menu id="menu_newItem" label="&zotero.toolbar.newItem.label;">
|
||||
<menupopup id="menu_NewItemPopup"
|
||||
|
@ -134,6 +135,16 @@
|
|||
<menuitem id="menu_close" label="&closeCmd.label;" key="key_close"
|
||||
accesskey="&closeCmd.accesskey;" command="cmd_close"/>
|
||||
<menuseparator/>
|
||||
<menu id="manage-attachments-menu" label="&manageAttachments.label;"
|
||||
onpopupshowing="ZoteroStandalone.onManageAttachmentsMenuOpen()"
|
||||
oncommand="ZoteroStandalone.onManageAttachmentsMenuItemClick(event)">
|
||||
<menupopup id="manage-attachments-menupopup">
|
||||
<menuitem
|
||||
id="file-menuitem-convert-to-stored"
|
||||
label="&convertToStored.label;"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
<menuseparator/>
|
||||
<menuitem id="menu_import" label="&importCmd.label;"
|
||||
command="cmd_zotero_import" key="key_import"/>
|
||||
<menuitem id="menu_importFromClipboard" label="&importFromClipboardCmd.label;"
|
||||
|
@ -190,7 +201,7 @@
|
|||
<menupopup id="menu_viewPopup">
|
||||
<menu id="layout-menu"
|
||||
label="&layout.label;">
|
||||
<menupopup oncommand="ZoteroStandalone.updateViewOption(event)">
|
||||
<menupopup oncommand="ZoteroStandalone.onViewMenuItemClick(event)">
|
||||
<menuitem id="view-menuitem-standard" label="&standardView.label;"/>
|
||||
<menuitem id="view-menuitem-stacked" label="&stackedView.label;"/>
|
||||
<menuseparator/>
|
||||
|
@ -201,7 +212,7 @@
|
|||
</menu>
|
||||
<menu id="font-size-menu"
|
||||
label="&fontSize.label;">
|
||||
<menupopup oncommand="ZoteroStandalone.updateViewOption(event)">
|
||||
<menupopup oncommand="ZoteroStandalone.onViewMenuItemClick(event)">
|
||||
<menuitem id="view-menuitem-font-size-bigger" label="&zotero.general.bigger;"/>
|
||||
<menuitem id="view-menuitem-font-size-smaller" label="&zotero.general.smaller;"/>
|
||||
<menuseparator/>
|
||||
|
@ -211,7 +222,7 @@
|
|||
<menu id="note-font-size-menu"
|
||||
label="¬eFontSize.label;">
|
||||
<!-- TODO: Maybe switch to Bigger/Smaller once we can update without restarting -->
|
||||
<!--<menupopup oncommand="ZoteroStandalone.updateViewOption(event)">
|
||||
<!--<menupopup oncommand="ZoteroStandalone.onViewMenuItemClick(event)">
|
||||
<menuitem id="view-menuitem-note-font-size-bigger" label="&zotero.general.bigger;"/>
|
||||
<menuitem id="view-menuitem-note-font-size-smaller" label="&zotero.general.smaller;"/>
|
||||
<menuseparator/>
|
||||
|
@ -232,13 +243,13 @@
|
|||
<menuitem
|
||||
id="view-menuitem-note-font-size-reset"
|
||||
label="&zotero.general.reset;"
|
||||
oncommand="ZoteroStandalone.updateViewOption(event); event.stopPropagation();"/>
|
||||
oncommand="ZoteroStandalone.onViewMenuItemClick(event); event.stopPropagation();"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
<menuseparator/>
|
||||
<menuitem id="view-menuitem-recursive-collections"
|
||||
label="&recursiveCollections.label;"
|
||||
oncommand="ZoteroStandalone.updateViewOption(event)"/>
|
||||
oncommand="ZoteroStandalone.onViewMenuItemClick(event)"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
|
||||
|
|
|
@ -2343,6 +2343,88 @@ Zotero.Attachments = new function(){
|
|||
});
|
||||
|
||||
|
||||
this.convertLinkedFileToStoredFile = async function (item, options = {}) {
|
||||
if (item.attachmentLinkMode != Zotero.Attachments.LINK_MODE_LINKED_FILE) {
|
||||
throw new Error("Not a linked-file attachment");
|
||||
}
|
||||
|
||||
var file = await item.getFilePathAsync();
|
||||
if (!file) {
|
||||
Zotero.debug("Linked file not found at " + file);
|
||||
return false;
|
||||
}
|
||||
|
||||
var json = item.toJSON();
|
||||
json.linkMode = 'imported_file';
|
||||
delete json.path;
|
||||
json.filename = OS.Path.basename(file);
|
||||
var newItem = new Zotero.Item('attachment');
|
||||
newItem.libraryID = item.libraryID;
|
||||
newItem.fromJSON(json);
|
||||
await newItem.saveTx();
|
||||
|
||||
await Zotero.Relations.copyObjectSubjectRelations(item, newItem);
|
||||
|
||||
var newFile;
|
||||
try {
|
||||
// Transfer file
|
||||
let destDir = await this.createDirectoryForItem(newItem);
|
||||
newFile = OS.Path.join(destDir, json.filename);
|
||||
if (options.move) {
|
||||
newFile = await Zotero.File.moveToUnique(file, newFile);
|
||||
}
|
||||
// Copy file to unique filename, which automatically shortens long filenames
|
||||
else {
|
||||
newFile = Zotero.File.copyToUnique(file, newFile);
|
||||
// TEMP: copyToUnique returns an nsIFile
|
||||
newFile = newFile.path;
|
||||
await Zotero.File.setNormalFilePermissions(newFile);
|
||||
let mtime = (await OS.File.stat(file)).lastModificationDate;
|
||||
await OS.File.setDates(newFile, null, mtime);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
// Delete new file
|
||||
if (newFile) {
|
||||
try {
|
||||
await Zotero.File.removeIfExists(newFile);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
}
|
||||
// Delete new item
|
||||
try {
|
||||
await newItem.eraseTx();
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await Zotero.DB.executeTransaction(async function () {
|
||||
await Zotero.Fulltext.transferItemIndex(item, newItem);
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
|
||||
if (newFile && json.filename != OS.Path.basename(newFile)) {
|
||||
Zotero.debug("Filename was changed");
|
||||
newItem.attachmentFilename = OS.Path.basename(newFile);
|
||||
await newItem.saveTx();
|
||||
}
|
||||
|
||||
await item.eraseTx();
|
||||
|
||||
return newItem;
|
||||
};
|
||||
|
||||
|
||||
this._getFileNameFromURL = function(url, contentType) {
|
||||
var nsIURL = Components.classes["@mozilla.org/network/standard-url;1"]
|
||||
.createInstance(Components.interfaces.nsIURL);
|
||||
|
|
|
@ -2106,7 +2106,7 @@ Zotero.Item.prototype.isWebAttachment = function() {
|
|||
|
||||
|
||||
/**
|
||||
* @return {Promise<Boolean>}
|
||||
* @return {Boolean}
|
||||
*/
|
||||
Zotero.Item.prototype.isFileAttachment = function() {
|
||||
if (!this.isAttachment()) {
|
||||
|
@ -2116,6 +2116,14 @@ Zotero.Item.prototype.isFileAttachment = function() {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {Boolean}
|
||||
*/
|
||||
Zotero.Item.prototype.isLinkedFileAttachment = function() {
|
||||
return this.isAttachment() && this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns number of child attachments of item
|
||||
*
|
||||
|
|
|
@ -169,6 +169,35 @@ Zotero.Relations = new function () {
|
|||
});
|
||||
|
||||
|
||||
/**
|
||||
* For every relation pointing to a given object, create a relation on the subject pointing to a
|
||||
* new object
|
||||
*
|
||||
* @param {Zotero.DataObject} fromObject
|
||||
* @param {Zotero.DataObject} toObject
|
||||
* @return {Promise}
|
||||
*/
|
||||
this.copyObjectSubjectRelations = async function (fromObject, toObject) {
|
||||
var objectType = fromObject.objectType;
|
||||
var ObjectType = Zotero.Utilities.capitalize(objectType);
|
||||
var fromObjectURI = Zotero.URI[`get${ObjectType}URI`](fromObject);
|
||||
var toObjectURI = Zotero.URI[`get${ObjectType}URI`](toObject);
|
||||
var subjectPredicates = await Zotero.Relations.getByObject(objectType, fromObjectURI);
|
||||
for (let { subject, predicate } of subjectPredicates) {
|
||||
if (subject.isEditable()) {
|
||||
subject.addRelation(predicate, toObjectURI);
|
||||
await subject.saveTx({
|
||||
skipDateModifiedUpdate: true
|
||||
});
|
||||
}
|
||||
else {
|
||||
Zotero.debug(`Subject ${objectType} ${subject.libraryKey} is not editable `
|
||||
+ `-- not copying ${predicate} relation`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.updateUser = Zotero.Promise.coroutine(function* (fromUserID, toUserID) {
|
||||
if (!fromUserID) {
|
||||
fromUserID = "local/" + Zotero.Users.getLocalUserKey();
|
||||
|
|
|
@ -1141,6 +1141,39 @@ Zotero.Fulltext = Zotero.FullText = new function(){
|
|||
});
|
||||
|
||||
|
||||
this.transferItemIndex = async function (fromItem, toItem) {
|
||||
await this.clearItemWords(toItem.id);
|
||||
|
||||
// Copy cache file if it exists
|
||||
var cacheFile = this.getItemCacheFile(fromItem).path;
|
||||
if (await OS.File.exists(cacheFile)) {
|
||||
try {
|
||||
await OS.File.move(cacheFile, this.getItemCacheFile(toItem).path);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Update database with new item id
|
||||
await Zotero.DB.queryAsync("PRAGMA foreign_keys = false");
|
||||
try {
|
||||
await Zotero.DB.queryAsync(
|
||||
"UPDATE fulltextItems SET itemID=? WHERE itemID=?",
|
||||
[toItem.id, fromItem.id]
|
||||
);
|
||||
await Zotero.DB.queryAsync(
|
||||
"UPDATE fulltextItemWords SET itemID=? WHERE itemID=?",
|
||||
[toItem.id, fromItem.id]
|
||||
);
|
||||
}
|
||||
catch (e) {
|
||||
await Zotero.DB.queryAsync("PRAGMA foreign_keys = true");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @requireTransaction
|
||||
*/
|
||||
|
|
|
@ -2748,7 +2748,7 @@ var ZoteroPane = new function()
|
|||
'reportMetadata',
|
||||
'createParent',
|
||||
'renameAttachments',
|
||||
'reindexItem'
|
||||
'reindexItem',
|
||||
];
|
||||
|
||||
var m = {};
|
||||
|
@ -2881,20 +2881,19 @@ var ZoteroPane = new function()
|
|||
show.push(m.sep5);
|
||||
}
|
||||
|
||||
// Block certain actions on files if no access and at least one item
|
||||
// is an imported attachment
|
||||
// Block certain actions on files if no access and at least one item is a file
|
||||
// attachment
|
||||
if (!collectionTreeRow.filesEditable) {
|
||||
var hasImportedAttachment = false;
|
||||
for (var i=0; i<items.length; i++) {
|
||||
var item = items[i];
|
||||
if (item.isImportedAttachment()) {
|
||||
hasImportedAttachment = true;
|
||||
for (let item of items) {
|
||||
if (item.isFileAttachment()) {
|
||||
disable.push(
|
||||
m.moveToTrash,
|
||||
m.createParent,
|
||||
m.renameAttachments
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasImportedAttachment) {
|
||||
disable.push(m.moveToTrash, m.createParent, m.renameAttachments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2971,10 +2970,11 @@ var ZoteroPane = new function()
|
|||
this.updateAttachmentButtonMenu(popup);
|
||||
|
||||
// Block certain actions on files if no access
|
||||
if (item.isImportedAttachment() && !collectionTreeRow.filesEditable) {
|
||||
[m.moveToTrash, m.createParent, m.renameAttachments].forEach(function (x) {
|
||||
disable.push(x);
|
||||
});
|
||||
if (item.isFileAttachment() && !collectionTreeRow.filesEditable) {
|
||||
[m.moveToTrash, m.createParent, m.renameAttachments]
|
||||
.forEach(function (x) {
|
||||
disable.push(x);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4580,6 +4580,69 @@ var ZoteroPane = new function()
|
|||
});
|
||||
|
||||
|
||||
this.convertLinkedFilesToStoredFiles = async function () {
|
||||
if (!this.canEdit() || !this.canEditFiles()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
var items = this.getSelectedItems();
|
||||
var attachments = new Set();
|
||||
for (let item of items) {
|
||||
// Add all child link attachments of regular items
|
||||
if (item.isRegularItem()) {
|
||||
for (let id of item.getAttachments()) {
|
||||
let attachment = await Zotero.Items.getAsync(id);
|
||||
if (attachment.isLinkedFileAttachment()) {
|
||||
attachments.add(attachment);
|
||||
}
|
||||
}
|
||||
}
|
||||
// And all selected link attachments
|
||||
else if (item.isLinkedFileAttachment()) {
|
||||
attachments.add(item);
|
||||
}
|
||||
}
|
||||
var num = attachments.size;
|
||||
|
||||
var ps = Services.prompt;
|
||||
var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING
|
||||
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL;
|
||||
var deleteOriginal = {};
|
||||
var index = ps.confirmEx(null,
|
||||
Zotero.getString('attachment.convertToStored.title', [num], num),
|
||||
Zotero.getString('attachment.convertToStored.text', [num], num),
|
||||
buttonFlags,
|
||||
Zotero.getString('general.continue'),
|
||||
null,
|
||||
null,
|
||||
Zotero.getString('attachment.convertToStored.deleteOriginal', [num], num),
|
||||
deleteOriginal
|
||||
);
|
||||
if (index != 0) {
|
||||
return;
|
||||
}
|
||||
for (let item of attachments) {
|
||||
try {
|
||||
let converted = await Zotero.Attachments.convertLinkedFileToStoredFile(
|
||||
item,
|
||||
{
|
||||
move: deleteOriginal.value
|
||||
}
|
||||
);
|
||||
if (!converted) {
|
||||
// Not found
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.relinkAttachment = Zotero.Promise.coroutine(function* (itemID) {
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
<menuitem class="menuitem-iconic zotero-menuitem-report-metadata" label="&zotero.items.menu.reportMetadata;" oncommand="ZoteroPane.reportMetadataForSelected()"/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-create-parent" oncommand="ZoteroPane_Local.createParentItemsFromSelected();"/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-rename-from-parent" oncommand="ZoteroPane_Local.renameSelectedAttachmentsFromParents()"/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-convert-linked-to-stored" oncommand="ZoteroPane.convertLinkedFilesToStoredFiles()"/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-reindex" oncommand="ZoteroPane_Local.reindexItem();"/>
|
||||
</menupopup>
|
||||
</popupset>
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
<!ENTITY closeCmd.label "Close">
|
||||
<!ENTITY closeCmd.key "W">
|
||||
<!ENTITY closeCmd.accesskey "C">
|
||||
<!ENTITY manageAttachments.label "Manage Attachments">
|
||||
<!ENTITY convertToStored.label "Convert Linked Files to Stored Files…">
|
||||
<!ENTITY importCmd.label "Import…">
|
||||
<!ENTITY importCmd.key "I">
|
||||
<!ENTITY importFromClipboardCmd.label "Import from Clipboard">
|
||||
|
|
|
@ -613,6 +613,9 @@ findPDF.noPDFFound = No PDF found
|
|||
attachment.fullText = Full Text
|
||||
attachment.acceptedVersion = Accepted Version
|
||||
attachment.submittedVersion = Submitted Version
|
||||
attachment.convertToStored.title = Convert to Stored File;Convert to Stored Files
|
||||
attachment.convertToStored.text = %1$S attachment will be converted from a linked file to a stored file.;%1$S attachments will be converted from linked files to stored files.
|
||||
attachment.convertToStored.deleteOriginal = Delete original file after storing;Delete original files after storing
|
||||
|
||||
db.dbCorrupted = The Zotero database '%S' appears to have become corrupted.
|
||||
db.dbCorrupted.restart = Please restart %S to attempt an automatic restore from the last backup.
|
||||
|
|
|
@ -1074,4 +1074,71 @@ describe("Zotero.Attachments", function() {
|
|||
assert.isTrue(yield OS.File.exists(dir));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#convertLinkedFileToStoredFile()", function () {
|
||||
it("should copy a linked file to a stored file", async function () {
|
||||
var item = await createDataObject('item');
|
||||
var relatedItem = await createDataObject('item');
|
||||
|
||||
var originalFile = OS.Path.join(getTestDataDirectory().path, 'test.pdf');
|
||||
var attachment = await Zotero.Attachments.linkFromFile({
|
||||
file: originalFile,
|
||||
title: 'Title',
|
||||
parentItemID: item.id
|
||||
});
|
||||
attachment.setNote('Note');
|
||||
attachment.setTags([{ tag: 'Tag' }]);
|
||||
attachment.addRelatedItem(relatedItem);
|
||||
await attachment.saveTx();
|
||||
relatedItem.addRelatedItem(attachment);
|
||||
await relatedItem.saveTx();
|
||||
// Make sure we're indexed
|
||||
await Zotero.Fulltext.indexItems([attachment.id]);
|
||||
|
||||
var newAttachment = await Zotero.Attachments.convertLinkedFileToStoredFile(attachment);
|
||||
|
||||
assert.isFalse(Zotero.Items.exists(attachment.id));
|
||||
assert.isTrue(await OS.File.exists(originalFile));
|
||||
assert.equal(newAttachment.attachmentLinkMode, Zotero.Attachments.LINK_MODE_IMPORTED_FILE);
|
||||
assert.equal(newAttachment.attachmentContentType, 'application/pdf');
|
||||
assert.isTrue(await newAttachment.fileExists());
|
||||
assert.equal(newAttachment.getField('title'), 'Title');
|
||||
assert.equal(newAttachment.getNote(), 'Note');
|
||||
assert.sameDeepMembers(newAttachment.getTags(), [{ tag: 'Tag' }]);
|
||||
assert.sameMembers(newAttachment.relatedItems, [relatedItem.key]);
|
||||
assert.sameMembers(relatedItem.relatedItems, [newAttachment.key]);
|
||||
assert.isTrue(await OS.File.exists(Zotero.Fulltext.getItemCacheFile(newAttachment).path));
|
||||
assert.equal(
|
||||
await Zotero.Fulltext.getIndexedState(newAttachment),
|
||||
Zotero.Fulltext.INDEX_STATE_INDEXED
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it("should move a linked file to a stored file with `move: true`", async function () {
|
||||
var item = await createDataObject('item');
|
||||
|
||||
var originalFile = OS.Path.join(Zotero.getTempDirectory().path, 'test.png');
|
||||
await OS.File.copy(
|
||||
OS.Path.join(getTestDataDirectory().path, 'test.png'),
|
||||
originalFile
|
||||
);
|
||||
var attachment = await Zotero.Attachments.linkFromFile({
|
||||
file: originalFile,
|
||||
parentItemID: item.id
|
||||
});
|
||||
|
||||
var newAttachment = await Zotero.Attachments.convertLinkedFileToStoredFile(
|
||||
attachment,
|
||||
{
|
||||
move: true
|
||||
}
|
||||
);
|
||||
|
||||
assert.isFalse(Zotero.Items.exists(attachment.id));
|
||||
assert.isFalse(await OS.File.exists(originalFile));
|
||||
assert.equal(newAttachment.attachmentLinkMode, Zotero.Attachments.LINK_MODE_IMPORTED_FILE);
|
||||
assert.isTrue(await newAttachment.fileExists());
|
||||
});
|
||||
});
|
||||
})
|
||||
|
|
Loading…
Add table
Reference in a new issue