Add flexible locate menu, based on a (very heavily modified) copy of the pubget patch. Documentation is forthcoming.
This commit is contained in:
parent
b6d2898a03
commit
1486132626
15 changed files with 1430 additions and 370 deletions
|
@ -44,7 +44,6 @@
|
|||
<field name="clickable">false</field>
|
||||
<field name="editable">false</field>
|
||||
<field name="saveOnEdit">false</field>
|
||||
<field name="displayGoButtons">false</field>
|
||||
<field name="showTypeMenu">false</field>
|
||||
<field name="hideEmptyFields">false</field>
|
||||
<field name="clickByRow">false</field> <!-- Click entire row rather than just field value -->
|
||||
|
@ -61,7 +60,6 @@
|
|||
this.clickable = false;
|
||||
this.editable = false;
|
||||
this.saveOnEdit = false;
|
||||
this.displayGoButtons = false;
|
||||
this.showTypeMenu = false;
|
||||
this.hideEmptyFields = false;
|
||||
this.clickByRow = false;
|
||||
|
@ -75,7 +73,6 @@
|
|||
this.clickable = true;
|
||||
this.editable = true;
|
||||
this.saveOnEdit = true
|
||||
this.displayGoButtons = true;
|
||||
this.showTypeMenu = true;
|
||||
this.clickHandler = this.showEditor;
|
||||
this.blurHandler = this.hideEditor;
|
||||
|
@ -90,7 +87,6 @@
|
|||
this.clickable = true;
|
||||
this.editable = true;
|
||||
this.saveOnEdit = false;
|
||||
this.displayGoButtons = false;
|
||||
this.showTypeMenu = true;
|
||||
this.clickHandler = this.showEditor;
|
||||
this.blurHandler = this.hideEditor;
|
||||
|
@ -230,111 +226,6 @@
|
|||
'document.getBindingParent(this).clickHandler(this)');
|
||||
}
|
||||
|
||||
if (this.displayGoButtons) {
|
||||
// Enable/disable "View =>" button
|
||||
testView: try {
|
||||
var viewButton = document.getElementById('view-button');
|
||||
|
||||
viewButton.removeAttribute('viewSnapshot');
|
||||
viewButton.removeAttribute('viewURL');
|
||||
viewButton.setAttribute('label',
|
||||
Zotero.getString('pane.item.goToURL.online.label'));
|
||||
viewButton.setAttribute('tooltiptext',
|
||||
Zotero.getString('pane.item.goToURL.online.tooltip'));
|
||||
|
||||
var spec = false, validURI = false;
|
||||
|
||||
var uri = Components.classes["@mozilla.org/network/standard-url;1"].
|
||||
createInstance(Components.interfaces.nsIURI);
|
||||
|
||||
// First try to find a snapshot matching the item's URL field
|
||||
var snapID = this.item.getBestAttachment();
|
||||
if (snapID) {
|
||||
spec = Zotero.Items.get(snapID).getLocalFileURL();
|
||||
uri.spec = spec;
|
||||
if (!uri.scheme || uri.scheme != 'file') {
|
||||
snapID = false;
|
||||
spec = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If that fails, try the URL field itself
|
||||
if (!spec) {
|
||||
spec = this.item.getField('url');
|
||||
uri.spec = spec;
|
||||
if (!(uri.scheme && (uri.host || uri.scheme == 'file'))) {
|
||||
spec = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If that fails, try the DOI field
|
||||
if (!spec) {
|
||||
var doi = this.item.getField('DOI');
|
||||
if (doi && typeof val == 'String') {
|
||||
// Pull out DOI, in case there's a prefix
|
||||
doi = Zotero.Utilities.cleanDOI(doi);;
|
||||
if (doi) {
|
||||
spec = "http://dx.doi.org/" + encodeURIComponent(doi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!spec) {
|
||||
break testView;
|
||||
}
|
||||
|
||||
validURI = true;
|
||||
|
||||
if (snapID) {
|
||||
viewButton.setAttribute('label',
|
||||
Zotero.getString('pane.item.goToURL.snapshot.label'));
|
||||
viewButton.setAttribute('tooltiptext',
|
||||
Zotero.getString('pane.item.goToURL.snapshot.tooltip'));
|
||||
viewButton.setAttribute('viewSnapshot', snapID);
|
||||
}
|
||||
else {
|
||||
viewButton.setAttribute('viewURL', spec);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug(e);
|
||||
}
|
||||
viewButton.setAttribute('disabled', !validURI);
|
||||
|
||||
// Enable/disable "Locate =>" button
|
||||
switch (this.item.itemTypeID) {
|
||||
// DEBUG: handle descendents of these types as well?
|
||||
case Zotero.ItemTypes.getID('book'):
|
||||
case Zotero.ItemTypes.getID('bookSection'):
|
||||
case Zotero.ItemTypes.getID('journalArticle'):
|
||||
case Zotero.ItemTypes.getID('thesis'):
|
||||
var openURL = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
var openURL = false;
|
||||
}
|
||||
|
||||
var locateButton = document.getElementById('locate-button');
|
||||
|
||||
// TODO: move Locate service logic to separate interface
|
||||
var wayback = this._itemHasURL();
|
||||
if (wayback) {
|
||||
locateButton.setAttribute('type', 'menu');
|
||||
locateButton.setAttribute('disabled', false);
|
||||
document.getElementById('locate-service-openurl').disabled = !openURL;
|
||||
}
|
||||
else {
|
||||
locateButton.removeAttribute('type');
|
||||
locateButton.disabled = !openURL;
|
||||
}
|
||||
|
||||
this._id('go-buttons').hidden = false;
|
||||
}
|
||||
else {
|
||||
this._id('go-buttons').hidden = true;
|
||||
}
|
||||
|
||||
// Item type menu
|
||||
if (this.showTypeMenu) {
|
||||
// Build item type menu if it hasn't been built yet
|
||||
|
@ -452,7 +343,7 @@
|
|||
label.setAttribute("isButton", true);
|
||||
// TODO: make getFieldValue non-private and use below instead
|
||||
label.setAttribute("onclick", "ZoteroPane.loadURI(this.nextSibling.firstChild ? this.nextSibling.firstChild.nodeValue : this.nextSibling.value, event)");
|
||||
label.setAttribute("tooltiptext", Zotero.getString('pane.item.goToURL.online.tooltip'));
|
||||
label.setAttribute("tooltiptext", Zotero.getString('locate.online.tooltip'));
|
||||
}
|
||||
else if (fieldName == 'DOI' && val && typeof val == 'string') {
|
||||
// Pull out DOI, in case there's a prefix
|
||||
|
@ -461,7 +352,7 @@
|
|||
doi = "http://dx.doi.org/" + encodeURIComponent(doi);
|
||||
label.setAttribute("isButton", true);
|
||||
label.setAttribute("onclick", "ZoteroPane.loadURI('" + doi + "', event)");
|
||||
label.setAttribute("tooltiptext", Zotero.getString('pane.item.goToURL.online.tooltip'));
|
||||
label.setAttribute("tooltiptext", Zotero.getString('locate.online.tooltip'));
|
||||
}
|
||||
}
|
||||
else if (fieldName == 'abstractNote') {
|
||||
|
@ -567,16 +458,6 @@
|
|||
</method>
|
||||
|
||||
|
||||
<method name="_itemHasURL">
|
||||
<body>
|
||||
<![CDATA[
|
||||
var url = this.item.getField('url');
|
||||
return url && url.match && !url.match(/^file:|^zotero:/);
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
|
||||
<method name="buildItemTypeMenu">
|
||||
<body>
|
||||
<![CDATA[
|
||||
|
@ -1079,56 +960,6 @@
|
|||
</method>
|
||||
|
||||
|
||||
<method name="onViewClick">
|
||||
<parameter name="button"/>
|
||||
<parameter name="event"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (button.getAttribute('viewURL')) {
|
||||
ZoteroPane.loadURI(button.getAttribute('viewURL'), event);
|
||||
}
|
||||
else if (button.getAttribute('viewSnapshot')) {
|
||||
ZoteroPane.viewAttachment(button.getAttribute('viewSnapshot'), event);
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
|
||||
<method name="onLocateClick">
|
||||
<parameter name="event"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
// Default OpenURL button
|
||||
if (event.originalTarget.id == 'locate-button') {
|
||||
var url = Zotero.OpenURL.resolve(this.item);
|
||||
if (url) {
|
||||
ZoteroPane.loadURI(url, event);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Menu options
|
||||
switch (event.originalTarget.id) {
|
||||
case 'locate-service-openurl':
|
||||
var url = Zotero.OpenURL.resolve(this.item);
|
||||
if (url) {
|
||||
ZoteroPane.loadURI(url, event);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'locate-service-wayback':
|
||||
var prefix = "http://web.archive.org/web/*/";
|
||||
var url = this.item.getField('url');
|
||||
url = prefix + url;
|
||||
ZoteroPane.loadURI(url, event);
|
||||
break;
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
|
||||
<method name="toggleAbstractExpand">
|
||||
<parameter name="label"/>
|
||||
<body>
|
||||
|
@ -2395,29 +2226,13 @@
|
|||
</menu>
|
||||
</menupopup>
|
||||
</popupset>
|
||||
<hbox id="go-buttons" align="center" hidden="true">
|
||||
<button id="view-button"
|
||||
onfocus="document.getBindingParent(this).ensureElementIsVisible(this)"
|
||||
oncommand="document.getBindingParent(this).onViewClick(this, event)" disabled="false"/>
|
||||
<button id="locate-button" label="&zotero.toolbar.openURL.label;"
|
||||
onfocus="document.getBindingParent(this).ensureElementIsVisible(this)"
|
||||
type="menu"
|
||||
oncommand="document.getBindingParent(this).onLocateClick(event)">
|
||||
<menupopup>
|
||||
<menuitem id="locate-service-openurl" label="Library Lookup" tooltiptext="&zotero.toolbar.openURL.tooltip;"/>
|
||||
<menuitem id="locate-service-wayback" label="Wayback Machine"/>
|
||||
</menupopup>
|
||||
</button>
|
||||
</hbox>
|
||||
<hbox align="center" hidden="true">
|
||||
</hbox>
|
||||
<grid flex="1">
|
||||
<columns>
|
||||
<column/>
|
||||
<column flex="1"/>
|
||||
</columns>
|
||||
<rows id="dynamic-fields" flex="1">
|
||||
<row>
|
||||
<row class="zotero-item-first-row">
|
||||
<label value="&zotero.items.itemType;:"/>
|
||||
<menulist class="zotero-clicky" id="item-type-menu" oncommand="document.getBindingParent(this).changeTypeTo(this.value, this)" flex="1"
|
||||
onfocus="document.getBindingParent(this).ensureElementIsVisible(this)"
|
||||
|
|
277
chrome/content/zotero/locateManager.xul
Normal file
277
chrome/content/zotero/locateManager.xul
Normal file
|
@ -0,0 +1,277 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2009 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
-->
|
||||
<!DOCTYPE prefwindow SYSTEM "chrome://zotero/locale/preferences.dtd">
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
|
||||
<?xml-stylesheet href="chrome://zotero/skin/preferences.css"?>
|
||||
|
||||
<!--
|
||||
|
||||
To add a new preference:
|
||||
1) Add a new <preference> to <preferences>
|
||||
2) Add a XUL control with a 'preference' attribute
|
||||
3) (Optional) Add additional setup/change logic to preferences.js
|
||||
4) (Optional) To add an observer for a preference change,
|
||||
add an appropriate case in the switch statement
|
||||
in Zotero.Prefs.observe()
|
||||
|
||||
-->
|
||||
<prefwindow id="zotero-locate-manager-prefs" title="&zotero.preferences.title;" onload="refreshLocateEnginesList()"
|
||||
windowtype="zotero:pref" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<prefpane id="zotero-prefpane-locate"
|
||||
label="&zotero.preferences.prefpane.locate;"
|
||||
image="chrome://zotero/skin/prefs-styles.png">
|
||||
<!-- TODO: pic for locate pane -->
|
||||
<!-- TODO: create labels in dtd -->
|
||||
|
||||
<preferences>
|
||||
<preference id="pref-locate-activeEngines" name="extensions.zotero.locate.activeEngines" type="string"/>
|
||||
</preferences>
|
||||
|
||||
<groupbox flex="1">
|
||||
<caption label="&zotero.preferences.locate.locateEngineManager;"/>
|
||||
|
||||
<label id="locateEngineDescription" width="45em" style="font-size: 10px">
|
||||
&zotero.preferences.locate.locateEnginedescription;
|
||||
</label>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<hbox>
|
||||
<tree flex="1" id="locateManager" hidecolumnpicker="true" rows="10"
|
||||
onselect="document.getElementById('locateManager-delete').disabled = undefined"
|
||||
editable="false">
|
||||
<treecols>
|
||||
<treecol type="checkbox" id="locateManager-checkbox" editable="true" flex="0.5"/>
|
||||
<treecol id="locateManager-name" label="&zotero.preferences.locate.name;" flex="1"/>
|
||||
<treecol id="locateManager-description" label="&zotero.preferences.locate.description;" flex="2"/>
|
||||
</treecols>
|
||||
<treechildren id="locateManager-rows"/>
|
||||
</tree>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<hbox align="center">
|
||||
<hbox pack="start" flex="1">
|
||||
<button label="Toggle" onclick="toggleLocateEngines()" flex="1"/>
|
||||
<button id="locateManager-restoreDefaults" label="&zotero.preferences.locate.restoreDefaults;" onclick="restoreDefaultLocateEngines()" flex="1"/>
|
||||
</hbox>
|
||||
<hbox pack="end" flex="2">
|
||||
<button disabled="true" id="locateManager-delete" label="-" onclick="deleteLocateEngine()" flex="0.5"/>
|
||||
</hbox>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<label id="addLocateEngineDescription" style="font-size: 10px; width: 45em; height: 6em">
|
||||
&zotero.preferences.locate.addDescription;
|
||||
</label>
|
||||
</groupbox>
|
||||
</prefpane>
|
||||
|
||||
<script src="chrome://zotero/content/include.js"></script>
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
function treeClick(event) {
|
||||
// We only care about primary button double and triple clicks
|
||||
if (!event || (event.detail != 2 && event.detail != 3) || event.button != 0) {
|
||||
return;
|
||||
}
|
||||
var t = event.originalTarget;
|
||||
|
||||
if (t.localName != 'treechildren') {
|
||||
return;
|
||||
}
|
||||
|
||||
var tree = t.parentNode;
|
||||
|
||||
var row = {}, col = {}, obj = {};
|
||||
var cell = tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, obj);
|
||||
|
||||
var treechildren = document.getElementById('locateManager-rows');
|
||||
var treeitem = treechildren.children[row.value];
|
||||
|
||||
treeitem.engine.hidden = !treeitem.engine.hidden;
|
||||
|
||||
refreshLocateEnginesList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the list of locate engines in the locate pane
|
||||
* @param {String} name of locate engine to select
|
||||
*/
|
||||
function refreshLocateEnginesList() {
|
||||
var tree = document.getElementById('locateManager');
|
||||
var treechildren = document.getElementById('locateManager-rows');
|
||||
|
||||
// add click listener
|
||||
tree.addEventListener("click", treeClick, false);
|
||||
|
||||
// store ranges
|
||||
var nRanges = tree.view.selection.getRangeCount();
|
||||
var start = {};
|
||||
var end = {};
|
||||
var ranges = [];
|
||||
for(var i=0; i<nRanges; i++) {
|
||||
tree.view.selection.getRangeAt(i, start, end);
|
||||
ranges.push([start.value, end.value]);
|
||||
}
|
||||
|
||||
// clear tree
|
||||
while (treechildren.hasChildNodes()) {
|
||||
treechildren.removeChild(treechildren.firstChild);
|
||||
}
|
||||
|
||||
// repopulate tree with available engines
|
||||
var engines = Zotero.LocateManager.getEngines();
|
||||
var i = 0;
|
||||
for each(var engine in engines) {
|
||||
var treeitem = document.createElement('treeitem');
|
||||
var treerow = document.createElement('treerow');
|
||||
var checkboxCell = document.createElement('treecell');
|
||||
var nameCell = document.createElement('treecell');
|
||||
var descriptionCell = document.createElement('treecell');
|
||||
|
||||
treeitem.engine = engine;
|
||||
nameCell.setAttribute('label', engine.name);
|
||||
descriptionCell.setAttribute('label', engine.description);
|
||||
if( !engine.hidden ) {
|
||||
checkboxCell.setAttribute('value', 'true');
|
||||
}
|
||||
|
||||
treerow.appendChild(checkboxCell);
|
||||
treerow.appendChild(nameCell);
|
||||
treerow.appendChild(descriptionCell);
|
||||
treeitem.appendChild(treerow);
|
||||
treechildren.appendChild(treeitem);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
// restore ranges
|
||||
for each(var range in ranges) {
|
||||
if(range[1] <= engines.length-1) {
|
||||
tree.view.selection.rangedSelect(range[0], range[1], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new Locate Engine to the locate pane
|
||||
**/
|
||||
/*
|
||||
function addLocateEngine() {
|
||||
// alert(Zotero.LocateManager.activeLocateEngines.join(" || "));
|
||||
var textbox = document.getElementById('locate-add-textbox');
|
||||
Zotero.LocateManager.addLocateEngine(textbox.value);
|
||||
|
||||
refreshLocateEnginesList();
|
||||
}
|
||||
*/
|
||||
|
||||
function toggleLocateEngines() {
|
||||
// get selected engines names
|
||||
var tree = document.getElementById('locateManager');
|
||||
var treeItems = tree.lastChild.childNodes;
|
||||
var engineNames = [];
|
||||
var start = {};
|
||||
var end = {};
|
||||
var nRanges = tree.view.selection.getRangeCount();
|
||||
var numStatuses = 0;
|
||||
var engineStatusesSum = 0;
|
||||
for(var i=0; i<nRanges; i++) {
|
||||
tree.view.selection.getRangeAt(i, start, end);
|
||||
for(var j=start.value; j<=end.value; j++) {
|
||||
var engineStatus = treeItems[j].engine.hidden ? 0 : 1;
|
||||
numStatuses += 1;
|
||||
engineStatusesSum += engineStatus;
|
||||
}
|
||||
}
|
||||
|
||||
var hidden;
|
||||
switch( engineStatusesSum ) {
|
||||
case 0:
|
||||
// all off, turn all on
|
||||
hidden = false;
|
||||
break;
|
||||
|
||||
case numStatuses:
|
||||
// all on, turn all off
|
||||
hidden = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
// some on, some off. turn all on
|
||||
hidden = false;
|
||||
}
|
||||
|
||||
[engine.hidden = hidden for each(engine in Zotero.LocateManager.getEngines())];
|
||||
|
||||
refreshLocateEnginesList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes selected Locate Engines from the locate pane
|
||||
**/
|
||||
function deleteLocateEngine() {
|
||||
// get selected engines names
|
||||
var tree = document.getElementById('locateManager');
|
||||
var treeItems = tree.lastChild.childNodes;
|
||||
var engineNames = [];
|
||||
var start = {};
|
||||
var end = {};
|
||||
var nRanges = tree.view.selection.getRangeCount();
|
||||
for(var i=0; i<nRanges; i++) {
|
||||
tree.view.selection.getRangeAt(i, start, end);
|
||||
for(var j=start.value; j<=end.value; j++) {
|
||||
Zotero.LocateManager.removeEngine(treeItems[j].engine);
|
||||
}
|
||||
}
|
||||
|
||||
for(var i=0; i<engineNames.length; i++) {
|
||||
Zotero.LocateManager.removeLocateEngine(engineNames[i]);
|
||||
}
|
||||
|
||||
tree.view.selection.clearSelection();
|
||||
refreshLocateEnginesList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores Default Locate Engines
|
||||
**/
|
||||
function restoreDefaultLocateEngines() {
|
||||
Zotero.LocateManager.restoreDefaultLocateEngines();
|
||||
refreshLocateEnginesList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</prefwindow>
|
317
chrome/content/zotero/locateMenu.js
Normal file
317
chrome/content/zotero/locateMenu.js
Normal file
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2009 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
/*
|
||||
* This object contains the various functions for the interface
|
||||
*/
|
||||
var Zotero_LocateMenu = new function() {
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ios", "@mozilla.org/network/io-service;1", "nsIIOService");
|
||||
|
||||
/**
|
||||
* Create a new menuitem XUL element
|
||||
*/
|
||||
function _createMenuItem( label, id, tooltiptext ) {
|
||||
var menuitem = document.createElement("menuitem");
|
||||
menuitem.setAttribute("label", label);
|
||||
if(id) menuitem.setAttribute("id", id);
|
||||
if(tooltiptext) menuitem.setAttribute("tooltiptext", tooltiptext);
|
||||
|
||||
return menuitem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get snapshot IDs for items
|
||||
*/
|
||||
function _getSnapshotIDs(items) {
|
||||
var ids = [];
|
||||
for each(var item in items) {
|
||||
if(item.isNote()) continue;
|
||||
var snapID = (item.isAttachment() ? item.id : item.getBestAttachment());
|
||||
if(!snapID) continue;
|
||||
var spec = Zotero.Items.get(snapID).getLocalFileURL();
|
||||
if(!spec) continue;
|
||||
var uri = Zotero_LocateMenu.ios.newURI(spec, null, null);
|
||||
if(!uri || uri.scheme != 'file') continue;
|
||||
ids.push(snapID);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URLs for items
|
||||
*/
|
||||
function _getURLs(items, includeDOIs) {
|
||||
var urls = [];
|
||||
for each(var item in items) {
|
||||
if(item.isNote()) continue;
|
||||
var url = null;
|
||||
|
||||
// try url field
|
||||
var urlField = item.getField('url');
|
||||
if(urlField) {
|
||||
var uri = Zotero_LocateMenu.ios.newURI(urlField, null, null);
|
||||
if(uri && (uri.host || !uri.scheme !== 'file')) {
|
||||
url = urlField;
|
||||
}
|
||||
}
|
||||
|
||||
if(includeDOIs) {
|
||||
if(!url) {
|
||||
// try DOI field
|
||||
var doi = item.getField('DOI');
|
||||
if(doi && typeof doi === "string") {
|
||||
doi = Zotero.Utilities.cleanDOI(doi);
|
||||
if(doi) url = "http://dx.doi.org/" + encodeURIComponent(doi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(url) urls.push(url);
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any locate engines that can be installed from the current page
|
||||
*/
|
||||
function _getInstallableLocateEngines() {
|
||||
var locateEngines = [];
|
||||
if(!Zotero_Browser) return locateEngines;
|
||||
|
||||
var links = Zotero_Browser.tabbrowser.selectedBrowser.contentDocument.getElementsByTagName("link");
|
||||
for each(var link in links) {
|
||||
if(!link.getAttribute) continue;
|
||||
var rel = link.getAttribute("rel");
|
||||
if(rel && rel === "search") {
|
||||
var type = link.getAttribute("type");
|
||||
if(type && type === "application/x-openurl-opensearchdescription+xml") {
|
||||
var label = link.getAttribute("title");
|
||||
if(label) {
|
||||
if(Zotero.LocateManager.getEngineByName(label)) {
|
||||
label = 'Update "'+label+'"';
|
||||
} else {
|
||||
label = 'Add "'+label+'"';
|
||||
}
|
||||
} else {
|
||||
label = 'Add Locate Engine';
|
||||
}
|
||||
|
||||
locateEngines.push({'label':label,
|
||||
'href':link.getAttribute("href"),
|
||||
'image':Zotero_Browser.tabbrowser.selectedTab.image});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return locateEngines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear and build the locate menu
|
||||
*/
|
||||
this.buildLocateMenu = function() {
|
||||
var locateMenu = document.getElementById('zotero-tb-locate-menu');
|
||||
|
||||
// clear menu
|
||||
while(locateMenu.childElementCount > 0) {
|
||||
locateMenu.removeChild(locateMenu.firstChild);
|
||||
}
|
||||
|
||||
var selectedItems = [item for each(item in ZoteroPane.getSelectedItems()) if(!item.isNote())];
|
||||
|
||||
if(selectedItems.length) {
|
||||
// get snapshot IDs and URLs
|
||||
var allURLs = _getURLs(selectedItems, true);
|
||||
var realURLs = _getURLs(selectedItems);
|
||||
|
||||
if(selectedItems.length == 1 && _getSnapshotIDs(selectedItems).length) {
|
||||
// add view snapshot
|
||||
var menuitem = _createMenuItem(Zotero.getString("locate.snapshot.label"),
|
||||
"zotero-locate-snapshot", Zotero.getString("locate.snapshot.tooltip"));
|
||||
locateMenu.appendChild(menuitem);
|
||||
menuitem.addEventListener("command", this.openItemSnapshot, false);
|
||||
}
|
||||
|
||||
if(allURLs.length) {
|
||||
// add view online
|
||||
var menuitem = _createMenuItem(Zotero.getString("locate.online.label"),
|
||||
"zotero-locate-online", Zotero.getString("locate.online.tooltip"));
|
||||
locateMenu.appendChild(menuitem);
|
||||
menuitem.addEventListener("command", this.openItemURL, false);
|
||||
}
|
||||
|
||||
// add library lookup to any item
|
||||
var menuitem = _createMenuItem(Zotero.getString("locate.libraryLookup.label"),
|
||||
"zotero-locate-service-openurl", Zotero.getString("locate.libraryLookup.tooltip"));
|
||||
locateMenu.appendChild(menuitem);
|
||||
menuitem.addEventListener("command", this.lookupItem, false);
|
||||
|
||||
// add wayback if there are real URLs
|
||||
if(realURLs.length) {
|
||||
var menuitem = _createMenuItem(Zotero.getString("locate.waybackMachine.label"),
|
||||
"zotero-locate-service-wayback", Zotero.getString("locate.waybackMachine.tooltip"));
|
||||
locateMenu.appendChild(menuitem);
|
||||
menuitem.addEventListener("command", this.waybackItem, false);
|
||||
}
|
||||
|
||||
var customEngines = Zotero.LocateManager.getVisibleEngines();
|
||||
if(customEngines.length) {
|
||||
locateMenu.appendChild(document.createElement("menuseparator"));
|
||||
|
||||
// add engines to menu
|
||||
for each(var engine in customEngines) {
|
||||
// require a submission for at least one selected item
|
||||
var canSubmit = false;
|
||||
for each(var item in selectedItems) {
|
||||
if(engine.getItemSubmission(item)) {
|
||||
canSubmit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(canSubmit) {
|
||||
var menuitem = _createMenuItem(engine.name, null, engine.description);
|
||||
menuitem.setAttribute("class", "menuitem-iconic");
|
||||
menuitem.setAttribute("image", engine.icon);
|
||||
locateMenu.appendChild(menuitem);
|
||||
menuitem.addEventListener("command", this.locateItem, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// add "no items selected"
|
||||
menuitem = _createMenuItem(Zotero.getString("pane.item.selected.zero"), "no-items-selected");
|
||||
locateMenu.appendChild(menuitem);
|
||||
menuitem.disabled = true;
|
||||
}
|
||||
|
||||
// add installable locate menus, if there are any
|
||||
if(window.Zotero_Browser) {
|
||||
var installableLocateEngines = _getInstallableLocateEngines();
|
||||
} else {
|
||||
var installableLocateEngines = [];
|
||||
}
|
||||
|
||||
if(installableLocateEngines.length) {
|
||||
locateMenu.appendChild(document.createElement("menuseparator"));
|
||||
|
||||
for each(var locateEngine in installableLocateEngines) {
|
||||
var menuitem = document.createElement("menuitem");
|
||||
menuitem.setAttribute("label", locateEngine.label);
|
||||
menuitem.setAttribute("image", locateEngine.image);
|
||||
menuitem.zoteroLocateInfo = locateEngine;
|
||||
menuitem.addEventListener("command", this.addLocateEngine, false);
|
||||
|
||||
locateMenu.appendChild(menuitem);
|
||||
}
|
||||
}
|
||||
|
||||
// add manage menu item
|
||||
locateMenu.appendChild(document.createElement("menuseparator"));
|
||||
|
||||
var menuitem = document.createElement("menuitem");
|
||||
menuitem = _createMenuItem(Zotero.getString("locate.manageLocateEngines"), "zotero-manage-locate-menu");
|
||||
menuitem.addEventListener("command", this.openLocateEngineManager, false);
|
||||
locateMenu.appendChild(menuitem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open snapshots for selected items
|
||||
*/
|
||||
this.openItemSnapshot = function(event) {
|
||||
ZoteroPane.viewAttachment(_getSnapshotIDs(ZoteroPane.getSelectedItems())[0], event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open URLs for selected items
|
||||
*/
|
||||
this.openItemURL = function(event) {
|
||||
ZoteroPane.loadURI(_getURLs(ZoteroPane.getSelectedItems(), true), event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform library lookup of selected items
|
||||
*/
|
||||
this.lookupItem = function(event) {
|
||||
var urls = [];
|
||||
for each(var item in ZoteroPane.getSelectedItems()) {
|
||||
var url = Zotero.OpenURL.resolve(item);
|
||||
if(url) urls.push(url);
|
||||
}
|
||||
ZoteroPane.loadURI(urls, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform library lookup of selected items
|
||||
*/
|
||||
this.waybackItem = function(event) {
|
||||
ZoteroPane.loadURI(["http://web.archive.org/web/*/"+url
|
||||
for each(url in _getURLs(ZoteroPane.getSelectedItems()))], event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate selected items
|
||||
*/
|
||||
this.locateItem = function(event) {
|
||||
var selectedItems = ZoteroPane.getSelectedItems();
|
||||
|
||||
// find selected engine
|
||||
var selectedEngine = Zotero.LocateManager.getEngineByName(event.target.label);
|
||||
if(!selectedEngine) throw "Selected locate engine not found";
|
||||
|
||||
var urls = [];
|
||||
var postDatas = [];
|
||||
for each(var item in selectedItems) {
|
||||
var submission = selectedEngine.getItemSubmission(item);
|
||||
urls.push(submission.uri.spec);
|
||||
postDatas.push(submission.postData);
|
||||
}
|
||||
|
||||
Zotero.debug("Loading using "+selectedEngine.name);
|
||||
Zotero.debug(urls);
|
||||
ZoteroPane.loadURI(urls, event, postDatas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new locate engine
|
||||
*/
|
||||
this.addLocateEngine = function(event) {
|
||||
Zotero.LocateManager.addEngine(event.target.zoteroLocateInfo.href,
|
||||
Components.interfaces.nsISearchEngine.TYPE_OPENSEARCH,
|
||||
event.target.zoteroLocateInfo.image, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the locate manager
|
||||
*/
|
||||
this.openLocateEngineManager = function(event) {
|
||||
window.openDialog('chrome://zotero/content/locateManager.xul',
|
||||
'Zotero Locate Engine Manager',
|
||||
'chrome,centerscreen'
|
||||
);
|
||||
}
|
||||
}
|
578
chrome/content/zotero/xpcom/locateManager.js
Normal file
578
chrome/content/zotero/xpcom/locateManager.js
Normal file
|
@ -0,0 +1,578 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2009 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
Zotero.LocateManager = new function() {
|
||||
const LOCATE_FILE_NAME = "engines.json";
|
||||
const LOCATE_DIR_NAME = "locate";
|
||||
|
||||
var _jsonFile;
|
||||
var _locateEngines;
|
||||
var _ios;
|
||||
var _timer;
|
||||
|
||||
/**
|
||||
* Read locateEngines JSON file to initialize locate manager
|
||||
*/
|
||||
this.init = function() {
|
||||
_ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
|
||||
_jsonFile = _getLocateFile();
|
||||
|
||||
if(_jsonFile.exists()) {
|
||||
_locateEngines = [new LocateEngine(engine)
|
||||
for each(engine in JSON.parse(Zotero.File.getContents(_jsonFile)))];
|
||||
} else {
|
||||
this.restoreDefaultEngines();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new search engine
|
||||
* confirm parameter is currently ignored
|
||||
*/
|
||||
this.addEngine = function(engineURL, dataType, iconURL, confirm) {
|
||||
if(dataType !== Components.interfaces.nsISearchEngine.TYPE_OPENSEARCH) {
|
||||
throw "LocateManager supports only OpenSearch engines";
|
||||
}
|
||||
|
||||
Zotero.HTTP.doGet(engineURL, function(xmlhttp) {
|
||||
var engine = new LocateEngine();
|
||||
engine.initWithXML(xmlhttp.responseText, iconURL);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all default search engines (not currently used)
|
||||
*/
|
||||
this.getDefaultEngines = function() [new LocateEngine(engine)
|
||||
for each(engine in JSON.parse(Zotero.File.getContents(_getDefaultFile())))];
|
||||
|
||||
/**
|
||||
* Returns an array of all search engines
|
||||
*/
|
||||
this.getEngines = function() _locateEngines.slice(0);
|
||||
|
||||
/**
|
||||
* Returns an array of all search engines visible that should be visible in the dropdown
|
||||
*/
|
||||
this.getVisibleEngines = function() [engine for each(engine in _locateEngines) if(!engine.hidden)];
|
||||
|
||||
/**
|
||||
* Returns an engine with a specific name
|
||||
*/
|
||||
this.getEngineByName = function(engineName) {
|
||||
engineName = engineName.toLowerCase();
|
||||
for each(var engine in _locateEngines) if(engine.name.toLowerCase() == engineName) return engine;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first engine with a specific alias
|
||||
*/
|
||||
this.getEngineByAlias = function(engineAlias) {
|
||||
engineAlias = engineAlias.toLowerCase();
|
||||
for each(var engine in _locateEngines) if(engine.alias.toLowerCase() == engineAlias) return engine;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves an engine in the list
|
||||
*/
|
||||
this.moveEngine = function(engine, newIndex) {
|
||||
this.removeEngine(engine);
|
||||
_locateEngines.splice(newIndex, engine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an engine from the list
|
||||
*/
|
||||
this.removeEngine = function(engine) {
|
||||
var oldIndex = _locateEngines.indexOf(engine);
|
||||
if(oldIndex === -1) throw "Engine is not currently listed";
|
||||
_locateEngines.splice(oldIndex, 1);
|
||||
engine._removeIcon();
|
||||
_serializeLocateEngines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore default engines by copying file from extension dir
|
||||
*/
|
||||
this.restoreDefaultEngines = function() {
|
||||
// get locate dir
|
||||
var locateDir = _getLocateDirectory();
|
||||
|
||||
// remove old locate dir
|
||||
if(locateDir.exists()) locateDir.remove(true);
|
||||
|
||||
// create new locate dir
|
||||
locateDir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0700);
|
||||
|
||||
// copy default file to new locate dir
|
||||
_getDefaultFile().copyTo(locateDir, LOCATE_FILE_NAME);
|
||||
|
||||
// reread locate engines
|
||||
this.init();
|
||||
|
||||
// reload icons for default locate engines
|
||||
for each(var engine in this.getEngines()) engine._updateIcon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the engines to disk; called from the nsITimer spawned by _serializeLocateEngines
|
||||
*/
|
||||
this.notify = function() {
|
||||
Zotero.File.putContents(_jsonFile, JSON.stringify(_locateEngines, null, "\t"));
|
||||
_timer = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the JSON file containing engine info
|
||||
*/
|
||||
function _getLocateFile() {
|
||||
var locateDir = _getLocateDirectory();
|
||||
locateDir.append(LOCATE_FILE_NAME);
|
||||
return locateDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the dir containing the JSON file and engine icons
|
||||
*/
|
||||
function _getLocateDirectory() {
|
||||
var locateDir = Zotero.getZoteroDirectory();
|
||||
locateDir.append(LOCATE_DIR_NAME);
|
||||
return locateDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the JSON file containing the engine info for the default engines
|
||||
*/
|
||||
function _getDefaultFile() {
|
||||
var defaultFile = Zotero.getInstallDirectory();
|
||||
defaultFile.append(LOCATE_FILE_NAME);
|
||||
return defaultFile;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes the engines to disk when the current block is finished executing
|
||||
*/
|
||||
function _serializeLocateEngines() {
|
||||
if(_timer) return;
|
||||
_timer = Components.classes["@mozilla.org/timer;1"].
|
||||
createInstance(Components.interfaces.nsITimer);
|
||||
_timer.initWithCallback(Zotero.LocateManager, 0, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to call to attach to watch engine properties and perform deferred serialization
|
||||
*/
|
||||
function _watchLocateEngineProperties(id, oldval, newval) {
|
||||
if(oldval !== newval) _serializeLocateEngines();
|
||||
return newval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an engine icon is downloaded to write it to disk
|
||||
*/
|
||||
function _engineIconLoaded(iconBytes, engine, contentType) {
|
||||
const iconExtensions = {
|
||||
"image/png":"png",
|
||||
"image/jpeg":"jpg",
|
||||
"image/gif":"gif",
|
||||
"image/x-icon":"ico"
|
||||
};
|
||||
|
||||
// ensure there is an icon
|
||||
if(!iconBytes) throw "Icon could not be retrieved for "+engine.name;
|
||||
|
||||
// ensure there is an extension
|
||||
var extension = iconExtensions[contentType.toLowerCase()];
|
||||
if(!extension) throw "Invalid MIME type "+contentType+" for icon for engine "+engine.name;
|
||||
|
||||
// remove old icon
|
||||
engine._removeIcon();
|
||||
|
||||
// find a good place to put the icon file
|
||||
var sanitizedAlias = engine.name.replace(/[^\w _]/g, "");
|
||||
var iconFile = _getLocateDirectory();
|
||||
iconFile.append(sanitizedAlias + "." + extension);
|
||||
if(iconFile.exists()) {
|
||||
for(var i=0; iconFile.exists(); i++) {
|
||||
iconFile = iconFile.parent;
|
||||
iconFile.append(sanitizedAlias + "_" + i + "." + extension);
|
||||
}
|
||||
}
|
||||
|
||||
// write the icon to the file
|
||||
var fos = Components.classes["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
fos.init(iconFile, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
|
||||
var bos = Components.classes["@mozilla.org/binaryoutputstream;1"].
|
||||
createInstance(Components.interfaces.nsIBinaryOutputStream);
|
||||
bos.setOutputStream(fos);
|
||||
bos.writeByteArray(iconBytes, iconBytes.length);
|
||||
bos.close();
|
||||
|
||||
// get the URI of the icon
|
||||
engine.icon = _ios.newFileURI(iconFile).spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a parameter in our list
|
||||
*
|
||||
* Supported parameters include
|
||||
* - all standard OpenURL parameters, identified by any OpenURL namespace
|
||||
* - "version", "identifier", and "format" identified by the OpenURL ctx namespace
|
||||
* - "openURL" identified by the Zotero namespace (= the whole openURL)
|
||||
* - "year" identified by the Zotero namespace
|
||||
* - any Zotero field identified by the Zotero namespace
|
||||
*/
|
||||
function _lookupParam(item, itemOpenURL, engine, nsPrefix, param) {
|
||||
const OPENURL_ITEM_PREFIXES = [
|
||||
"info:ofi/fmt:kev:mtx:journal",
|
||||
"info:ofi/fmt:kev:mtx:book",
|
||||
"info:ofi/fmt:kev:mtx:patent",
|
||||
"info:ofi/fmt:kev:mtx:sch_svc",
|
||||
"info:ofi/fmt:kev:mtx:dissertation"
|
||||
];
|
||||
|
||||
const OPENURL_CONTEXT_MAPPINGS = {
|
||||
"version":"ctx_ver",
|
||||
"identifier":"rfr_id",
|
||||
"format":"rft_val_fmt"
|
||||
};
|
||||
|
||||
if(nsPrefix) {
|
||||
var ns = engine._urlNamespaces[nsPrefix];
|
||||
if(!ns) return false;
|
||||
} else {
|
||||
if(param === "searchTerms") return [item.getField("title")];
|
||||
return false;
|
||||
}
|
||||
|
||||
if(OPENURL_ITEM_PREFIXES.indexOf(ns) !== -1) {
|
||||
// take a normal "title," even though we don't use it, because it is valid (but not
|
||||
// preferred) OpenURL
|
||||
if(param === "title") {
|
||||
var title = item.getField("title");
|
||||
return (title ? [encodeURIComponent(title)] : false);
|
||||
}
|
||||
|
||||
if(!itemOpenURL["rft."+param]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return [encodeURIComponent(val) for each(val in itemOpenURL["rft."+param])];
|
||||
} else if(ns === "info:ofi/fmt:kev:mtx:ctx") {
|
||||
if(!OPENURL_CONTEXT_MAPPINGS[param] || !itemOpenURL[OPENURL_CONTEXT_MAPPINGS[param]]) {
|
||||
return false;
|
||||
}
|
||||
return [encodeURIComponent(val) for each(val in itemOpenURL[OPENURL_CONTEXT_MAPPINGS[param]])];
|
||||
} else if(ns === "http://www.zotero.org/namespaces/openSearch#") {
|
||||
if(param === "openURL") {
|
||||
return [Zotero.OpenURL.createContextObject(item, "1.0")];
|
||||
} else if(param === "year") {
|
||||
return (itemOpenURL["rft.date"] ? [itemOpenURL["rft.date"][0].substr(0, 4)] : false);
|
||||
} else {
|
||||
var result = item.getField(param);
|
||||
return (result ? [encodeURIComponent(result)] : false);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Theoretically implements nsISearchSubmission
|
||||
*/
|
||||
var LocateSubmission = function(uri, postData) {
|
||||
this.uri = _ios.newURI(uri, null, null);
|
||||
this.postData = postData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* Constructs a new LocateEngine
|
||||
* @param {Object} [obj] The locate engine, in parsed form, as it was serialized to JSON
|
||||
*/
|
||||
var LocateEngine = function(obj) {
|
||||
this.alias = this.name = "Untitled";
|
||||
this.description = this._urlTemplate = this.icon = null;
|
||||
this.hidden = false;
|
||||
this._urlParams = [];
|
||||
|
||||
if(obj) for(var prop in obj) this[prop] = obj[prop];
|
||||
|
||||
// Queue deferred serialization whenever a property is modified
|
||||
for each(var prop in ["alias", "name", "description", "icon", "hidden"]) {
|
||||
this.watch(prop, _watchLocateEngineProperties);
|
||||
}
|
||||
}
|
||||
|
||||
LocateEngine.prototype = {
|
||||
/**
|
||||
* Initializes an engine with a string and an iconURL to use if none is defined in the file
|
||||
*/
|
||||
"initWithXML":function(xmlStr, iconURL) {
|
||||
const OPENSEARCH_NAMESPACES = [
|
||||
// These are the official namespaces
|
||||
"http://a9.com/-/spec/opensearch/1.1/",
|
||||
"http://a9.com/-/spec/opensearch/1.0/",
|
||||
// These were also in nsSearchService.js
|
||||
"http://a9.com/-/spec/opensearchdescription/1.1/",
|
||||
"http://a9.com/-/spec/opensearchdescription/1.0/"
|
||||
];
|
||||
|
||||
var xml = Zotero.Styles.cleanXML(xmlStr);
|
||||
if(OPENSEARCH_NAMESPACES.indexOf(xml.namespace()) === "-1") {
|
||||
throw "Invalid namespace";
|
||||
}
|
||||
|
||||
default xml namespace = xml.namespace();
|
||||
|
||||
// get simple attributes
|
||||
this.alias = xml.ShortName.toString();
|
||||
this.name = xml.LongName.toString();
|
||||
if(!this.name) this.name = this.alias;
|
||||
this.description = xml.Description.toString();
|
||||
|
||||
// get the URL template
|
||||
this._urlTemplate = undefined;
|
||||
for each(var urlTag in xml.Url.(@type.toLowerCase() == "text/html")) {
|
||||
if(urlTag.@rel == undefined || urlTag.@rel == "results") {
|
||||
this._urlTemplate = urlTag.@template.toString();
|
||||
break;
|
||||
}
|
||||
this._method = urlTag.@method.toUpperCase() === "POST" ? "POST" : "GET";
|
||||
}
|
||||
|
||||
// TODO: better error handling
|
||||
if(!this._urlTemplate) throw "No URL found for required content type";
|
||||
|
||||
// get namespaces
|
||||
this._urlNamespaces = {};
|
||||
for each(var ns in urlTag.inScopeNamespaces()) {
|
||||
this._urlNamespaces[ns.prefix] = ns.uri;
|
||||
}
|
||||
|
||||
// get params
|
||||
this._urlParams = [];
|
||||
for each(var param in urlTag.Param) {
|
||||
this._urlParams[param.@name.toString()] = param.@value.toString();
|
||||
}
|
||||
|
||||
// find the icon
|
||||
this._iconSourceURI = iconURL;
|
||||
for each(var img in xml.Image) {
|
||||
if((img.@width == undefined && img.@height == undefined)
|
||||
|| (img.@width.toString() == "16" && img.@height.toString() == "16")) {
|
||||
this._iconSourceURI = img.toString();
|
||||
}
|
||||
}
|
||||
|
||||
if(this._iconSourceURI) {
|
||||
// begin fetching the icon if necesssary
|
||||
this._updateIcon();
|
||||
}
|
||||
|
||||
// delete any old engine with the same name
|
||||
var engine = Zotero.LocateManager.getEngineByName(this.name);
|
||||
if(engine) Zotero.LocateManager.removeEngine(engine);
|
||||
|
||||
// add and serialize the new engine
|
||||
_locateEngines.push(this);
|
||||
_serializeLocateEngines();
|
||||
},
|
||||
|
||||
"getItemSubmission":function(item, responseType) {
|
||||
if(responseType && responseType !== "text/html") {
|
||||
throw "LocateManager supports only responseType text/html";
|
||||
}
|
||||
|
||||
var itemAsOpenURL = Zotero.OpenURL.createContextObject(item, "1.0", true);
|
||||
|
||||
// do substitutions
|
||||
var me = this;
|
||||
var abort = false;
|
||||
var url = this._urlTemplate.replace(/{(?:([^}:]+):)?([^}:?]+)(\?)?}/g, function(all, nsPrefix, param, required) {
|
||||
var result = _lookupParam(item, itemAsOpenURL, me, nsPrefix, param, required);
|
||||
if(result) {
|
||||
return result[0];
|
||||
} else {
|
||||
if(required) { // if no param and it wasn't optional, return
|
||||
return "";
|
||||
} else {
|
||||
abort = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if(abort) return null;
|
||||
|
||||
// handle params
|
||||
var paramsToAdd = [];
|
||||
for(var param in this._urlParams) {
|
||||
var m = this._urlParams[param].match(/^{(?:([^}:]+):)?([^}:?]+)(\?)?}$/);
|
||||
if(!m) {
|
||||
paramsToAdd.push(encodeURIComponent(param)+"="+encodeURIComponent(this._urlParams[param]));
|
||||
} else {
|
||||
var result = _lookupParam(item, itemAsOpenURL, me, m[1], m[2]);
|
||||
if(result) {
|
||||
paramsToAdd = paramsToAdd.concat([encodeURIComponent(param)+"="+encodeURIComponent(val) for(val in result)]);
|
||||
} else if(m[3]) { // if no param and it wasn't optional, return
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// attach params
|
||||
if(paramsToAdd.length) {
|
||||
if(this._method === "POST") {
|
||||
var postData = paramsToAdd.join("&");
|
||||
} else {
|
||||
var postData = null;
|
||||
if(url.indexOf("?") === -1) {
|
||||
url += "?"+paramsToAdd.join("&");
|
||||
} else {
|
||||
url += "&"+paramsToAdd.join("&");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new LocateSubmission(url, postData);
|
||||
},
|
||||
|
||||
"_removeIcon":function() {
|
||||
if(!this.icon) return;
|
||||
var uri = _ios.newURI(this.icon, null, null);
|
||||
var file = uri.QueryInterface(Components.interfaces.nsIFileURL).file;
|
||||
if(file.exists()) file.remove(null);
|
||||
},
|
||||
|
||||
"_updateIcon":function() {
|
||||
// create new channel
|
||||
var uri = _ios.newURI(this._iconSourceURI, null, null);
|
||||
if(uri.scheme !== "http" && uri.scheme !== "https" && uri.scheme !== "ftp") return;
|
||||
var chan = _ios.newChannelFromURI(uri);
|
||||
var listener = new loadListener(chan, this, _engineIconLoaded);
|
||||
chan.notificationCallbacks = listener;
|
||||
chan.asyncOpen(listener, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ripped from nsSearchService.js
|
||||
*/
|
||||
function loadListener(aChannel, aEngine, aCallback) {
|
||||
this._channel = aChannel;
|
||||
this._bytes = [];
|
||||
this._engine = aEngine;
|
||||
this._callback = aCallback;
|
||||
}
|
||||
|
||||
loadListener.prototype = {
|
||||
_callback: null,
|
||||
_channel: null,
|
||||
_countRead: 0,
|
||||
_engine: null,
|
||||
_stream: null,
|
||||
|
||||
QueryInterface: function SRCH_loadQI(aIID) {
|
||||
if (aIID.equals(Ci.nsISupports) ||
|
||||
aIID.equals(Ci.nsIRequestObserver) ||
|
||||
aIID.equals(Ci.nsIStreamListener) ||
|
||||
aIID.equals(Ci.nsIChannelEventSink) ||
|
||||
aIID.equals(Ci.nsIInterfaceRequestor) ||
|
||||
aIID.equals(Ci.nsIBadCertListener2) ||
|
||||
aIID.equals(Ci.nsISSLErrorListener) ||
|
||||
// See FIXME comment below
|
||||
aIID.equals(Ci.nsIHttpEventSink) ||
|
||||
aIID.equals(Ci.nsIProgressEventSink) ||
|
||||
false)
|
||||
return this;
|
||||
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
// nsIRequestObserver
|
||||
onStartRequest: function SRCH_loadStartR(aRequest, aContext) {
|
||||
this._stream = Cc["@mozilla.org/binaryinputstream;1"].
|
||||
createInstance(Ci.nsIBinaryInputStream);
|
||||
},
|
||||
|
||||
onStopRequest: function SRCH_loadStopR(aRequest, aContext, aStatusCode) {
|
||||
var requestFailed = !Components.isSuccessCode(aStatusCode);
|
||||
if (!requestFailed && (aRequest instanceof Ci.nsIHttpChannel))
|
||||
requestFailed = !aRequest.requestSucceeded;
|
||||
|
||||
if (requestFailed || this._countRead == 0) {
|
||||
// send null so the callback can deal with the failure
|
||||
this._callback(null, this._engine, this._channel.contentType);
|
||||
} else
|
||||
this._callback(this._bytes, this._engine, this._channel.contentType);
|
||||
this._channel = null;
|
||||
this._engine = null;
|
||||
},
|
||||
|
||||
// nsIStreamListener
|
||||
onDataAvailable: function SRCH_loadDAvailable(aRequest, aContext,
|
||||
aInputStream, aOffset,
|
||||
aCount) {
|
||||
this._stream.setInputStream(aInputStream);
|
||||
|
||||
// Get a byte array of the data
|
||||
this._bytes = this._bytes.concat(this._stream.readByteArray(aCount));
|
||||
this._countRead += aCount;
|
||||
},
|
||||
|
||||
// nsIChannelEventSink
|
||||
onChannelRedirect: function SRCH_loadCRedirect(aOldChannel, aNewChannel,
|
||||
aFlags) {
|
||||
this._channel = aNewChannel;
|
||||
},
|
||||
|
||||
// nsIInterfaceRequestor
|
||||
getInterface: function SRCH_load_GI(aIID) {
|
||||
return this.QueryInterface(aIID);
|
||||
},
|
||||
|
||||
// nsIBadCertListener2
|
||||
notifyCertProblem: function SRCH_certProblem(socketInfo, status, targetSite) {
|
||||
return true;
|
||||
},
|
||||
|
||||
// nsISSLErrorListener
|
||||
notifySSLError: function SRCH_SSLError(socketInfo, error, targetSite) {
|
||||
return true;
|
||||
},
|
||||
|
||||
// FIXME: bug 253127
|
||||
// nsIHttpEventSink
|
||||
onRedirect: function (aChannel, aNewChannel) {},
|
||||
// nsIProgressEventSink
|
||||
onProgress: function (aRequest, aContext, aProgress, aProgressMax) {},
|
||||
onStatus: function (aRequest, aContext, aStatus, aStatusArg) {}
|
||||
}
|
||||
}
|
|
@ -89,89 +89,95 @@ Zotero.OpenURL = new function() {
|
|||
/*
|
||||
* Generates an OpenURL ContextObject from an item
|
||||
*/
|
||||
function createContextObject(item, version) {
|
||||
function createContextObject(item, version, asObj) {
|
||||
var entries = (asObj ? {} : []);
|
||||
|
||||
function _mapTag(data, tag, dontAddPrefix) {
|
||||
if(!data) return;
|
||||
|
||||
if(version === "1.0" && !dontAddPrefix) tag = "rft."+tag;
|
||||
|
||||
if(asObj) {
|
||||
if(!entries[tag]) entries[tag] = [];
|
||||
entries[tag].push(data);
|
||||
} else {
|
||||
entries.push(tag+"="+encodeURIComponent(data));
|
||||
}
|
||||
}
|
||||
|
||||
if(item.toArray) {
|
||||
item = item.toArray();
|
||||
}
|
||||
|
||||
var identifiers = new Array();
|
||||
if(item.DOI) {
|
||||
identifiers.push("info:doi/"+item.DOI);
|
||||
}
|
||||
if(item.ISBN) {
|
||||
identifiers.push("urn:isbn:"+item.ISBN);
|
||||
}
|
||||
// find pmid
|
||||
const pmidRe = /(?:\n|^)PMID:\s*(\d+)/g;
|
||||
var pmid = pmidRe.exec(item.extra);
|
||||
if(pmid) pmid = pmid[1];
|
||||
|
||||
// encode ctx_ver (if available) and identifiers
|
||||
// TODO identifiers may need to be encoded as follows:
|
||||
// rft_id=info:doi/<the-url-encoded-doi>
|
||||
// rft_id=http://<the-rest-of-the-url-encoded-url>
|
||||
// encode ctx_ver (if available) and encode identifiers
|
||||
if(version == "0.1") {
|
||||
var co = "sid=Zotero:"+encodeURIComponent(Zotero.version);
|
||||
|
||||
for(var i=0; i<identifiers.length; i++) {
|
||||
co += "&id="+encodeURIComponent(identifiers[i]);
|
||||
}
|
||||
_mapTag("Zotero:2", "sid", true);
|
||||
if(item.DOI) _mapTag("doi:"+item.DOI, "id", true);
|
||||
if(item.ISBN) _mapTag(item.ISBN, "isbn", true);
|
||||
if(pmid) _mapTag("pmid:"+pmid, "id", true);
|
||||
} else {
|
||||
var co = "url_ver=Z39.88-2004&ctx_ver=Z39.88-2004"+
|
||||
"&rfr_id="+encodeURIComponent("info:sid/zotero.org:"+Zotero.version);
|
||||
|
||||
for(var i=0; i<identifiers.length; i++) {
|
||||
co += "&rft_id="+encodeURIComponent(identifiers[i])
|
||||
}
|
||||
_mapTag("Z39.88-2004", "url_ver", true);
|
||||
_mapTag("Z39.88-2004", "ctx_ver", true);
|
||||
_mapTag("info:sid/zotero.org:2", "rfr_id", true);
|
||||
if(item.DOI) _mapTag("info:doi/"+item.DOI, "rft_id", true);
|
||||
if(item.ISBN) _mapTag("urn:isbn:"+item.ISBN, "rft_id", true);
|
||||
if(pmid) _mapTag("info:pmid/"+pmid, "rft_id", true);
|
||||
}
|
||||
|
||||
// encode genre and item-specific data
|
||||
if(item.itemType == "journalArticle") {
|
||||
if(version == "0.1") {
|
||||
co += "&genre=article";
|
||||
} else {
|
||||
co += "&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Ajournal&rft.genre=article";
|
||||
if(version === "1.0") {
|
||||
_mapTag("info:ofi/fmt:kev:mtx:journal", "rft_val_fmt", true);
|
||||
}
|
||||
if(item.title) co += _mapTag(item.title, "atitle", version)
|
||||
if(item.publicationTitle) co += _mapTag(item.publicationTitle, (version == "0.1" ? "title" : "jtitle"), version)
|
||||
if(item.journalAbbreviation) co += _mapTag(item.journalAbbreviation, "stitle", version);
|
||||
if(item.volume) co += _mapTag(item.volume, "volume", version);
|
||||
if(item.issue) co += _mapTag(item.issue, "issue", version);
|
||||
_mapTag("article", "genre");
|
||||
|
||||
if(item.title) _mapTag(item.title, "atitle")
|
||||
if(item.publicationTitle) _mapTag(item.publicationTitle, (version == "0.1" ? "title" : "jtitle"))
|
||||
if(item.journalAbbreviation) _mapTag(item.journalAbbreviation, "stitle");
|
||||
if(item.volume) _mapTag(item.volume, "volume");
|
||||
if(item.issue) _mapTag(item.issue, "issue");
|
||||
} else if(item.itemType == "book" || item.itemType == "bookSection" || item.itemType == "conferencePaper") {
|
||||
if(version == "0.1") {
|
||||
co += "&genre=book";
|
||||
} else {
|
||||
co += "&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook";
|
||||
if(version === "1.0") {
|
||||
_mapTag("info:ofi/fmt:kev:mtx:book", "rft_val_fmt", true);
|
||||
}
|
||||
|
||||
if(item.itemType == "book") {
|
||||
co += "&rft.genre=book";
|
||||
if(item.title) co += _mapTag(item.title, (version == "0.1" ? "title" : "btitle"), version);
|
||||
_mapTag("book", "genre");
|
||||
if(item.title) _mapTag(item.title, (version == "0.1" ? "title" : "btitle"));
|
||||
} else if (item.itemType == "conferencePaper") {
|
||||
co += "&rft.genre=proceeding";
|
||||
if(item.title) co += _mapTag(item.title, "atitle", version)
|
||||
if(item.proceedingsTitle) co += _mapTag(item.proceedingsTitle, (version == "0.1" ? "title" : "btitle"), version);
|
||||
_mapTag("proceeding", "genre");
|
||||
if(item.title) _mapTag(item.title, "atitle")
|
||||
if(item.proceedingsTitle) _mapTag(item.proceedingsTitle, (version == "0.1" ? "title" : "btitle"));
|
||||
} else {
|
||||
co += "&rft.genre=bookitem";
|
||||
if(item.title) co += _mapTag(item.title, "atitle", version)
|
||||
if(item.publicationTitle) co += _mapTag(item.publicationTitle, (version == "0.1" ? "title" : "btitle"), version);
|
||||
_mapTag("bookitem", "genre");
|
||||
if(item.title) _mapTag(item.title, "atitle")
|
||||
if(item.publicationTitle) _mapTag(item.publicationTitle, (version == "0.1" ? "title" : "btitle"));
|
||||
}
|
||||
|
||||
if(item.place) co += _mapTag(item.place, "place", version);
|
||||
if(item.publisher) co += _mapTag(item.publisher, "publisher", version)
|
||||
if(item.edition) co += _mapTag(item.edition, "edition", version);
|
||||
if(item.series) co += _mapTag(item.series, "series", version);
|
||||
if(item.place) _mapTag(item.place, "place");
|
||||
if(item.publisher) _mapTag(item.publisher, "publisher")
|
||||
if(item.edition) _mapTag(item.edition, "edition");
|
||||
if(item.series) _mapTag(item.series, "series");
|
||||
} else if(item.itemType == "thesis" && version == "1.0") {
|
||||
co += "&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Adissertation";
|
||||
_mapTag("info:ofi/fmt:kev:mtx:dissertation", "rft_val_fmt", true);
|
||||
|
||||
if(item.title) co += _mapTag(item.title, "title", version);
|
||||
if(item.publisher) co += _mapTag(item.publisher, "inst", version);
|
||||
if(item.type) co += _mapTag(item.type, "degree", version);
|
||||
if(item.title) _mapTag(item.title, "title");
|
||||
if(item.publisher) _mapTag(item.publisher, "inst");
|
||||
if(item.type) _mapTag(item.type, "degree");
|
||||
} else if(item.itemType == "patent" && version == "1.0") {
|
||||
co += "&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Apatent";
|
||||
_mapTag("info:ofi/fmt:kev:mtx:patent", "rft_val_fmt", true);
|
||||
|
||||
if(item.title) co += _mapTag(item.title, "title", version);
|
||||
if(item.assignee) co += _mapTag(item.assignee, "assignee", version);
|
||||
if(item.patentNumber) co += _mapTag(item.patentNumber, "number", version);
|
||||
if(item.title) _mapTag(item.title, "title");
|
||||
if(item.assignee) _mapTag(item.assignee, "assignee");
|
||||
if(item.patentNumber) _mapTag(item.patentNumber, "number");
|
||||
|
||||
if(item.issueDate) {
|
||||
co += _mapTag(Zotero.Date.strToISO(item.issueDate), "date", version);
|
||||
_mapTag(Zotero.Date.strToISO(item.issueDate), "date");
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
|
@ -181,32 +187,41 @@ Zotero.OpenURL = new function() {
|
|||
// encode first author as first and last
|
||||
var firstCreator = item.creators[0];
|
||||
if(item.itemType == "patent") {
|
||||
co += _mapTag(firstCreator.firstName, "invfirst", version);
|
||||
co += _mapTag(firstCreator.lastName, "invlast", version);
|
||||
_mapTag(firstCreator.firstName, "invfirst");
|
||||
_mapTag(firstCreator.lastName, "invlast");
|
||||
} else {
|
||||
if(firstCreator.isInstitution) {
|
||||
co += _mapTag(firstCreator.lastName, "aucorp", version);
|
||||
_mapTag(firstCreator.lastName, "aucorp");
|
||||
} else {
|
||||
co += _mapTag(firstCreator.firstName, "aufirst", version);
|
||||
co += _mapTag(firstCreator.lastName, "aulast", version);
|
||||
_mapTag(firstCreator.firstName, "aufirst");
|
||||
_mapTag(firstCreator.lastName, "aulast");
|
||||
}
|
||||
}
|
||||
|
||||
// encode subsequent creators as au
|
||||
for(var i=0; i<identifiers.length; i++) {
|
||||
co += _mapTag((creators[i].firstName ? creators[i].firstName+" " : "")+creators[i].lastName, (item.itemType == "patent" ? "inventor" : "au"), version);
|
||||
for(var i=0; i<item.creators.length; i++) {
|
||||
_mapTag((item.creators[i].firstName ? item.creators[i].firstName+" " : "")+
|
||||
item.creators[i].lastName, (item.itemType == "patent" ? "inventor" : "au"));
|
||||
}
|
||||
}
|
||||
|
||||
if(item.date) {
|
||||
co += _mapTag(Zotero.Date.strToISO(item.date), (item.itemType == "patent" ? "appldate" : "date"), version);
|
||||
_mapTag(Zotero.Date.strToISO(item.date), (item.itemType == "patent" ? "appldate" : "date"));
|
||||
}
|
||||
if(item.pages) co += _mapTag(item.pages, "pages", version);
|
||||
if(item.numPages) co += _mapTag(item.numPages, "tpages", version);
|
||||
if(item.ISBN) co += _mapTag(item.ISBN, "isbn", version);
|
||||
if(item.ISSN) co += _mapTag(item.ISSN, "issn", version);
|
||||
if(item.pages) {
|
||||
_mapTag(item.pages, "pages");
|
||||
var pages = item.pages.split("-");
|
||||
if(pages.length >= 1) {
|
||||
_mapTag(pages[0], "spage");
|
||||
if(pages.length >= 2) _mapTag(pages[1], "epage");
|
||||
}
|
||||
}
|
||||
if(item.numPages) _mapTag(item.numPages, "tpages");
|
||||
if(item.ISBN) _mapTag(item.ISBN, "isbn");
|
||||
if(item.ISSN) _mapTag(item.ISSN, "issn");
|
||||
|
||||
return co;
|
||||
if(asObj) return entries;
|
||||
return entries.join("&");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -445,19 +460,4 @@ Zotero.OpenURL = new function() {
|
|||
|
||||
return item;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to map tags for generating OpenURL contextObjects
|
||||
*/
|
||||
function _mapTag(data, tag, version) {
|
||||
if(data) {
|
||||
if(version == "0.1") {
|
||||
return "&"+tag+"="+encodeURIComponent(data);
|
||||
} else {
|
||||
return "&rft."+tag+"="+encodeURIComponent(data);
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -601,6 +601,9 @@ var Zotero = new function(){
|
|||
// Initialize keyboard shortcuts
|
||||
Zotero.Keys.init();
|
||||
|
||||
// Initialize Locate Manager
|
||||
Zotero.LocateManager.init();
|
||||
|
||||
this.initialized = true;
|
||||
Zotero.debug("Initialized in "+((new Date()).getTime() - start)+" ms");
|
||||
|
||||
|
|
|
@ -2416,51 +2416,57 @@ 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(uri, event, data) {
|
||||
// Ignore javascript: and data: URIs
|
||||
if (uri.match(/^(javascript|data):/)) {
|
||||
return;
|
||||
function loadURI(uris, event, data) {
|
||||
if(typeof uris === "string") {
|
||||
uris = [uris];
|
||||
}
|
||||
|
||||
if (Zotero.isStandalone && uri.match(/^https?/)) {
|
||||
var io = Components.classes['@mozilla.org/network/io-service;1']
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
var uri = io.newURI(uri, null, null);
|
||||
var handler = Components.classes['@mozilla.org/uriloader/external-protocol-service;1']
|
||||
.getService(Components.interfaces.nsIExternalProtocolService)
|
||||
.getProtocolHandlerInfo('http');
|
||||
handler.preferredAction = Components.interfaces.nsIHandlerInfo.useSystemDefault;
|
||||
handler.launchWithURI(uri, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Open in new tab
|
||||
var openInNewTab = event && (event.metaKey || (!Zotero.isMac && event.ctrlKey));
|
||||
if (event && event.shiftKey) {
|
||||
window.open(uri, "zotero-loaded-page",
|
||||
"menubar=yes,location=yes,toolbar=yes,personalbar=yes,resizable=yes,scrollbars=yes,status=yes");
|
||||
}
|
||||
else if (openInNewTab || !window.loadURI) {
|
||||
// if no gBrowser, find it
|
||||
if(!gBrowser) {
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var browserWindow = wm.getMostRecentWindow("navigator:browser");
|
||||
var gBrowser = browserWindow.gBrowser;
|
||||
for each(var uri in uris) {
|
||||
// Ignore javascript: and data: URIs
|
||||
if (uri.match(/^(javascript|data):/)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// load in a new tab
|
||||
var tab = gBrowser.addTab(uri);
|
||||
var browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
if (event && event.shiftKey || !openInNewTab) {
|
||||
// if shift key is down, or we are opening in a new tab because there is no loadURI,
|
||||
// select new tab
|
||||
gBrowser.selectedTab = tab;
|
||||
if (Zotero.isStandalone && uri.match(/^https?/)) {
|
||||
var io = Components.classes['@mozilla.org/network/io-service;1']
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
var uri = io.newURI(uri, null, null);
|
||||
var handler = Components.classes['@mozilla.org/uriloader/external-protocol-service;1']
|
||||
.getService(Components.interfaces.nsIExternalProtocolService)
|
||||
.getProtocolHandlerInfo('http');
|
||||
handler.preferredAction = Components.interfaces.nsIHandlerInfo.useSystemDefault;
|
||||
handler.launchWithURI(uri, null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Open in new tab
|
||||
var openInNewTab = event && (event.metaKey || (!Zotero.isMac && event.ctrlKey));
|
||||
if (event && event.shiftKey && !openInNewTab) {
|
||||
window.open(uri, "zotero-loaded-page",
|
||||
"menubar=yes,location=yes,toolbar=yes,personalbar=yes,resizable=yes,scrollbars=yes,status=yes");
|
||||
}
|
||||
else if (openInNewTab || !window.loadURI || uris.length > 1) {
|
||||
// if no gBrowser, find it
|
||||
if(!gBrowser) {
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var browserWindow = wm.getMostRecentWindow("navigator:browser");
|
||||
var gBrowser = browserWindow.gBrowser;
|
||||
}
|
||||
|
||||
// load in a new tab
|
||||
var tab = gBrowser.addTab(uri);
|
||||
var browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
if (event && event.shiftKey || !openInNewTab) {
|
||||
// if shift key is down, or we are opening in a new tab because there is no loadURI,
|
||||
// select new tab
|
||||
gBrowser.selectedTab = tab;
|
||||
}
|
||||
}
|
||||
else {
|
||||
window.loadURI(uri);
|
||||
}
|
||||
}
|
||||
else {
|
||||
window.loadURI(uri);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3351,7 +3357,6 @@ var ZoteroPane = new function()
|
|||
"zotero-error-report", "chrome,centerscreen,modal", io);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Display an error message saying that an error has occurred and Firefox
|
||||
* needs to be restarted.
|
||||
|
@ -3408,4 +3413,5 @@ var ZoteroPane = new function()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -43,6 +43,7 @@
|
|||
<script src="timelineInterface.js"/>
|
||||
<script src="recognizePDF.js"/>
|
||||
<script src="browser.js"/>
|
||||
<script src="locateMenu.js"/>
|
||||
|
||||
<commandset id="mainCommandSet">
|
||||
<command id="cmd_zotero_search" oncommand="ZoteroPane.search();"/>
|
||||
|
@ -334,38 +335,45 @@
|
|||
<splitter id="zotero-view-splitter" resizebefore="closest" resizeafter="closest"/>
|
||||
|
||||
<vbox id="zotero-item-pane" persist="width">
|
||||
<hbox class="toolbar" align="center" pack="end">
|
||||
<hbox id="zotero-tb-sync-progress-box" hidden="true" align="center">
|
||||
<toolbarbutton id="zotero-tb-sync-storage-cancel"
|
||||
tooltiptext="Cancel Storage Sync"
|
||||
oncommand="Zotero.Sync.Storage.QueueManager.cancel()"/>
|
||||
<progressmeter id="zotero-tb-sync-progress" mode="determined"
|
||||
value="0" tooltip="zotero-tb-sync-progress-tooltip">
|
||||
</progressmeter>
|
||||
<tooltip id="zotero-tb-sync-progress-tooltip" noautohide="true">
|
||||
<grid>
|
||||
<columns>
|
||||
<column/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<label value="&zotero.sync.storage.progress;"/>
|
||||
<label id="zotero-tb-sync-progress-tooltip-progress"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="&zotero.sync.storage.downloads;"/>
|
||||
<label
|
||||
id="zotero-tb-sync-progress-tooltip-downloads"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="&zotero.sync.storage.uploads;"/>
|
||||
<label
|
||||
id="zotero-tb-sync-progress-tooltip-uploads"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</tooltip>
|
||||
<hbox class="toolbar" align="center">
|
||||
<hbox align="center" pack="start" flex="1">
|
||||
<toolbarbutton id="zotero-tb-locate" class="zotero-tb-button" tooltiptext="&zotero.toolbar.openURL.label;" type="menu">
|
||||
<menupopup id="zotero-tb-locate-menu" onpopupshowing="Zotero_LocateMenu.buildLocateMenu()"/>
|
||||
</toolbarbutton>
|
||||
</hbox>
|
||||
<hbox align="center" pack="end">
|
||||
<hbox id="zotero-tb-sync-progress-box" hidden="true" align="center">
|
||||
<toolbarbutton id="zotero-tb-sync-storage-cancel"
|
||||
tooltiptext="Cancel Storage Sync"
|
||||
oncommand="Zotero.Sync.Storage.QueueManager.cancel()"/>
|
||||
<progressmeter id="zotero-tb-sync-progress" mode="determined"
|
||||
value="0" tooltip="zotero-tb-sync-progress-tooltip">
|
||||
</progressmeter>
|
||||
<tooltip id="zotero-tb-sync-progress-tooltip" noautohide="true">
|
||||
<grid>
|
||||
<columns>
|
||||
<column/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<label value="&zotero.sync.storage.progress;"/>
|
||||
<label id="zotero-tb-sync-progress-tooltip-progress"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="&zotero.sync.storage.downloads;"/>
|
||||
<label
|
||||
id="zotero-tb-sync-progress-tooltip-downloads"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="&zotero.sync.storage.uploads;"/>
|
||||
<label
|
||||
id="zotero-tb-sync-progress-tooltip-uploads"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</tooltip>
|
||||
</hbox>
|
||||
</hbox>
|
||||
<toolbarbutton id="zotero-tb-sync-warning" hidden="true"/>
|
||||
<toolbarbutton id="zotero-tb-sync" class="zotero-tb-button" tooltip="_child"
|
||||
|
|
|
@ -150,6 +150,14 @@
|
|||
|
||||
<!ENTITY zotero.preferences.prefpane.advanced "Advanced">
|
||||
|
||||
<!ENTITY zotero.preferences.prefpane.locate "Locate">
|
||||
<!ENTITY zotero.preferences.locate.locateEngineManager "Article Lookup Engine Manager">
|
||||
<!ENTITY zotero.preferences.locate.description "Description">
|
||||
<!ENTITY zotero.preferences.locate.name "Name">
|
||||
<!ENTITY zotero.preferences.locate.locateEnginedescription "A Lookup Engine extends the capability of the Locate drop down in the Info pane. By enabling Lookup Engines in the list below they will be added to the drop down and can be used to locate resources from your library on the web.">
|
||||
<!ENTITY zotero.preferences.locate.addDescription "To add a Lookup Engine that is not on the list, visit the desired search engine in your browser and select 'Add' from the Firefox Search Bar. When you reopen this preference pane you will have the option to enable the new Lookup Engine.">
|
||||
<!ENTITY zotero.preferences.locate.restoreDefaults "Restore Defaults">
|
||||
|
||||
<!ENTITY zotero.preferences.charset "Character Encoding">
|
||||
<!ENTITY zotero.preferences.charset.importCharset "Import Character Encoding">
|
||||
<!ENTITY zotero.preferences.charset.displayExportOption "Display character encoding option on export">
|
||||
|
|
|
@ -167,10 +167,6 @@ pane.items.interview.manyParticipants = Interview by %S et al.
|
|||
pane.item.selected.zero = No items selected
|
||||
pane.item.selected.multiple = %S items selected
|
||||
|
||||
pane.item.goToURL.online.label = View
|
||||
pane.item.goToURL.online.tooltip = Go to this item online
|
||||
pane.item.goToURL.snapshot.label = View Snapshot
|
||||
pane.item.goToURL.snapshot.tooltip = View snapshot for this item
|
||||
pane.item.changeType.title = Change Item Type
|
||||
pane.item.changeType.text = Are you sure you want to change the item type?\n\nThe following fields will be lost:
|
||||
pane.item.defaultFirstName = first
|
||||
|
@ -709,4 +705,14 @@ rtfScan.saveTitle = Select a location in which to save the formatted file
|
|||
rtfScan.scannedFileSuffix = (Scanned)
|
||||
|
||||
lookup.failure.title = Lookup Failed
|
||||
lookup.failure.description = Zotero could not find a record for the specified identifier. Please verify the identifier and try again.
|
||||
lookup.failure.description = Zotero could not find a record for the specified identifier. Please verify the identifier and try again.
|
||||
|
||||
locate.online.label = View Online
|
||||
locate.online.tooltip = Go to this item online
|
||||
locate.snapshot.label = View Snapshot
|
||||
locate.snapshot.tooltip = View snapshot for this item
|
||||
locate.libraryLookup.label = Library Lookup
|
||||
locate.libraryLookup.tooltip = Look up this item using the selected OpenURL resolver
|
||||
locate.waybackMachine.label = Wayback Machine
|
||||
locate.waybackMachine.tooltip = View an archived version of this item
|
||||
locate.manageLocateEngines = Manage Locate Engines...
|
|
@ -15,24 +15,6 @@ textbox, tagsbox textbox
|
|||
margin-left: 0;
|
||||
}
|
||||
|
||||
#go-buttons button
|
||||
{
|
||||
list-style-image: url('chrome://zotero/skin/toolbar-go-arrow.png');
|
||||
-moz-box-direction: reverse;
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
#go-buttons button#locate-button
|
||||
{
|
||||
-moz-box-direction: normal;
|
||||
}
|
||||
|
||||
|
||||
#go-buttons button[disabled=true]
|
||||
{
|
||||
list-style-image: url('chrome://zotero/skin/toolbar-go-arrow-disabled.png');
|
||||
}
|
||||
|
||||
|
||||
/* DEBUG: this doesn't seem to work, unfortunately
|
||||
label[singleField=false]:after
|
||||
|
|
|
@ -204,6 +204,11 @@
|
|||
list-style-image: url('chrome://zotero/skin/toolbar-advanced-search.png');
|
||||
}
|
||||
|
||||
#zotero-tb-locate
|
||||
{
|
||||
list-style-image: url('chrome://zotero/skin/toolbar-go-arrow.png');
|
||||
}
|
||||
|
||||
#zotero-tb-sync-storage-cancel
|
||||
{
|
||||
list-style-image: url(chrome://zotero/skin/control_stop_blue.png);
|
||||
|
|
|
@ -246,4 +246,15 @@ grid row hbox:first-child
|
|||
#zotero-prefpane-keys checkbox
|
||||
{
|
||||
margin: .75em 0;
|
||||
}
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-checkbox {
|
||||
/* unchecked checkbox treecells. This style MUST come before treechildren::-moz-tree-checkbox(checked) otherwise it won't take effect. */
|
||||
list-style-image: none;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-checkbox(checked){
|
||||
/* css for checked cells. cbox-check.gif isn't available in Firefox 1, 2, and 3 on Mac OS X, so you should specify a URL to an image
|
||||
in your extension or elsewhere. */
|
||||
list-style-image: url("chrome://global/skin/checkbox/cbox-check.gif");
|
||||
}
|
||||
|
|
|
@ -90,6 +90,7 @@ var xpcomFiles = [
|
|||
'integration',
|
||||
'integration_compat',
|
||||
'itemTreeView',
|
||||
'locateManager',
|
||||
'mime',
|
||||
'mimeTypeHandler',
|
||||
'notifier',
|
||||
|
|
43
engines.json
Normal file
43
engines.json
Normal file
|
@ -0,0 +1,43 @@
|
|||
[
|
||||
{
|
||||
"name": "CrossRef Lookup",
|
||||
"alias": "CrossRef",
|
||||
"_urlTemplate": "http://crossref.org/openurl?{z:openURL}&pid=zter:zter321",
|
||||
"description": "CrossRef Search Engine",
|
||||
"hidden": false,
|
||||
"_urlParams": [],
|
||||
"_urlNamespaces": {
|
||||
"z": "http://www.zotero.org/namespaces/openSearch#",
|
||||
"": "http://a9.com/-/spec/opensearch/1.1/"
|
||||
},
|
||||
"_iconSourceURI": "http://crossref.org/favicon.ico"
|
||||
},
|
||||
{
|
||||
"name": "Google Scholar Search",
|
||||
"alias": "Google Scholar",
|
||||
"_urlTemplate": "http://scholar.google.com/scholar?as_q=&as_epq={z:title}&as_occt=title&as_sauthors={rft:aufirst?}+{rft:aulast?}&as_ylo={z:year?}&as_yhi={z:year?}&as_sdt=1.&as_sdtp=on&as_sdtf=&as_sdts=22&",
|
||||
"description": "Google Scholar Search",
|
||||
"hidden": true,
|
||||
"_urlParams": [],
|
||||
"_urlNamespaces": {
|
||||
"rft": "info:ofi/fmt:kev:mtx:journal",
|
||||
"z": "http://www.zotero.org/namespaces/openSearch#",
|
||||
"": "http://a9.com/-/spec/opensearch/1.1/"
|
||||
},
|
||||
"_iconSourceURI": "http://scholar.google.com/favicon.ico"
|
||||
},
|
||||
{
|
||||
"name": "Pubget Lookup",
|
||||
"alias": "Pubget",
|
||||
"_urlTemplate": "http://pubget.com/openurl?rft.title={rft:title}&rft.issue={rft:issue?}&rft.spage={rft:spage?}&rft.epage={rft:epage?}&rft.issn={rft:issn?}&rft.jtitle={rft:stitle?}&doi={z:DOI?}",
|
||||
"description": "Pubget Article Lookup",
|
||||
"hidden": true,
|
||||
"_urlParams": [],
|
||||
"_urlNamespaces": {
|
||||
"rft": "info:ofi/fmt:kev:mtx:journal",
|
||||
"z": "http://www.zotero.org/namespaces/openSearch#",
|
||||
"": "http://a9.com/-/spec/opensearch/1.1/"
|
||||
},
|
||||
"_iconSourceURI": "http://pubget.com/favicon.ico"
|
||||
}
|
||||
]
|
Loading…
Reference in a new issue