Add OpenURL resolver directory
Remove the apparently obsolete [1] WorldCat `lookup?IP=requestor` search functionality and replace with a hierarchical menu populated directly from our directory [2]. Also switch to https://www.worldcat.org/registry/gateway as the default resolver, which seems to be the same as http://worldcatlibraries.org/registry/gateway but with HTTPS support Fixes #1811 Fixes #1853 [1] https://forums.zotero.org/discussion/79312/search-for-resolvers-gives-out-of-date-information [2] https://www.zotero.org/support/locate/openurl_resolvers
This commit is contained in:
parent
5118cd4164
commit
3732f97d41
9 changed files with 254 additions and 57 deletions
|
@ -575,10 +575,14 @@ var Zotero_LocateMenu = new function() {
|
||||||
this.icon = "chrome://zotero/skin/locate-library-lookup.png";
|
this.icon = "chrome://zotero/skin/locate-library-lookup.png";
|
||||||
this.canHandleItem = function (item) { return Zotero.Promise.resolve(item.isRegularItem()); };
|
this.canHandleItem = function (item) { return Zotero.Promise.resolve(item.isRegularItem()); };
|
||||||
this.handleItems = Zotero.Promise.method(function (items, event) {
|
this.handleItems = Zotero.Promise.method(function (items, event) {
|
||||||
|
// If no resolver configured, just switch to the default
|
||||||
|
if (!Zotero.Prefs.get('openURL.resolver')) {
|
||||||
|
Zotero.Prefs.clear('openURL.resolver')
|
||||||
|
}
|
||||||
var urls = [];
|
var urls = [];
|
||||||
for (let item of items) {
|
for (let item of items) {
|
||||||
if(!item.isRegularItem()) continue;
|
if(!item.isRegularItem()) continue;
|
||||||
var url = Zotero.OpenURL.resolve(item);
|
var url = Zotero.Utilities.Internal.OpenURL.resolve(item);
|
||||||
if(url) urls.push(url);
|
if(url) urls.push(url);
|
||||||
}
|
}
|
||||||
ZoteroPane_Local.loadURI(urls, event);
|
ZoteroPane_Local.loadURI(urls, event);
|
||||||
|
|
|
@ -27,8 +27,9 @@ Components.utils.import("resource://gre/modules/Services.jsm");
|
||||||
import FilePicker from 'zotero/filePicker';
|
import FilePicker from 'zotero/filePicker';
|
||||||
|
|
||||||
Zotero_Preferences.Advanced = {
|
Zotero_Preferences.Advanced = {
|
||||||
_openURLResolvers: null,
|
DEFAULT_OPENURL_RESOLVER: 'https://www.worldcat.org/registry/gateway',
|
||||||
|
|
||||||
|
_openURLResolvers: null,
|
||||||
|
|
||||||
init: function () {
|
init: function () {
|
||||||
Zotero_Preferences.Keys.init();
|
Zotero_Preferences.Keys.init();
|
||||||
|
@ -50,6 +51,14 @@ Zotero_Preferences.Advanced = {
|
||||||
input.value = Zotero.Prefs.get(preferenceName);
|
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.onDataDirLoad();
|
||||||
this.refreshLocale();
|
this.refreshLocale();
|
||||||
},
|
},
|
||||||
|
@ -421,55 +430,163 @@ Zotero_Preferences.Advanced = {
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
populateOpenURLResolvers: function () {
|
handleOpenURLPopupShowing: async function (event) {
|
||||||
var openURLMenu = document.getElementById('openURLMenu');
|
if (event.target.id != 'openurl-primary-popup') {
|
||||||
|
return;
|
||||||
this._openURLResolvers = Zotero.OpenURL.discoverResolvers();
|
}
|
||||||
var i = 0;
|
if (!this._openURLResolvers) {
|
||||||
for (let r of this._openURLResolvers) {
|
let menupopup = document.getElementById('openurl-primary-popup');
|
||||||
openURLMenu.insertItemAt(i, r.name);
|
menupopup.firstChild.setAttribute('label', Zotero.getString('general.loading'));
|
||||||
if (r.url == Zotero.Prefs.get('openURL.resolver') && r.version == Zotero.Prefs.get('openURL.version')) {
|
try {
|
||||||
openURLMenu.selectedIndex = i;
|
this._openURLResolvers = await Zotero.Utilities.Internal.OpenURL.getResolvers();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
Zotero.logError(e);
|
||||||
|
menupopup.firstChild.setAttribute('label', "Error loading resolvers");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
this.updateOpenURLResolversMenu();
|
||||||
var button = document.getElementById('openURLSearchButton');
|
|
||||||
switch (this._openURLResolvers.length) {
|
|
||||||
case 0:
|
|
||||||
var num = 'zero';
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
var num = 'singular';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
var num = 'plural';
|
|
||||||
}
|
|
||||||
|
|
||||||
button.setAttribute('label', Zotero.getString('zotero.preferences.openurl.resolversFound.' + num, this._openURLResolvers.length));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
onOpenURLSelected: function () {
|
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 openURLServerField = document.getElementById('openURLServerField');
|
||||||
var openURLVersionMenu = document.getElementById('openURLVersionMenu');
|
var openURLVersionMenu = document.getElementById('openURLVersionMenu');
|
||||||
var openURLMenu = document.getElementById('openURLMenu');
|
|
||||||
|
|
||||||
if(openURLMenu.value == "custom")
|
// 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();
|
openURLServerField.focus();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
Zotero.Prefs.set('openURL.name', openURLServerField.value = event.target.label);
|
||||||
openURLServerField.value = this._openURLResolvers[openURLMenu.selectedIndex]['url'];
|
Zotero.Prefs.set('openURL.resolver', openURLServerField.value = event.target.value);
|
||||||
openURLVersionMenu.value = this._openURLResolvers[openURLMenu.selectedIndex]['version'];
|
Zotero.Prefs.set('openURL.version', openURLVersionMenu.value = "1.0");
|
||||||
Zotero.Prefs.set("openURL.resolver", this._openURLResolvers[openURLMenu.selectedIndex]['url']);
|
|
||||||
Zotero.Prefs.set("openURL.version", this._openURLResolvers[openURLMenu.selectedIndex]['version']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openURLMenu.firstChild.hidePopup();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.updateOpenURLResolversMenu();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onOpenURLCustomized: function () {
|
onOpenURLCustomized: function () {
|
||||||
document.getElementById('openURLMenu').value = "custom";
|
setTimeout(() => {
|
||||||
|
this.updateOpenURLResolversMenu();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -95,25 +95,23 @@
|
||||||
<groupbox>
|
<groupbox>
|
||||||
<caption label="OpenURL"/>
|
<caption label="OpenURL"/>
|
||||||
|
|
||||||
<hbox align="center">
|
<hbox>
|
||||||
<!-- vbox prevents some weird vertical stretching of the menulist -->
|
<menulist id="openurl-menu">
|
||||||
<vbox flex="1">
|
<menupopup
|
||||||
<menulist id="openURLMenu" oncommand="Zotero_Preferences.Advanced.onOpenURLSelected();">
|
id="openurl-primary-popup"
|
||||||
<menupopup>
|
onpopupshowing="Zotero_Preferences.Advanced.handleOpenURLPopupShowing(event)"
|
||||||
<menuseparator/>
|
oncommand="Zotero_Preferences.Advanced.handleOpenURLSelected(event)">
|
||||||
<menuitem label="&zotero.preferences.openurl.custom;" value="custom" selected="true"/>
|
<menuitem label="&zotero.preferences.openurl.choose;"/>
|
||||||
</menupopup>
|
</menupopup>
|
||||||
</menulist>
|
</menulist>
|
||||||
</vbox>
|
|
||||||
<button id="openURLSearchButton" label="&zotero.preferences.openurl.search;"
|
|
||||||
oncommand="Zotero_Preferences.Advanced.populateOpenURLResolvers()"/>
|
|
||||||
</hbox>
|
</hbox>
|
||||||
|
|
||||||
<hbox align="center">
|
<hbox align="center">
|
||||||
<label value="&zotero.preferences.openurl.server;"/>
|
<label value="&zotero.preferences.openurl.server;"/>
|
||||||
<textbox id="openURLServerField" flex="1"
|
<textbox id="openURLServerField" flex="1"
|
||||||
oninput="Zotero_Preferences.Advanced.onOpenURLCustomized();"
|
oninput="Zotero_Preferences.Advanced.onOpenURLCustomized();"
|
||||||
preference="pref-openURL-resolver"/>
|
preference="pref-openURL-resolver"
|
||||||
|
/>
|
||||||
</hbox>
|
</hbox>
|
||||||
|
|
||||||
<hbox align="center">
|
<hbox align="center">
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2a0b11fad5f3345271c1bb393c1e09f653103240
|
Subproject commit db52081e6eedfb0aa250dfc7f93ab2cf7ed6e468
|
|
@ -2694,6 +2694,78 @@ Zotero.Utilities.Internal.Base64 = {
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Zotero.Utilities.Internal.OpenURL = {
|
||||||
|
/**
|
||||||
|
* Returns a URL to look up an item in the OpenURL resolver
|
||||||
|
*/
|
||||||
|
resolve: function (item) {
|
||||||
|
var co = Zotero.OpenURL.createContextObject(
|
||||||
|
item.toJSON(),
|
||||||
|
Zotero.Prefs.get("openURL.version")
|
||||||
|
);
|
||||||
|
if (co) {
|
||||||
|
let base = Zotero.Prefs.get("openURL.resolver");
|
||||||
|
// Add & if there's already a ?
|
||||||
|
let splice = base.indexOf("?") == -1 ? "?" : "&";
|
||||||
|
return base + splice + co;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch list of resolvers from the Zotero wiki
|
||||||
|
*
|
||||||
|
* https://www.zotero.org/support/locate/openurl_resolvers
|
||||||
|
*/
|
||||||
|
getResolvers: async function () {
|
||||||
|
var req = await Zotero.HTTP.request(
|
||||||
|
"GET",
|
||||||
|
"https://www.zotero.org/support/locate/openurl_resolvers?do=export_raw"
|
||||||
|
);
|
||||||
|
var text = req.response;
|
||||||
|
var lines = text.split(/\n/);
|
||||||
|
var urls = [];
|
||||||
|
var continent;
|
||||||
|
var country = null;
|
||||||
|
for (let line of lines) {
|
||||||
|
// Continent
|
||||||
|
let matches = line.match(/^\s*=====\s*([^=]+)=====\s*$/);
|
||||||
|
if (matches) {
|
||||||
|
continent = matches[1].trim();
|
||||||
|
country = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Country
|
||||||
|
matches = line.match(/^\s*====\s*([^=]+)====\s*$/);
|
||||||
|
if (matches) {
|
||||||
|
country = matches[1].trim();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
matches = line.match(/^\s*\|\s*([^|]+)\s*\|\s*%%([^%]+)%%\s*\|\s*$/);
|
||||||
|
if (matches) {
|
||||||
|
urls.push({
|
||||||
|
continent,
|
||||||
|
country,
|
||||||
|
name: matches[1].trim(),
|
||||||
|
url: matches[2],
|
||||||
|
version: "1.0"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Skip global resolver, which is hard-coded locally
|
||||||
|
urls = urls.filter(x => x.continent != 'Global');
|
||||||
|
urls.sort((a, b) => {
|
||||||
|
var cmp = Zotero.localeCompare(a.continent, b.continent);
|
||||||
|
if (cmp) return cmp;
|
||||||
|
cmp = Zotero.localeCompare(a.country, b.country);
|
||||||
|
if (cmp) return cmp;
|
||||||
|
return Zotero.localeCompare(a.name, b.name);
|
||||||
|
});
|
||||||
|
return urls;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
if (typeof process === 'object' && process + '' === '[object process]'){
|
if (typeof process === 'object' && process + '' === '[object process]'){
|
||||||
module.exports = Zotero.Utilities.Internal;
|
module.exports = Zotero.Utilities.Internal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
<!ENTITY zotero.preferences.feeds.sorting.oldest "Oldest items first">
|
<!ENTITY zotero.preferences.feeds.sorting.oldest "Oldest items first">
|
||||||
<!ENTITY zotero.preferences.feeds.feedDefaults "Feed Defaults">
|
<!ENTITY zotero.preferences.feeds.feedDefaults "Feed Defaults">
|
||||||
|
|
||||||
<!ENTITY zotero.preferences.openurl.search "Search for resolvers">
|
<!ENTITY zotero.preferences.openurl.choose "Choose a resolver…">
|
||||||
<!ENTITY zotero.preferences.openurl.custom "Custom…">
|
<!ENTITY zotero.preferences.openurl.custom "Custom…">
|
||||||
<!ENTITY zotero.preferences.openurl.server "Resolver:">
|
<!ENTITY zotero.preferences.openurl.server "Resolver:">
|
||||||
<!ENTITY zotero.preferences.openurl.version "Version:">
|
<!ENTITY zotero.preferences.openurl.version "Version:">
|
||||||
|
|
|
@ -82,6 +82,9 @@ general.item = Item
|
||||||
general.pdf = PDF
|
general.pdf = PDF
|
||||||
general.back = Back
|
general.back = Back
|
||||||
general.languages = Languages
|
general.languages = Languages
|
||||||
|
general.default = Default
|
||||||
|
general.custom = Custom
|
||||||
|
general.loading = Loading…
|
||||||
|
|
||||||
general.yellow = Yellow
|
general.yellow = Yellow
|
||||||
general.red = Red
|
general.red = Red
|
||||||
|
@ -666,9 +669,6 @@ zotero.preferences.update.updated = Updated
|
||||||
zotero.preferences.update.upToDate = Up to date
|
zotero.preferences.update.upToDate = Up to date
|
||||||
zotero.preferences.update.error = Error
|
zotero.preferences.update.error = Error
|
||||||
zotero.preferences.launchNonNativeFiles = Open PDFs and other files within %S when possible
|
zotero.preferences.launchNonNativeFiles = Open PDFs and other files within %S when possible
|
||||||
zotero.preferences.openurl.resolversFound.zero = %S resolvers found
|
|
||||||
zotero.preferences.openurl.resolversFound.singular = %S resolver found
|
|
||||||
zotero.preferences.openurl.resolversFound.plural = %S resolvers found
|
|
||||||
zotero.preferences.locale.automaticWithLocale = Automatic (%S)
|
zotero.preferences.locale.automaticWithLocale = Automatic (%S)
|
||||||
zotero.preferences.locale.automatic = Automatic
|
zotero.preferences.locale.automatic = Automatic
|
||||||
|
|
||||||
|
|
|
@ -281,6 +281,12 @@ grid row hbox:first-child
|
||||||
width: 105px;
|
width: 105px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Advanced General pane */
|
||||||
|
|
||||||
|
#zotero-prefpane-advanced-general-tab #openurl-menu {
|
||||||
|
width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Shortcut Keys pane */
|
/* Shortcut Keys pane */
|
||||||
#zotero-prefpane-advanced-keys-tab row
|
#zotero-prefpane-advanced-keys-tab row
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,7 @@ pref("extensions.zotero.automaticScraperUpdates",true);
|
||||||
pref("extensions.zotero.triggerProxyAuthentication", true);
|
pref("extensions.zotero.triggerProxyAuthentication", true);
|
||||||
// Proxy auth URLs should respond successfully to HEAD requests over HTTP and HTTPS (in case of forced HTTPS requests)
|
// Proxy auth URLs should respond successfully to HEAD requests over HTTP and HTTPS (in case of forced HTTPS requests)
|
||||||
pref("extensions.zotero.proxyAuthenticationURLs", "https://www.acm.org,https://www.ebscohost.com,https://www.sciencedirect.com,https://ieeexplore.ieee.org,https://www.jstor.org,http://www.ovid.com,https://link.springer.com,https://www.tandfonline.com");
|
pref("extensions.zotero.proxyAuthenticationURLs", "https://www.acm.org,https://www.ebscohost.com,https://www.sciencedirect.com,https://ieeexplore.ieee.org,https://www.jstor.org,http://www.ovid.com,https://link.springer.com,https://www.tandfonline.com");
|
||||||
pref("extensions.zotero.openURL.resolver","http://worldcatlibraries.org/registry/gateway");
|
pref("extensions.zotero.openURL.resolver","https://www.worldcat.org/registry/gateway");
|
||||||
pref("extensions.zotero.openURL.version","1.0");
|
pref("extensions.zotero.openURL.version","1.0");
|
||||||
pref("extensions.zotero.automaticSnapshots",true);
|
pref("extensions.zotero.automaticSnapshots",true);
|
||||||
pref("extensions.zotero.downloadAssociatedFiles",true);
|
pref("extensions.zotero.downloadAssociatedFiles",true);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue