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:
Dan Stillman 2021-08-13 06:05:18 -04:00
parent 5118cd4164
commit 3732f97d41
9 changed files with 254 additions and 57 deletions

View file

@ -575,10 +575,14 @@ var Zotero_LocateMenu = new function() {
this.icon = "chrome://zotero/skin/locate-library-lookup.png";
this.canHandleItem = function (item) { return Zotero.Promise.resolve(item.isRegularItem()); };
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 = [];
for (let item of items) {
if(!item.isRegularItem()) continue;
var url = Zotero.OpenURL.resolve(item);
var url = Zotero.Utilities.Internal.OpenURL.resolve(item);
if(url) urls.push(url);
}
ZoteroPane_Local.loadURI(urls, event);

View file

@ -27,8 +27,9 @@ Components.utils.import("resource://gre/modules/Services.jsm");
import FilePicker from 'zotero/filePicker';
Zotero_Preferences.Advanced = {
_openURLResolvers: null,
DEFAULT_OPENURL_RESOLVER: 'https://www.worldcat.org/registry/gateway',
_openURLResolvers: null,
init: function () {
Zotero_Preferences.Keys.init();
@ -50,6 +51,14 @@ Zotero_Preferences.Advanced = {
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();
},
@ -421,55 +430,163 @@ Zotero_Preferences.Advanced = {
},
populateOpenURLResolvers: function () {
var openURLMenu = document.getElementById('openURLMenu');
this._openURLResolvers = Zotero.OpenURL.discoverResolvers();
var i = 0;
for (let r of this._openURLResolvers) {
openURLMenu.insertItemAt(i, r.name);
if (r.url == Zotero.Prefs.get('openURL.resolver') && r.version == Zotero.Prefs.get('openURL.version')) {
openURLMenu.selectedIndex = i;
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;
}
i++;
}
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));
this.updateOpenURLResolversMenu();
},
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 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();
}
else
{
openURLServerField.value = this._openURLResolvers[openURLMenu.selectedIndex]['url'];
openURLVersionMenu.value = this._openURLResolvers[openURLMenu.selectedIndex]['version'];
Zotero.Prefs.set("openURL.resolver", this._openURLResolvers[openURLMenu.selectedIndex]['url']);
Zotero.Prefs.set("openURL.version", this._openURLResolvers[openURLMenu.selectedIndex]['version']);
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 () {
document.getElementById('openURLMenu').value = "custom";
setTimeout(() => {
this.updateOpenURLResolversMenu();
});
},

View file

@ -95,25 +95,23 @@
<groupbox>
<caption label="OpenURL"/>
<hbox align="center">
<!-- vbox prevents some weird vertical stretching of the menulist -->
<vbox flex="1">
<menulist id="openURLMenu" oncommand="Zotero_Preferences.Advanced.onOpenURLSelected();">
<menupopup>
<menuseparator/>
<menuitem label="&zotero.preferences.openurl.custom;" value="custom" selected="true"/>
</menupopup>
</menulist>
</vbox>
<button id="openURLSearchButton" label="&zotero.preferences.openurl.search;"
oncommand="Zotero_Preferences.Advanced.populateOpenURLResolvers()"/>
<hbox>
<menulist id="openurl-menu">
<menupopup
id="openurl-primary-popup"
onpopupshowing="Zotero_Preferences.Advanced.handleOpenURLPopupShowing(event)"
oncommand="Zotero_Preferences.Advanced.handleOpenURLSelected(event)">
<menuitem label="&zotero.preferences.openurl.choose;"/>
</menupopup>
</menulist>
</hbox>
<hbox align="center">
<label value="&zotero.preferences.openurl.server;"/>
<textbox id="openURLServerField" flex="1"
oninput="Zotero_Preferences.Advanced.onOpenURLCustomized();"
preference="pref-openURL-resolver"/>
oninput="Zotero_Preferences.Advanced.onOpenURLCustomized();"
preference="pref-openURL-resolver"
/>
</hbox>
<hbox align="center">

@ -1 +1 @@
Subproject commit 2a0b11fad5f3345271c1bb393c1e09f653103240
Subproject commit db52081e6eedfb0aa250dfc7f93ab2cf7ed6e468

View file

@ -2694,6 +2694,78 @@ Zotero.Utilities.Internal.Base64 = {
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]'){
module.exports = Zotero.Utilities.Internal;
}

View file

@ -39,7 +39,7 @@
<!ENTITY zotero.preferences.feeds.sorting.oldest "Oldest items first">
<!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.server "Resolver:">
<!ENTITY zotero.preferences.openurl.version "Version:">

View file

@ -82,6 +82,9 @@ general.item = Item
general.pdf = PDF
general.back = Back
general.languages = Languages
general.default = Default
general.custom = Custom
general.loading = Loading…
general.yellow = Yellow
general.red = Red
@ -666,9 +669,6 @@ zotero.preferences.update.updated = Updated
zotero.preferences.update.upToDate = Up to date
zotero.preferences.update.error = Error
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.automatic = Automatic

View file

@ -281,6 +281,12 @@ grid row hbox:first-child
width: 105px;
}
/* Advanced General pane */
#zotero-prefpane-advanced-general-tab #openurl-menu {
width: 400px;
}
/* Shortcut Keys pane */
#zotero-prefpane-advanced-keys-tab row
{

View file

@ -23,7 +23,7 @@ pref("extensions.zotero.automaticScraperUpdates",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)
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.automaticSnapshots",true);
pref("extensions.zotero.downloadAssociatedFiles",true);