Relative path support for linked files
This commit is contained in:
parent
d4771c5f0d
commit
b224c5cf66
|
@ -129,6 +129,160 @@ function init()
|
|||
}
|
||||
}
|
||||
|
||||
function chooseBaseAttachmentPath() {
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow('navigator:browser');
|
||||
|
||||
//Prompt user to choose new base path
|
||||
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(win, Zotero.getString('attachmentBasePath.selectDir'), nsIFilePicker.modeGetFolder);
|
||||
fp.appendFilters(nsIFilePicker.filterAll);
|
||||
if (fp.show() != nsIFilePicker.returnOK) {
|
||||
return false;
|
||||
}
|
||||
var basePathFile = fp.file;
|
||||
|
||||
//Find all current attachments with relative attachment paths
|
||||
var sql = "SELECT itemID FROM itemAttachments WHERE linkMode=? AND path LIKE '" +
|
||||
Zotero.Attachments.BASE_PATH_PLACEHOLDER + "%'";
|
||||
var params=[Zotero.Attachments.LINK_MODE_LINKED_FILE];
|
||||
var oldRelativeAttachmentIDs = Zotero.DB.columnQuery(sql,params);
|
||||
if (!oldRelativeAttachmentIDs) {
|
||||
oldRelativeAttachmentIDs=[];
|
||||
}
|
||||
|
||||
//Find all attachments on the new base path
|
||||
var sql = "SELECT itemID FROM itemAttachments WHERE linkMode=?";
|
||||
var params=[Zotero.Attachments.LINK_MODE_LINKED_FILE];
|
||||
var allAttachments = Zotero.DB.columnQuery(sql,params);
|
||||
var newRelativeAttachmentIDs = [];
|
||||
var attachmentFile = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
var tempAttachmentID,tempAttachment;
|
||||
for (var index=0; index<allAttachments.length; index++) {
|
||||
tempAttachmentID=allAttachments[index];
|
||||
|
||||
//Don't count current relative attachment paths.
|
||||
if (oldRelativeAttachmentIDs.indexOf(tempAttachmentID)!=-1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
tempAttachment=Zotero.Items.get(tempAttachmentID);
|
||||
attachmentFile.initWithPath(tempAttachment.attachmentPath);
|
||||
}
|
||||
catch (e) {
|
||||
//Don't deal with bad attachment paths. Just skip them.
|
||||
continue;
|
||||
}
|
||||
if (basePathFile.contains(attachmentFile,false)) {
|
||||
newRelativeAttachmentIDs.push(allAttachments[index]);
|
||||
}
|
||||
}
|
||||
|
||||
//Confirm change of the base path
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
|
||||
var confirmTitle=Zotero.getString('attachmentBasePath.confirmNewPath.title');
|
||||
var confirmString;
|
||||
switch (newRelativeAttachmentIDs.length) {
|
||||
case 0:
|
||||
confirmString=Zotero.getString('attachmentBasePath.confirmNewPath.none');
|
||||
break;
|
||||
case 1:
|
||||
confirmString=Zotero.getString('attachmentBasePath.confirmNewPath.singular');
|
||||
break;
|
||||
default:
|
||||
confirmString=Zotero.getString('attachmentBasePath.confirmNewPath.plural',
|
||||
newRelativeAttachmentIDs.length);
|
||||
}
|
||||
if (!ps.confirm(null,confirmTitle,confirmString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set new data directory
|
||||
Zotero.Prefs.set('baseAttachmentPath', basePathFile.persistentDescriptor);
|
||||
Zotero.Prefs.set('lastDataDir', basePathFile.path);
|
||||
Zotero.Prefs.set('saveRelativeAttachmentPath', true);
|
||||
//Save all attachments on base path so that their paths become relative
|
||||
var tempAttachment;
|
||||
for (var index=0; index<newRelativeAttachmentIDs.length; index++) {
|
||||
tempAttachment=Zotero.Items.get(newRelativeAttachmentIDs[index]);
|
||||
if (!tempAttachment._changedAttachmentData) {
|
||||
tempAttachment._changedAttachmentData = {};
|
||||
}
|
||||
tempAttachment._changedAttachmentData.path = true;
|
||||
tempAttachment.save();
|
||||
}
|
||||
|
||||
return basePathFile.path;
|
||||
}
|
||||
|
||||
function getBaseAttachmentPath() {
|
||||
var desc = Zotero.Prefs.get('baseAttachmentPath');
|
||||
if (desc == '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
var file = Components.classes["@mozilla.org/file/local;1"].
|
||||
createInstance(Components.interfaces.nsILocalFile);
|
||||
try {
|
||||
file.persistentDescriptor = desc;
|
||||
}
|
||||
catch (e) {
|
||||
return '';
|
||||
}
|
||||
return file.path;
|
||||
}
|
||||
|
||||
function clearBaseAttachmentPath() {
|
||||
//Find all current attachments with relative attachment paths
|
||||
var sql = "SELECT itemID FROM itemAttachments WHERE linkMode=? AND path LIKE '" +
|
||||
Zotero.Attachments.BASE_PATH_PLACEHOLDER + "%'";
|
||||
var params=[Zotero.Attachments.LINK_MODE_LINKED_FILE];
|
||||
var relativeAttachmentIDs = Zotero.DB.columnQuery(sql,params);
|
||||
|
||||
//Confirm the clearing of the base path and restoring of relative paths to absolute
|
||||
//ones with the user.
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
|
||||
var confirmTitle=Zotero.getString('attachmentBasePath.clearBasePath.title');
|
||||
var confirmString;
|
||||
switch (relativeAttachmentIDs.length) {
|
||||
case 0:
|
||||
confirmString=Zotero.getString('attachmentBasePath.clearBasePath.none');
|
||||
break;
|
||||
case 1:
|
||||
confirmString=Zotero.getString('attachmentBasePath.clearBasePath.singular');
|
||||
break;
|
||||
default:
|
||||
confirmString=Zotero.getString('attachmentBasePath.clearBasePath.plural',
|
||||
relativeAttachmentIDs.length);
|
||||
}
|
||||
if (!ps.confirm(null,confirmTitle,confirmString)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Set saveRelativeAttachmentPath preference to false and then resave all relative
|
||||
//attachments so that their absolute paths are stored.
|
||||
Zotero.Prefs.set('saveRelativeAttachmentPath', false);
|
||||
var tempAttachment;
|
||||
for (var index=0; index<relativeAttachmentIDs.length; index++) {
|
||||
tempAttachment=Zotero.Items.get(relativeAttachmentIDs[index]);
|
||||
if (!tempAttachment._changedAttachmentData) {
|
||||
tempAttachment._changedAttachmentData = {};
|
||||
}
|
||||
tempAttachment._changedAttachmentData.path = true;
|
||||
tempAttachment.save();
|
||||
}
|
||||
|
||||
Zotero.Prefs.set('baseAttachmentPath', '');
|
||||
}
|
||||
|
||||
function onDataDirLoad() {
|
||||
var path = document.getElementById('dataDirPath');
|
||||
|
|
|
@ -716,6 +716,7 @@ To add a new preference:
|
|||
image="chrome://zotero/skin/prefs-advanced.png"
|
||||
helpTopic="advanced">
|
||||
<preferences>
|
||||
<preference id="pref-baseAttachmentPath" name="extensions.zotero.baseAttachmentPath" type="string"/>
|
||||
<preference id="pref-useDataDir" name="extensions.zotero.useDataDir" type="bool"/>
|
||||
<preference id="pref-dataDir" name="extensions.zotero.dataDir" type="string"/>
|
||||
<preference id="pref-export-displayCharsetOption" name="extensions.zotero.export.displayCharsetOption" type="bool"/>
|
||||
|
@ -725,6 +726,26 @@ To add a new preference:
|
|||
<preference id="pref-openURL-version" name="extensions.zotero.openURL.version" type="string"/>
|
||||
</preferences>
|
||||
|
||||
<groupbox>
|
||||
<caption label="&zotero.preferences.attachments;"/>
|
||||
|
||||
<!-- This doesn't wrap without an explicit width -->
|
||||
<vbox>
|
||||
<description width="45em">&zotero.preferences.attachments.message;</description>
|
||||
</vbox>
|
||||
|
||||
<hbox>
|
||||
<label value="&zotero.preferences.attachments.basePath;"/>
|
||||
<textbox id="baseAttachmentPath" preference="pref-baseAttachmentPath" onsyncfrompreference="return getBaseAttachmentPath();" readonly="true" flex="1"/>
|
||||
<button label="&zotero.preferences.attachments.selectBasePath;" oncommand="var file = chooseBaseAttachmentPath(); if (!file) { event.stopPropagation(); }"/>
|
||||
</hbox>
|
||||
|
||||
<hbox>
|
||||
<button label="&zotero.preferences.attachments.resetBasePath;" oncommand="clearBaseAttachmentPath();"/>
|
||||
</hbox>
|
||||
|
||||
</groupbox>
|
||||
|
||||
<groupbox>
|
||||
<caption label="&zotero.preferences.dataDir;"/>
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ Zotero.Attachments = new function(){
|
|||
this.LINK_MODE_IMPORTED_URL = 1;
|
||||
this.LINK_MODE_LINKED_FILE = 2;
|
||||
this.LINK_MODE_LINKED_URL = 3;
|
||||
this.BASE_PATH_PLACEHOLDER = '<BASE_ATTACHMENT_PATH>';
|
||||
|
||||
this.importFromFile = importFromFile;
|
||||
this.linkFromFile = linkFromFile;
|
||||
|
|
|
@ -1522,6 +1522,25 @@ Zotero.Item.prototype.save = function() {
|
|||
var path = this.attachmentPath;
|
||||
var syncState = this.attachmentSyncState;
|
||||
|
||||
//Save attachment in base attachment path as relative path
|
||||
if (this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE) {
|
||||
var basePath = Zotero.Prefs.get('baseAttachmentPath');
|
||||
if (basePath!='' && Zotero.Prefs.get('saveRelativeAttachmentPath')) {
|
||||
var baseDir = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
baseDir.initWithPath(basePath);
|
||||
|
||||
var attachmentFile = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
attachmentFile.initWithPath(path);
|
||||
|
||||
if (baseDir.contains(attachmentFile,false)) {
|
||||
path = Zotero.Attachments.BASE_PATH_PLACEHOLDER
|
||||
+attachmentFile.getRelativeDescriptor(baseDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var bindParams = [
|
||||
itemID,
|
||||
parent ? parent : null,
|
||||
|
@ -1916,6 +1935,25 @@ Zotero.Item.prototype.save = function() {
|
|||
var path = this.attachmentPath;
|
||||
var syncState = this.attachmentSyncState;
|
||||
|
||||
//Save attachment in base attachment path as relative path
|
||||
if (this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE) {
|
||||
var basePath = Zotero.Prefs.get('baseAttachmentPath');
|
||||
if (basePath!='' && Zotero.Prefs.get('saveRelativeAttachmentPath')) {
|
||||
var baseDir = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
baseDir.initWithPath(basePath);
|
||||
|
||||
var attachmentFile = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
attachmentFile.initWithPath(path);
|
||||
|
||||
if (baseDir.contains(attachmentFile,false)) {
|
||||
path = Zotero.Attachments.BASE_PATH_PLACEHOLDER
|
||||
+attachmentFile.getRelativeDescriptor(baseDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var bindParams = [
|
||||
parent ? parent : null,
|
||||
{ int: linkMode },
|
||||
|
@ -3172,20 +3210,52 @@ Zotero.Item.prototype.__defineGetter__('attachmentPath', function () {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
if (this._attachmentPath !== null) {
|
||||
return this._attachmentPath;
|
||||
}
|
||||
var pathIsRelative = false;
|
||||
|
||||
if (!this.id) {
|
||||
if (this._attachmentPath !== null) {
|
||||
pathIsRelative = (this._attachmentPath.indexOf(Zotero.Attachments.BASE_PATH_PLACEHOLDER)==0);
|
||||
pathIsRelative = (pathIsRelative && this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE);
|
||||
|
||||
|
||||
if (!pathIsRelative) {
|
||||
return this._attachmentPath;
|
||||
}
|
||||
}
|
||||
else if (!this.id) {
|
||||
return '';
|
||||
} else {
|
||||
var sql = "SELECT path FROM itemAttachments WHERE itemID=?";
|
||||
var path = Zotero.DB.valueQuery(sql, this.id);
|
||||
if (!path) {
|
||||
this._attachmentPath = '';
|
||||
return this._attachmentPath;
|
||||
}
|
||||
|
||||
this._attachmentPath = path;
|
||||
|
||||
pathIsRelative = (path.indexOf(Zotero.Attachments.BASE_PATH_PLACEHOLDER)==0);
|
||||
pathIsRelative = (pathIsRelative && this.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE);
|
||||
}
|
||||
|
||||
var sql = "SELECT path FROM itemAttachments WHERE itemID=?";
|
||||
var path = Zotero.DB.valueQuery(sql, this.id);
|
||||
if (!path) {
|
||||
path = '';
|
||||
if (pathIsRelative) {
|
||||
var baseDir = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
var basePath = Zotero.Prefs.get('baseAttachmentPath');
|
||||
if (basePath != '') {
|
||||
baseDir.initWithPath(basePath);
|
||||
} else {
|
||||
//If the base path has been cleared, don't try to recreate the full attachment path
|
||||
return '';
|
||||
}
|
||||
|
||||
var relativePath = this._attachmentPath.substr(
|
||||
Zotero.Attachments.BASE_PATH_PLACEHOLDER.length);
|
||||
var attachmentFile = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
attachmentFile.setRelativeDescriptor(baseDir,relativePath);
|
||||
return attachmentFile.persistentDescriptor;
|
||||
}
|
||||
this._attachmentPath = path;
|
||||
|
||||
return path;
|
||||
});
|
||||
|
||||
|
|
|
@ -177,6 +177,12 @@
|
|||
<!ENTITY zotero.preferences.dataDir.choose "Choose...">
|
||||
<!ENTITY zotero.preferences.dataDir.reveal "Show Data Directory">
|
||||
|
||||
<!ENTITY zotero.preferences.attachments "Attachments">
|
||||
<!ENTITY zotero.preferences.attachments.message "Attached links to files below the base directory will be stored relative to the base directory. This will allow links to remain functional on computers with different locations for the base directory.">
|
||||
<!ENTITY zotero.preferences.attachments.basePath "Base directory:">
|
||||
<!ENTITY zotero.preferences.attachments.selectBasePath "Choose...">
|
||||
<!ENTITY zotero.preferences.attachments.resetBasePath "Revert to absolute paths">
|
||||
|
||||
<!ENTITY zotero.preferences.dbMaintenance "Database Maintenance">
|
||||
<!ENTITY zotero.preferences.dbMaintenance.integrityCheck "Check Database Integrity">
|
||||
<!ENTITY zotero.preferences.dbMaintenance.resetTranslatorsAndStyles "Reset Translators and Styles...">
|
||||
|
|
|
@ -69,6 +69,16 @@ errorReport.stepsToReproduce = Steps to Reproduce:
|
|||
errorReport.expectedResult = Expected result:
|
||||
errorReport.actualResult = Actual result:
|
||||
|
||||
attachmentBasePath.selectDir = Choose base directory for attachments
|
||||
attachmentBasePath.confirmNewPath.title = Confirm new base directory
|
||||
attachmentBasePath.confirmNewPath.none = No attachments were found with an absolute path containing the new base directory. New attachment links below this directory will be saved relative to it.\n\nPress OK to continue or Cancel to keep the current base directory setting.
|
||||
attachmentBasePath.confirmNewPath.singular = Zotero found one attachment with an absolute path containing the new base directory. This attachment will be converted to a relative path. New attachment links below this directory will be saved relative to it.\n\nPress OK to continue or Cancel to keep the current base directory setting.
|
||||
attachmentBasePath.confirmNewPath.plural = Zotero found %S attachments with absolute paths containing the new base directory. These attachments will be converted to relative paths. New attachment links below this directory will be saved relative to it.\n\nPress OK to continue or Cancel to keep the current base directory setting.
|
||||
attachmentBasePath.clearBasePath.title = Revert to absolute paths
|
||||
attachmentBasePath.clearBasePath.none = No existing attachments were found beneath the current base directory. The base directory setting will be cleared and new attachments will be stored using absolute paths.
|
||||
attachmentBasePath.clearBasePath.singular = One relative attachment link will be converted to absolute using the last base directory setting. The base directory setting will be cleared and new attachments will be stored using absolute paths.
|
||||
attachmentBasePath.clearBasePath.plural = %S relative attachment links will be converted to absolute using the last base directory setting. The base directory setting will be cleared and new attachments will be stored using absolute paths.
|
||||
|
||||
dataDir.notFound = The Zotero data directory could not be found.
|
||||
dataDir.previousDir = Previous directory:
|
||||
dataDir.useProfileDir = Use %S profile directory
|
||||
|
@ -794,4 +804,4 @@ connector.standaloneOpen = Your database cannot be accessed because Zotero Sta
|
|||
firstRunGuidance.saveIcon = Zotero has found a reference on this page. Click this icon in the address bar to save the reference to your Zotero library.
|
||||
firstRunGuidance.authorMenu = Zotero lets you specify editors and translators, too. You can turn an author into an editor or translator by selecting from this menu.
|
||||
firstRunGuidance.quickFormat = Type a title or author to search for a reference.\n\nAfter you've made your selection, click the bubble or press Ctrl-\u2193 to add page numbers, prefixes, or suffixes. You can also include a page number along with your search terms to add it directly.\n\nYou can edit citations directly in the word processor document.
|
||||
firstRunGuidance.quickFormatMac = Type a title or author to search for a reference.\n\nAfter you've made your selection, click the bubble or press Cmd-\u2193 to add page numbers, prefixes, or suffixes. You can also include a page number along with your search terms to add it directly.\n\nYou can edit citations directly in the word processor document.
|
||||
firstRunGuidance.quickFormatMac = Type a title or author to search for a reference.\n\nAfter you've made your selection, click the bubble or press Cmd-\u2193 to add page numbers, prefixes, or suffixes. You can also include a page number along with your search terms to add it directly.\n\nYou can edit citations directly in the word processor document.
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
pref("extensions.zotero.firstRun2", true);
|
||||
pref("extensions.zotero@chnm.gmu.edu.description", "chrome://zotero/locale/zotero.properties");
|
||||
|
||||
pref("extensions.zotero.saveRelativeAttachmentPath", false);
|
||||
pref("extensions.zotero.baseAttachmentPath", '');
|
||||
pref("extensions.zotero.useDataDir", false);
|
||||
pref("extensions.zotero.dataDir", '');
|
||||
pref("extensions.zotero.lastDataDir", '');
|
||||
|
|
Loading…
Reference in New Issue
Block a user