zotero/chrome/content/zotero/preferences/preferences_advanced.js
2021-08-21 06:58:12 -04:00

989 lines
30 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
***** BEGIN LICENSE BLOCK *****
Copyright © 20062013 Center for History and New Media
George Mason University, Fairfax, Virginia, USA
http://zotero.org
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
Components.utils.import("resource://gre/modules/Services.jsm");
import FilePicker from 'zotero/modules/filePicker';
Zotero_Preferences.Advanced = {
DEFAULT_OPENURL_RESOLVER: 'https://www.worldcat.org/registry/gateway',
_openURLResolvers: null,
init: function () {
Zotero_Preferences.Keys.init();
// Show Memory Info button
if (Zotero.Prefs.get('debug.memoryInfo')) {
document.getElementById('memory-info').hidden = false;
}
// This might not work for checkboxes if we later need to create them
// with html
var inputs = document.querySelectorAll('input[data-preference]');
for (let input of inputs) {
let preferenceName = input.dataset.preference;
input.addEventListener('change', function () {
let value = input.value;
Zotero.Prefs.set(preferenceName, value);
});
input.value = Zotero.Prefs.get(preferenceName);
}
// Set OpenURL resolver drop-down to last-known name
if (Zotero.Prefs.get('openURL.resolver')) {
let name = Zotero.Prefs.get('openURL.name');
if (name) {
document.getElementById('openurl-primary-popup').firstChild.setAttribute('label', name);
}
}
this.onDataDirLoad();
this.refreshLocale();
},
updateTranslators: Zotero.Promise.coroutine(function* () {
var updated = yield Zotero.Schema.updateFromRepository(Zotero.Schema.REPO_UPDATE_MANUAL);
var button = document.getElementById('updateButton');
if (button) {
if (updated===-1) {
var label = Zotero.getString('zotero.preferences.update.upToDate');
}
else if (updated) {
var label = Zotero.getString('zotero.preferences.update.updated');
}
else {
var label = Zotero.getString('zotero.preferences.update.error');
}
button.setAttribute('label', label);
if (updated && Zotero_Preferences.Cite) {
yield Zotero_Preferences.Cite.refreshStylesList();
}
}
}),
migrateDataDirectory: Zotero.Promise.coroutine(function* () {
var currentDir = Zotero.DataDirectory.dir;
var defaultDir = Zotero.DataDirectory.defaultDir;
if (currentDir == defaultDir) {
Zotero.debug("Already using default directory");
return;
}
Components.utils.import("resource://zotero/config.js")
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
// If there's a migration marker, point data directory back to the current location and remove
// it to trigger the migration again
var marker = OS.Path.join(defaultDir, Zotero.DataDirectory.MIGRATION_MARKER);
if (yield OS.File.exists(marker)) {
Zotero.Prefs.clear('dataDir');
Zotero.Prefs.clear('useDataDir');
yield OS.File.remove(marker);
try {
yield OS.File.remove(OS.Path.join(defaultDir, '.DS_Store'));
}
catch (e) {}
}
// ~/Zotero exists and is non-empty
if ((yield OS.File.exists(defaultDir)) && !(yield Zotero.File.directoryIsEmpty(defaultDir))) {
let buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
let index = ps.confirmEx(
window,
Zotero.getString('general.error'),
Zotero.getString('zotero.preferences.advanced.migrateDataDir.directoryExists1', defaultDir)
+ "\n\n"
+ Zotero.getString('zotero.preferences.advanced.migrateDataDir.directoryExists2'),
buttonFlags,
Zotero.getString('general.showDirectory'),
null, null, null, {}
);
if (index == 0) {
yield Zotero.File.reveal(
// Windows opens the directory, which might be confusing here, so open parent instead
Zotero.isWin ? OS.Path.dirname(defaultDir) : defaultDir
);
}
return;
}
var additionalText = '';
if (Zotero.isWin) {
try {
let numItems = yield Zotero.DB.valueQueryAsync(
"SELECT COUNT(*) FROM itemAttachments WHERE linkMode IN (?, ?)",
[Zotero.Attachments.LINK_MODE_IMPORTED_FILE, Zotero.Attachments.LINK_MODE_IMPORTED_URL]
);
if (numItems > 100) {
additionalText = '\n\n' + Zotero.getString(
'zotero.preferences.advanced.migrateDataDir.manualMigration',
[Zotero.appName, defaultDir, ZOTERO_CONFIG.CLIENT_NAME]
);
}
}
catch (e) {
Zotero.logError(e);
}
}
// Prompt to restart
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
var index = ps.confirmEx(window,
Zotero.getString('zotero.preferences.advanced.migrateDataDir.title'),
Zotero.getString(
'zotero.preferences.advanced.migrateDataDir.directoryWillBeMoved',
[ZOTERO_CONFIG.CLIENT_NAME, defaultDir]
) + '\n\n'
+ Zotero.getString(
'zotero.preferences.advanced.migrateDataDir.appMustBeRestarted', Zotero.appName
) + additionalText,
buttonFlags,
Zotero.getString('general.continue'),
null, null, null, {}
);
if (index == 0) {
yield Zotero.DataDirectory.markForMigration(currentDir);
Zotero.Utilities.Internal.quitZotero(true);
}
}),
runIntegrityCheck: async function (button) {
button.disabled = true;
try {
let ps = Services.prompt;
var ok = await Zotero.DB.integrityCheck();
if (ok) {
ok = await Zotero.Schema.integrityCheck();
if (!ok) {
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
var index = ps.confirmEx(window,
Zotero.getString('general.failed'),
Zotero.getString('db.integrityCheck.failed') + "\n\n" +
Zotero.getString('db.integrityCheck.repairAttempt') + " " +
Zotero.getString('db.integrityCheck.appRestartNeeded', Zotero.appName),
buttonFlags,
Zotero.getString('db.integrityCheck.fixAndRestart', Zotero.appName),
null, null, null, {}
);
if (index == 0) {
// Safety first
await Zotero.DB.backupDatabase();
// Fix the errors
await Zotero.Schema.integrityCheck(true);
// And run the check again
ok = await Zotero.Schema.integrityCheck();
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING);
if (ok) {
var str = 'success';
var msg = Zotero.getString('db.integrityCheck.errorsFixed');
}
else {
var str = 'failed';
var msg = Zotero.getString('db.integrityCheck.errorsNotFixed')
+ "\n\n" + Zotero.getString('db.integrityCheck.reportInForums');
}
ps.confirmEx(window,
Zotero.getString('general.' + str),
msg,
buttonFlags,
Zotero.getString('general.restartApp', Zotero.appName),
null, null, null, {}
);
var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
.getService(Components.interfaces.nsIAppStartup);
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit
| Components.interfaces.nsIAppStartup.eRestart);
}
return;
}
try {
await Zotero.DB.vacuum();
}
catch (e) {
Zotero.logError(e);
ok = false;
}
}
var str = ok ? 'passed' : 'failed';
ps.alert(window,
Zotero.getString('general.' + str),
Zotero.getString('db.integrityCheck.' + str)
+ (!ok ? "\n\n" + Zotero.getString('db.integrityCheck.dbRepairTool') : ''));
}
finally {
button.disabled = false;
}
},
resetTranslatorsAndStyles: function () {
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
var index = ps.confirmEx(null,
Zotero.getString('general.warning'),
Zotero.getString('zotero.preferences.advanced.resetTranslatorsAndStyles.changesLost'),
buttonFlags,
Zotero.getString('zotero.preferences.advanced.resetTranslatorsAndStyles'),
null, null, null, {});
if (index == 0) {
Zotero.Schema.resetTranslatorsAndStyles()
.then(function () {
if (Zotero_Preferences.Export) {
Zotero_Preferences.Export.populateQuickCopyList();
}
});
}
},
resetTranslators: async function () {
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
var index = ps.confirmEx(null,
Zotero.getString('general.warning'),
Zotero.getString('zotero.preferences.advanced.resetTranslators.changesLost'),
buttonFlags,
Zotero.getString('zotero.preferences.advanced.resetTranslators'),
null, null, null, {});
if (index == 0) {
let button = document.getElementById('reset-translators-button');
button.disabled = true;
try {
await Zotero.Schema.resetTranslators();
if (Zotero_Preferences.Export) {
Zotero_Preferences.Export.populateQuickCopyList();
}
}
finally {
button.disabled = false;
}
}
},
resetStyles: async function () {
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
var index = ps.confirmEx(null,
Zotero.getString('general.warning'),
Zotero.getString('zotero.preferences.advanced.resetStyles.changesLost'),
buttonFlags,
Zotero.getString('zotero.preferences.advanced.resetStyles'),
null, null, null, {});
if (index == 0) {
let button = document.getElementById('reset-styles-button');
button.disabled = true;
try {
await Zotero.Schema.resetStyles()
if (Zotero_Preferences.Export) {
Zotero_Preferences.Export.populateQuickCopyList();
}
}
finally {
button.disabled = false;
}
}
},
onDataDirLoad: function () {
var useDataDir = Zotero.Prefs.get('useDataDir');
var dataDir = Zotero.Prefs.get('lastDataDir') || Zotero.Prefs.get('dataDir');
var currentDir = Zotero.DataDirectory.dir;
var defaultDataDir = Zotero.DataDirectory.defaultDir;
if (Zotero.forceDataDir) {
document.getElementById('command-line-data-dir-path').textContent = currentDir;
document.getElementById('command-line-data-dir').hidden = false;
document.getElementById('data-dir').hidden = true;
}
// Change "Use profile directory" label to home directory location unless using profile dir
if (useDataDir || currentDir == defaultDataDir) {
document.getElementById('default-data-dir').setAttribute(
'label', Zotero.getString('dataDir.default', Zotero.DataDirectory.defaultDir)
);
}
// Don't show custom data dir as in-use if set to the default
if (dataDir == defaultDataDir) {
useDataDir = false;
}
document.getElementById('data-dir-path').setAttribute('disabled', !useDataDir);
document.getElementById('migrate-data-dir').setAttribute(
'hidden', !Zotero.DataDirectory.canMigrate()
);
return useDataDir;
},
onDataDirUpdate: Zotero.Promise.coroutine(function* (event, forceNew) {
var radiogroup = document.getElementById('data-dir');
var newUseDataDir = radiogroup.selectedIndex == 1;
if (!forceNew && newUseDataDir && !this._usingDefaultDataDir()) {
return;
}
// This call shows a filepicker if needed, forces a restart if required, and does nothing if
// cancel was pressed or value hasn't changed
yield Zotero.DataDirectory.choose(
true,
!newUseDataDir,
() => Zotero_Preferences.openURL('https://www.zotero.org/support/zotero_data')
);
radiogroup.selectedIndex = this._usingDefaultDataDir() ? 0 : 1;
}),
chooseDataDir: function(event) {
document.getElementById('data-dir').selectedIndex = 1;
this.onDataDirUpdate(event, true);
},
getDataDirPath: function () {
// TEMP: lastDataDir can be removed once old persistent descriptors have been
// converted, which they are in getZoteroDirectory() in 5.0
var prefValue = Zotero.Prefs.get('lastDataDir') || Zotero.Prefs.get('dataDir');
// Don't show path if the default
if (prefValue == Zotero.DataDirectory.defaultDir) {
return '';
}
return prefValue || '';
},
_usingDefaultDataDir: function () {
// Legacy profile directory location
if (!Zotero.Prefs.get('useDataDir')) {
return true;
}
var dataDir = Zotero.Prefs.get('lastDataDir') || Zotero.Prefs.get('dataDir');
// Default home directory location
if (dataDir == Zotero.DataDirectory.defaultDir) {
return true;
}
return false;
},
handleOpenURLPopupShowing: async function (event) {
if (event.target.id != 'openurl-primary-popup') {
return;
}
if (!this._openURLResolvers) {
let menupopup = document.getElementById('openurl-primary-popup');
menupopup.firstChild.setAttribute('label', Zotero.getString('general.loading'));
try {
this._openURLResolvers = await Zotero.Utilities.Internal.OpenURL.getResolvers();
}
catch (e) {
Zotero.logError(e);
menupopup.firstChild.setAttribute('label', "Error loading resolvers");
return;
}
}
this.updateOpenURLResolversMenu();
},
updateOpenURLResolversMenu: function () {
if (!this._openURLResolvers) {
Zotero.debug("Resolvers not loaded -- not updating menu");
return;
}
var currentResolver = Zotero.Prefs.get('openURL.resolver');
var openURLMenu = document.getElementById('openurl-menu');
var menupopup = openURLMenu.firstChild;
menupopup.innerHTML = '';
var defaultMenuItem = document.createElement('menuitem');
defaultMenuItem.setAttribute('label', Zotero.getString('general.default'));
defaultMenuItem.setAttribute('value', this.DEFAULT_OPENURL_RESOLVER);
defaultMenuItem.setAttribute('type', 'checkbox');
menupopup.appendChild(defaultMenuItem);
var customMenuItem = document.createElement('menuitem');
customMenuItem.setAttribute('label', Zotero.getString('general.custom'));
customMenuItem.setAttribute('value', 'custom');
customMenuItem.setAttribute('type', 'checkbox');
menupopup.appendChild(customMenuItem);
menupopup.appendChild(document.createElement('menuseparator'));
var selectedName;
var lastContinent;
var lastCountry;
var currentContinentPopup;
var currentMenuPopup;
for (let r of this._openURLResolvers) {
// Create submenus for continents
if (r.continent != lastContinent) {
let menu = document.createElement('menu');
menu.setAttribute('label', r.continent);
openURLMenu.firstChild.appendChild(menu);
currentContinentPopup = currentMenuPopup = document.createElement('menupopup');
menu.appendChild(currentContinentPopup);
lastContinent = r.continent;
}
if (r.country != lastCountry) {
// If there's a country, create a submenu for it
if (r.country) {
let menu = document.createElement('menu');
menu.setAttribute('label', r.country);
currentContinentPopup.appendChild(menu);
let menupopup = document.createElement('menupopup');
menu.appendChild(menupopup);
currentMenuPopup = menupopup;
}
// Otherwise use the continent popup
else {
currentMenuPopup = currentContinentPopup;
}
lastCountry = r.country;
}
let menuitem = document.createElement('menuitem');
menuitem.setAttribute('label', r.name);
menuitem.setAttribute('value', r.url);
menuitem.setAttribute('type', 'checkbox');
currentMenuPopup.appendChild(menuitem);
var checked = r.url == Zotero.Prefs.get('openURL.resolver');
menuitem.setAttribute('checked', checked);
if (checked) {
selectedName = r.name;
}
}
// Default
if (currentResolver == this.DEFAULT_OPENURL_RESOLVER) {
openURLMenu.setAttribute('label', Zotero.getString('general.default'));
defaultMenuItem.setAttribute('checked', true);
Zotero.Prefs.clear('openURL.name');
}
else if (selectedName) {
openURLMenu.setAttribute('label', selectedName);
// If we found a match, update stored name
Zotero.Prefs.set('openURL.name', selectedName);
}
// Custom
else {
openURLMenu.setAttribute('label', Zotero.getString('general.custom'));
customMenuItem.setAttribute('checked', true);
Zotero.Prefs.clear('openURL.name');
}
},
handleOpenURLSelected: function (event) {
event.stopPropagation();
event.preventDefault();
if (event.target.localName != 'menuitem') {
Zotero.debug("Ignoring click on " + event.target.localName);
return;
}
var openURLMenu = document.getElementById('openurl-menu');
var openURLServerField = document.getElementById('openURLServerField');
var openURLVersionMenu = document.getElementById('openURLVersionMenu');
// Default
if (event.target.value == this.DEFAULT_OPENURL_RESOLVER) {
Zotero.Prefs.clear('openURL.name');
Zotero.Prefs.clear('openURL.resolver');
Zotero.Prefs.clear('openURL.version');
openURLServerField.value = this.DEFAULT_OPENURL_RESOLVER;
}
// If "Custom" selected, clear URL field
else if (event.target.value == "custom") {
Zotero.Prefs.clear('openURL.name');
Zotero.Prefs.set('openURL.resolver', '');
Zotero.Prefs.clear('openURL.version');
openURLServerField.value = '';
openURLServerField.focus();
}
else {
Zotero.Prefs.set('openURL.name', openURLServerField.value = event.target.label);
Zotero.Prefs.set('openURL.resolver', openURLServerField.value = event.target.value);
Zotero.Prefs.set('openURL.version', openURLVersionMenu.value = "1.0");
}
openURLMenu.firstChild.hidePopup();
setTimeout(() => {
this.updateOpenURLResolversMenu();
});
},
onOpenURLCustomized: function () {
setTimeout(() => {
this.updateOpenURLResolversMenu();
});
},
_getAutomaticLocaleMenuLabel: function () {
return Zotero.getString(
'zotero.preferences.locale.automaticWithLocale',
Zotero.Locale.availableLocales[Zotero.locale] || Zotero.locale
);
},
refreshLocale: function () {
var autoLocaleName, currentValue;
// If matching OS, get the name of the current locale
if (Zotero.Prefs.get('intl.locale.requested', true) === '') {
autoLocaleName = this._getAutomaticLocaleMenuLabel();
currentValue = 'automatic';
}
// Otherwise get the name of the locale specified in the pref
else {
autoLocaleName = Zotero.getString('zotero.preferences.locale.automatic');
currentValue = Zotero.locale;
}
// Populate menu
var menu = document.getElementById('locale-menu');
var menupopup = menu.firstChild;
menupopup.textContent = '';
// Show "Automatic (English)", "Automatic (Français)", etc.
menu.appendItem(autoLocaleName, 'automatic');
menu.menupopup.appendChild(document.createElement('menuseparator'));
// Add all available locales
for (let locale in Zotero.Locale.availableLocales) {
menu.appendItem(Zotero.Locale.availableLocales[locale], locale);
}
menu.value = currentValue;
},
onLocaleChange: function () {
var requestedLocale = Services.locale.getRequestedLocale();
var menu = document.getElementById('locale-menu');
if (menu.value == 'automatic') {
// Changed if not already set to automatic (unless we have the automatic locale name,
// meaning we just switched away to the same manual locale and back to automatic)
var changed = requestedLocale && menu.label != this._getAutomaticLocaleMenuLabel();
Services.locale.setRequestedLocales(null);
}
else {
// Changed if moving to a locale other than the current one
var changed = Zotero.locale != menu.value
Services.locale.setRequestedLocales([menu.value]);
}
if (!changed) {
return;
}
var ps = Services.prompt;
var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_IS_STRING;
var index = ps.confirmEx(null,
Zotero.getString('general.restartRequired'),
Zotero.getString('general.restartRequiredForChange', Zotero.appName),
buttonFlags,
Zotero.getString('general.restartNow'),
Zotero.getString('general.restartLater'),
null, null, {});
if (index == 0) {
Zotero.Utilities.Internal.quitZotero(true);
}
}
};
Zotero_Preferences.Attachment_Base_Directory = {
getPath: function () {
var oldPath = Zotero.Prefs.get('baseAttachmentPath');
if (oldPath) {
try {
return OS.Path.normalize(oldPath);
}
catch (e) {
Zotero.logError(e);
return false;
}
}
},
choosePath: async function () {
var oldPath = this.getPath();
//Prompt user to choose new base path
var fp = new FilePicker();
if (oldPath) {
fp.displayDirectory = oldPath;
}
fp.init(window, Zotero.getString('attachmentBasePath.selectDir'), fp.modeGetFolder);
fp.appendFilters(fp.filterAll);
if (await fp.show() != fp.returnOK) {
return false;
}
var newPath = fp.file;
if (oldPath && oldPath == newPath) {
Zotero.debug("Base directory hasn't changed");
return false;
}
try {
return await this.changePath(newPath);
}
catch (e) {
Zotero.logError(e);
Zotero.alert(null, Zotero.getString('general.error'), e.message);
}
},
changePath: Zotero.Promise.coroutine(function* (basePath) {
Zotero.debug(`New base directory is ${basePath}`);
if (Zotero.File.directoryContains(Zotero.DataDirectory.dir, basePath)) {
throw new Error(
Zotero.getString(
'zotero.preferences.advanced.baseDirectory.withinDataDir',
Zotero.appName
)
);
}
// Find all current attachments with relative attachment paths
var sql = "SELECT itemID FROM itemAttachments WHERE linkMode=? AND path LIKE ?";
var params = [
Zotero.Attachments.LINK_MODE_LINKED_FILE,
Zotero.Attachments.BASE_PATH_PLACEHOLDER + "%"
];
var oldRelativeAttachmentIDs = yield Zotero.DB.columnQueryAsync(sql, params);
//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 = yield Zotero.DB.columnQueryAsync(sql, params);
var newAttachmentPaths = {};
var numNewAttachments = 0;
var numOldAttachments = 0;
for (let i=0; i<allAttachments.length; i++) {
let attachmentID = allAttachments[i];
let attachmentPath;
let relPath = false
try {
let attachment = yield Zotero.Items.getAsync(attachmentID);
// This will return FALSE for relative paths if base directory
// isn't currently set
attachmentPath = attachment.getFilePath();
// Get existing relative path
let storedPath = attachment.attachmentPath;
if (storedPath.startsWith(Zotero.Attachments.BASE_PATH_PLACEHOLDER)) {
relPath = storedPath.substr(Zotero.Attachments.BASE_PATH_PLACEHOLDER.length);
}
}
catch (e) {
// Don't deal with bad attachment paths. Just skip them.
Zotero.debug(e, 2);
continue;
}
// If a file with the same relative path exists within the new base directory,
// don't touch the attachment, since it will continue to work
if (relPath) {
if (yield OS.File.exists(OS.Path.join(basePath, relPath))) {
numNewAttachments++;
continue;
}
}
// Files within the new base directory need to be updated to use
// relative paths (or, if the new base directory is an ancestor or
// descendant of the old one, new relative paths)
if (attachmentPath && Zotero.File.directoryContains(basePath, attachmentPath)) {
Zotero.debug(`Converting ${attachmentPath} to relative path`);
newAttachmentPaths[attachmentID] = relPath ? attachmentPath : null;
numNewAttachments++;
}
// Existing relative attachments not within the new base directory
// will be converted to absolute paths
else if (relPath && this.getPath()) {
Zotero.debug(`Converting ${relPath} to absolute path`);
newAttachmentPaths[attachmentID] = attachmentPath;
numOldAttachments++;
}
else {
Zotero.debug(`${attachmentPath} is not within the base directory`);
}
}
//Confirm change of the base path
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var chooseStrPrefix = 'attachmentBasePath.chooseNewPath.';
var clearStrPrefix = 'attachmentBasePath.clearBasePath.';
var title = Zotero.getString(chooseStrPrefix + 'title');
var msg1 = Zotero.getString(chooseStrPrefix + 'message') + "\n\n", msg2 = "", msg3 = "";
switch (numNewAttachments) {
case 0:
break;
case 1:
msg2 += Zotero.getString(chooseStrPrefix + 'existingAttachments.singular') + " ";
break;
default:
msg2 += Zotero.getString(chooseStrPrefix + 'existingAttachments.plural', numNewAttachments) + " ";
}
switch (numOldAttachments) {
case 0:
break;
case 1:
msg3 += Zotero.getString(clearStrPrefix + 'existingAttachments.singular');
break;
default:
msg3 += Zotero.getString(clearStrPrefix + 'existingAttachments.plural', numOldAttachments);
}
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
var index = ps.confirmEx(
null,
title,
(msg1 + msg2 + msg3).trim(),
buttonFlags,
Zotero.getString(chooseStrPrefix + 'button'),
null,
null,
null,
{}
);
if (index == 1) {
return false;
}
// Set new base directory
Zotero.debug("Setting base directory to " + basePath);
Zotero.Prefs.set('baseAttachmentPath', basePath);
Zotero.Prefs.set('saveRelativeAttachmentPath', true);
// Resave all attachments on base path (so that their paths become relative)
// and all other relative attachments (so that their paths become absolute)
yield Zotero.Utilities.Internal.forEachChunkAsync(
Object.keys(newAttachmentPaths),
100,
function (chunk) {
return Zotero.DB.executeTransaction(function* () {
for (let id of chunk) {
let attachment = Zotero.Items.get(id);
if (newAttachmentPaths[id]) {
attachment.attachmentPath = newAttachmentPaths[id];
}
else {
attachment.attachmentPath = attachment.getFilePath();
}
yield attachment.save({
skipDateModifiedUpdate: true
});
}
})
}
);
return true;
}),
clearPath: Zotero.Promise.coroutine(function* () {
// Find all current attachments with relative paths
var sql = "SELECT itemID FROM itemAttachments WHERE linkMode=? AND path LIKE ?";
var params = [
Zotero.Attachments.LINK_MODE_LINKED_FILE,
Zotero.Attachments.BASE_PATH_PLACEHOLDER + "%"
];
var relativeAttachmentIDs = yield Zotero.DB.columnQueryAsync(sql, params);
// Prompt for confirmation
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var strPrefix = 'attachmentBasePath.clearBasePath.';
var title = Zotero.getString(strPrefix + 'title');
var msg = Zotero.getString(strPrefix + 'message');
switch (relativeAttachmentIDs.length) {
case 0:
break;
case 1:
msg += "\n\n" + Zotero.getString(strPrefix + 'existingAttachments.singular');
break;
default:
msg += "\n\n" + Zotero.getString(strPrefix + 'existingAttachments.plural',
relativeAttachmentIDs.length);
}
var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
var index = ps.confirmEx(
window,
title,
msg,
buttonFlags,
Zotero.getString(strPrefix + 'button'),
null,
null,
null,
{}
);
if (index == 1) {
return false;
}
// Disable relative path saving and then resave all relative
// attachments so that their absolute paths are stored
Zotero.debug('Clearing base directory');
Zotero.Prefs.set('saveRelativeAttachmentPath', false);
yield Zotero.Utilities.Internal.forEachChunkAsync(
relativeAttachmentIDs,
100,
function (chunk) {
return Zotero.DB.executeTransaction(function* () {
for (let id of chunk) {
let attachment = yield Zotero.Items.getAsync(id);
attachment.attachmentPath = attachment.getFilePath();
yield attachment.save({
skipDateModifiedUpdate: true
});
}
}.bind(this));
}.bind(this)
);
Zotero.Prefs.set('baseAttachmentPath', '');
}),
updateUI: Zotero.Promise.coroutine(function* () {
var filefield = document.getElementById('baseAttachmentPath');
var path = Zotero.Prefs.get('baseAttachmentPath');
Components.utils.import("resource://gre/modules/osfile.jsm");
if (yield OS.File.exists(path)) {
filefield.file = Zotero.File.pathToFile(path);
filefield.label = path;
}
else {
filefield.label = '';
}
document.getElementById('resetBasePath').disabled = !path;
})
};
Zotero_Preferences.Keys = {
init: function () {
var rows = document.getElementById('zotero-prefpane-advanced-keys-tab').getElementsByTagName('row');
for (var i=0; i<rows.length; i++) {
// Display the appropriate modifier keys for the platform
let label = rows[i].firstChild.nextSibling;
if (label.className == 'modifier') {
label.value = Zotero.isMac ? Zotero.getString('general.keys.cmdShift') : Zotero.getString('general.keys.ctrlShift');
}
}
var textboxes = document.getElementById('zotero-keys-rows').getElementsByTagName('textbox');
for (let i=0; i<textboxes.length; i++) {
let textbox = textboxes[i];
textbox.value = textbox.value.toUpperCase();
// .value takes care of the initial value, and this takes care of direct pref changes
// while the window is open
textbox.setAttribute('onsyncfrompreference', 'return Zotero_Preferences.Keys.capitalizePref(this.id)');
textbox.setAttribute('oninput', 'this.value = this.value.toUpperCase()');
}
},
capitalizePref: function (id) {
var elem = document.getElementById(id);
var pref = document.getElementById(elem.getAttribute('preference'));
if (pref.value) {
return pref.value.toUpperCase();
}
}
};