Fix #1163, Unable to open zotero urls from tinymce

This commit is contained in:
Dan Stillman 2017-01-30 14:01:04 -05:00
parent b073c3e680
commit ae47ae28bd
5 changed files with 152 additions and 115 deletions

View File

@ -440,7 +440,11 @@
this._changed = true;
commandEvent = true;
break;
case 'ZoteroLinkClick':
ZoteroPane.loadURI(event.value);
break;
default:
return;
}

View File

@ -51,7 +51,6 @@ var ZoteroPane = new function()
this.getSortedItems = getSortedItems;
this.getSortField = getSortField;
this.getSortDirection = getSortDirection;
this.loadURI = loadURI;
this.setItemsPaneMessage = setItemsPaneMessage;
this.clearItemsPaneMessage = clearItemsPaneMessage;
this.contextPopupShowing = contextPopupShowing;
@ -3188,7 +3187,7 @@ var ZoteroPane = new function()
* (e.g. meta-click == new background tab, meta-shift-click == new front tab,
* shift-click == new window, no modifier == frontmost tab
*/
function loadURI(uris, event) {
this.loadURI = function (uris, event) {
if(typeof uris === "string") {
uris = [uris];
}
@ -3203,9 +3202,22 @@ var ZoteroPane = new function()
if (Zotero.isStandalone) {
if(uri.match(/^https?/)) {
this.launchURL(uri);
} else {
Zotero.openInViewer(uri);
return;
}
// Handle no-content zotero: URLs (e.g., zotero://select) without opening viewer
if (uri.startsWith('zotero:')) {
let nsIURI = Services.io.newURI(uri, null, null);
let handler = Components.classes["@mozilla.org/network/protocol;1?name=zotero"]
.createInstance(Components.interfaces.nsIProtocolHandler);
let extension = handler.wrappedJSObject.getExtension(nsIURI);
if (extension.noContent) {
extension.doAction(nsIURI);
return;
}
}
Zotero.openInViewer(uri);
return;
}

View File

@ -127,7 +127,7 @@ function ZoteroProtocolHandler() {
router.add('groups/:groupID/:scopeObject/:scopeObjectKey/items');
// All items
router.add('library/items', function () {
router.add('library/items/:objectKey', function () {
params.libraryID = userLibraryID;
});
router.add('groups/:groupID/items');
@ -796,73 +796,70 @@ function ZoteroProtocolHandler() {
* zotero://select/[type]/1234 (not consistent across synced machines)
*/
var SelectExtension = {
newChannel: function (uri) {
return new AsyncChannel(uri, function* () {
var userLibraryID = Zotero.Libraries.userLibraryID;
var path = uri.path;
if (!path) {
return 'Invalid URL';
}
// Strip leading '/'
path = path.substr(1);
var mimeType, content = '';
var params = {
objectType: 'item'
};
var router = new Zotero.Router(params);
// Item within a collection or search
router.add('library/:scopeObject/:scopeObjectKey/items/:objectKey', function () {
params.libraryID = userLibraryID;
});
router.add('groups/:groupID/:scopeObject/:scopeObjectKey/items/:objectKey');
// All items
router.add('library/items/:objectKey', function () {
params.libraryID = userLibraryID;
});
router.add('groups/:groupID/items/:objectKey');
// Old-style URLs
router.add('item/:id', function () {
var lkh = Zotero.Items.parseLibraryKeyHash(params.id);
if (lkh) {
params.libraryID = lkh.libraryID;
params.objectKey = lkh.key;
}
else {
params.objectID = params.id;
}
delete params.id;
});
router.run(path);
try {
Zotero.API.parseParams(params);
var results = yield Zotero.API.getResultsFromParams(params);
}
catch (e) {
Zotero.debug(e, 1);
return e.toString();
}
if (!results.length) {
var msg = "Selected items not found";
Zotero.debug(msg, 2);
Components.utils.reportError(msg);
return;
}
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var win = wm.getMostRecentWindow("navigator:browser");
// TODO: Currently only able to select one item
yield win.ZoteroPane.selectItem(results[0].id);
noContent: true,
doAction: Zotero.Promise.coroutine(function* (uri) {
var userLibraryID = Zotero.Libraries.userLibraryID;
var path = uri.path;
if (!path) {
return 'Invalid URL';
}
// Strip leading '/'
path = path.substr(1);
var mimeType, content = '';
var params = {
objectType: 'item'
};
var router = new Zotero.Router(params);
// Item within a collection or search
router.add('library/:scopeObject/:scopeObjectKey/items/:objectKey', function () {
params.libraryID = userLibraryID;
});
router.add('groups/:groupID/:scopeObject/:scopeObjectKey/items/:objectKey');
// All items
router.add('library/items/:objectKey', function () {
params.libraryID = userLibraryID;
});
router.add('groups/:groupID/items/:objectKey');
// Old-style URLs
router.add('item/:id', function () {
var lkh = Zotero.Items.parseLibraryKeyHash(params.id);
if (lkh) {
params.libraryID = lkh.libraryID;
params.objectKey = lkh.key;
}
else {
params.objectID = params.id;
}
delete params.id;
});
router.run(path);
Zotero.API.parseParams(params);
var results = yield Zotero.API.getResultsFromParams(params);
if (!results.length) {
var msg = "Items not found";
Zotero.debug(msg, 2);
Components.utils.reportError(msg);
return;
}
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var win = wm.getMostRecentWindow("navigator:browser");
// TODO: Currently only able to select one item
return win.ZoteroPane.selectItem(results[0].id);
}),
newChannel: function (uri) {
this.doAction(uri);
}
};
@ -1039,6 +1036,22 @@ ZoteroProtocolHandler.prototype = {
return false;
},
getExtension: function (uri) {
let uriString = uri;
if (uri instanceof Components.interfaces.nsIURI) {
uriString = uri.spec;
}
uriString = uriString.toLowerCase();
for (let extSpec in this._extensions) {
if (uriString.startsWith(extSpec)) {
return this._extensions[extSpec];
}
}
return false;
},
newURI : function(spec, charset, baseURI) {
var newURL = Components.classes["@mozilla.org/network/standard-url;1"]
.createInstance(Components.interfaces.nsIStandardURL);
@ -1056,53 +1069,49 @@ ZoteroProtocolHandler.prototype = {
var newChannel = null;
try {
var uriString = uri.spec.toLowerCase();
let ext = this.getExtension(uri);
for (var extSpec in this._extensions) {
var ext = this._extensions[extSpec];
if (uriString.indexOf(extSpec) == 0) {
if (!this._principal) {
if (ext.loadAsChrome) {
var chromeURI = chromeService.newURI(DUMMY_CHROME_URL, null, null);
var chromeChannel = chromeService.newChannel(chromeURI);
// Cache System Principal from chrome request
// so proxied pages load with chrome privileges
this._principal = chromeChannel.owner;
var chromeRequest = chromeChannel.QueryInterface(Components.interfaces.nsIRequest);
chromeRequest.cancel(0x804b0002); // BINDING_ABORTED
}
}
if (!ext) {
// Return cancelled channel for unknown paths
//
// These can be in the form zotero://example.com/... -- maybe for "//example.com" URLs?
var chromeURI = chromeService.newURI(DUMMY_CHROME_URL, null, null);
var extChannel = chromeService.newChannel(chromeURI);
var chromeRequest = extChannel.QueryInterface(Components.interfaces.nsIRequest);
chromeRequest.cancel(0x804b0002); // BINDING_ABORTED
return extChannel;
}
if (!this._principal) {
if (ext.loadAsChrome) {
var chromeURI = chromeService.newURI(DUMMY_CHROME_URL, null, null);
var chromeChannel = chromeService.newChannel(chromeURI);
var extChannel = ext.newChannel(uri);
// Extension returned null, so cancel request
if (!extChannel) {
var chromeURI = chromeService.newURI(DUMMY_CHROME_URL, null, null);
var extChannel = chromeService.newChannel(chromeURI);
var chromeRequest = extChannel.QueryInterface(Components.interfaces.nsIRequest);
chromeRequest.cancel(0x804b0002); // BINDING_ABORTED
}
// Cache System Principal from chrome request
// so proxied pages load with chrome privileges
this._principal = chromeChannel.owner;
// Apply cached principal to extension channel
if (this._principal) {
extChannel.owner = this._principal;
}
if(!extChannel.originalURI) extChannel.originalURI = uri;
return extChannel;
var chromeRequest = chromeChannel.QueryInterface(Components.interfaces.nsIRequest);
chromeRequest.cancel(0x804b0002); // BINDING_ABORTED
}
}
// Return cancelled channel for unknown paths
//
// These can be in the form zotero://example.com/... -- maybe for "//example.com" URLs?
var chromeURI = chromeService.newURI(DUMMY_CHROME_URL, null, null);
var extChannel = chromeService.newChannel(chromeURI);
var chromeRequest = extChannel.QueryInterface(Components.interfaces.nsIRequest);
chromeRequest.cancel(0x804b0002); // BINDING_ABORTED
var extChannel = ext.newChannel(uri);
// Extension returned null, so cancel request
if (!extChannel) {
var chromeURI = chromeService.newURI(DUMMY_CHROME_URL, null, null);
var extChannel = chromeService.newChannel(chromeURI);
var chromeRequest = extChannel.QueryInterface(Components.interfaces.nsIRequest);
chromeRequest.cancel(0x804b0002); // BINDING_ABORTED
}
// Apply cached principal to extension channel
if (this._principal) {
extChannel.owner = this._principal;
}
if(!extChannel.originalURI) extChannel.originalURI = uri;
return extChannel;
}
catch (e) {

View File

@ -57,6 +57,15 @@
zoteroExecCommand(ed.getDoc(), cmd, ui, value);
});
});
["ZoteroLinkClick"].forEach(function (command) {
ed.addCommand(command, function (ui, value) {
zoteroHandleEvent({
type: command,
value
});
});
});
},
// More restrictive version of default set, with JS/etc. removed

View File

@ -59,11 +59,14 @@ tinymce.PluginManager.add('link', function(editor) {
}
function openDetachedWindow(url) {
// Added by Zotero
editor.execCommand('ZoteroLinkClick', false, url);
// Chrome and Webkit has implemented noopener and works correctly with/without popup blocker
// Firefox has it implemented noopener but when the popup blocker is activated it doesn't work
// Edge has only implemented noreferrer and it seems to remove opener as well
// Older IE versions pre IE 11 falls back to a window.open approach
if (!tinymce.Env.ie || tinymce.Env.ie > 10) {
/*if (!tinymce.Env.ie || tinymce.Env.ie > 10) {
var link = document.createElement('a');
link.target = '_blank';
link.href = url;
@ -81,7 +84,7 @@ tinymce.PluginManager.add('link', function(editor) {
doc.write('<meta http-equiv="refresh" content="0; url=' + tinymce.DOM.encode(url) + '">');
doc.close();
}
}
}*/
}
function gotoLink(a) {