Closes #601, Allow Quick Copy to be site-specific

Closes #560, Method for inserting bibliography/export format into text box on current page

Dragging items to external text apps is also possible now (the one oddity being that the format has to be set at the beginning of the drag session, so if the window's current page matches a site-specific setting, the dragged references will use that format even the if the text is dropped into an external app or another window)
This commit is contained in:
Dan Stillman 2007-04-06 15:54:03 +00:00
parent b6a9c09d85
commit 2a1658228b
12 changed files with 394 additions and 26 deletions

View File

@ -895,8 +895,7 @@ var ZoteroPane = new function()
}
var [mode, format] = Zotero.Prefs.get("export.quickCopy.setting").split('=');
Zotero.debug(mode);
Zotero.debug(format);
if (mode == 'bibliography') {
Zotero_File_Interface.copyItemsToClipboard(items, format);
}

View File

@ -134,14 +134,31 @@ function populateOpenURLResolvers() {
function populateQuickCopyList() {
// Initialize default format drop-down
var formatMenu = document.getElementById("quickCopy-menu");
var listbox = formatMenu.firstChild;
var format = Zotero.Prefs.get("export.quickCopy.setting");
buildQuickCopyFormatDropDown(formatMenu, format);
formatMenu.setAttribute('preference', "pref-quickCopy-setting");
refreshQuickCopySiteList();
}
function buildQuickCopyFormatDropDown(menulist, currentFormat) {
// Prevent Cmd-w from setting "Wikipedia"
menulist.onkeydown = function (event) {
if ((Zotero.isMac && event.metaKey) || event.ctrlKey) {
event.preventDefault();
}
}
var popup = document.createElement('menupopup');
menulist.appendChild(popup);
var itemNode = document.createElement("menuitem");
itemNode.setAttribute("label", Zotero.getString('zotero.preferences.export.quickCopy.bibStyles'));
itemNode.setAttribute("disabled", true);
listbox.appendChild(itemNode);
popup.appendChild(itemNode);
// add styles to list
var styles = Zotero.Cite.getStyles();
@ -150,23 +167,23 @@ function populateQuickCopyList() {
var itemNode = document.createElement("menuitem");
itemNode.setAttribute("value", val);
itemNode.setAttribute("label", styles[i]);
listbox.appendChild(itemNode);
popup.appendChild(itemNode);
if (val == format) {
formatMenu.selectedItem = itemNode;
if (val == currentFormat) {
menulist.selectedItem = itemNode;
}
}
var itemNode = document.createElement("menuitem");
itemNode.setAttribute("label", Zotero.getString('zotero.preferences.export.quickCopy.exportFormats'));
itemNode.setAttribute("disabled", true);
listbox.appendChild(itemNode);
popup.appendChild(itemNode);
// add export formats to list
var translation = new Zotero.Translate("export");
var translators = translation.getTranslators();
for (var i in translators) {
for (var i=0; i<translators.length; i++) {
// Skip RDF formats
switch (translators[i].translatorID) {
case '6e372642-ed9d-4934-b5d1-c11ac758ebb7':
@ -177,14 +194,82 @@ function populateQuickCopyList() {
var itemNode = document.createElement("menuitem");
itemNode.setAttribute("value", val);
itemNode.setAttribute("label", translators[i].label);
listbox.appendChild(itemNode);
popup.appendChild(itemNode);
if (val == format) {
formatMenu.selectedItem = itemNode;
if (val == currentFormat) {
menulist.selectedItem = itemNode;
}
}
formatMenu.setAttribute('preference', "pref-quickCopy-setting");
return popup;
}
function showQuickCopySiteEditor(index) {
var treechildren = document.getElementById('quickCopy-siteSettings-rows');
if (index != undefined && index > -1 && index < treechildren.childNodes.length) {
var treerow = treechildren.childNodes[index].firstChild;
var domain = treerow.childNodes[0].getAttribute('label')
var format = treerow.childNodes[1].getAttribute('label')
}
var format = Zotero.QuickCopy.getSettingFromFormattedName(format);
var io = {domain: domain, format: format, ok: false};
window.openDialog('chrome://zotero/content/quickCopySiteEditor.xul', "zotero-preferences-quickCopySiteEditor", "chrome, modal", io);
if (!io.ok) {
return;
}
if (domain && domain != io.domain) {
Zotero.DB.query("DELETE FROM settings WHERE setting='quickCopySite' AND key=?", [domain]);
}
Zotero.DB.query("REPLACE INTO settings VALUES ('quickCopySite', ?, ?)", [io.domain, io.format]);
refreshQuickCopySiteList();
}
function refreshQuickCopySiteList() {
var treechildren = document.getElementById('quickCopy-siteSettings-rows');
while (treechildren.hasChildNodes()) {
treechildren.removeChild(treechildren.firstChild);
}
var sql = "SELECT key AS domainPath, value AS format FROM settings "
+ "WHERE setting='quickCopySite' ORDER BY domainPath COLLATE NOCASE";
var siteData = Zotero.DB.query(sql);
if (!siteData) {
return;
}
for (var i=0; i<siteData.length; i++) {
var treeitem = document.createElement('treeitem');
var treerow = document.createElement('treerow');
var domainCell = document.createElement('treecell');
var formatCell = document.createElement('treecell');
domainCell.setAttribute('label', siteData[i].domainPath);
var formatted = Zotero.QuickCopy.getFormattedNameFromSetting(siteData[i].format);
formatCell.setAttribute('label', formatted);
treerow.appendChild(domainCell);
treerow.appendChild(formatCell);
treeitem.appendChild(treerow);
treechildren.appendChild(treeitem);
}
}
function deleteSelectedQuickCopySite() {
var tree = document.getElementById('quickCopy-siteSettings');
var treeitem = tree.lastChild.childNodes[tree.currentIndex];
var domainPath = treeitem.firstChild.firstChild.getAttribute('label');
Zotero.DB.query("DELETE FROM settings WHERE setting='quickCopySite' AND key=?", [domainPath]);
refreshQuickCopySiteList();
}
@ -206,6 +291,7 @@ function updateQuickCopyInstructions() {
}
function onOpenURLSelected()
{
var openURLMenu = document.getElementById('openURLMenu');

View File

@ -158,11 +158,31 @@ To add a new preference:
<groupbox>
<caption label="&zotero.preferences.quickCopy.caption;"/>
<label value="&zotero.preferences.quickCopy.outputFormat;" control="quickCopy-menu"/>
<menulist id="quickCopy-menu">
<menupopup/>
</menulist>
<label id="quickCopy-instructions"/>
<vbox>
<label value="&zotero.preferences.quickCopy.defaultOutputFormat;" control="quickCopy-menu"/>
<menulist id="quickCopy-menu"/>
</vbox>
<vbox>
<label value="&zotero.preferences.quickCopy.siteEditor.setings;" control="quickCopy-siteSettings"/>
<tree flex="1" id="quickCopy-siteSettings" hidecolumnpicker="true" rows="6" seltype="single"
ondblclick="showQuickCopySiteEditor(this.currentIndex)"
onkeypress="if (event.keyCode == event.DOM_VK_DELETE) { deleteSelectedQuickCopySite(); }">
<treecols>
<treecol id="quickCopy-urlColumn" label="&zotero.preferences.quickCopy.siteEditor.domainPath;" flex="1"/>
<treecol id="quickCopy-formatColumn" label="&zotero.preferences.quickCopy.siteEditor.outputFormat;" flex="2"/>
</treecols>
<treechildren id="quickCopy-siteSettings-rows"/>
</tree>
<hbox pack="end">
<button label="-" onclick="deleteSelectedQuickCopySite()"/>
<button label="+" onclick="showQuickCopySiteEditor()"/>
</hbox>
</vbox>
<label id="quickCopy-macWarning" hidden="true" value="&zotero.preferences.quickCopy.macWarning;"/>
</groupbox>
</prefpane>

View File

@ -0,0 +1,46 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!DOCTYPE window SYSTEM "chrome://zotero/locale/preferences.dtd">
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="" buttons="cancel,accept"
id="zotero-quickCopySiteEditor"
onload="sizeToContent();"
ondialogaccept="Zotero_QuickCopySiteEditor.onAccept();">
<script src="include.js"/>
<script src="preferences.js"/>
<script>
<![CDATA[
var Zotero_QuickCopySiteEditor = new function () {
this.onAccept = onAccept;
function onAccept() {
var io = window.arguments[0];
io.domain = document.getElementById('zotero-quickCopy-domain').value;
io.format = document.getElementById('zotero-quickCopy-format').value;
io.ok = true;
}
}
]]>
</script>
<vbox id="zotero-preferences-quickCopySiteEditor">
<vbox>
<label value="&zotero.preferences.quickCopy.siteEditor.domainPath; &zotero.preferences.quickCopy.siteEditor.domainPath.example;" control="zotero-quickCopy-domain"/>
<textbox id="zotero-quickCopy-domain"/>
</vbox>
<vbox>
<label value="&zotero.preferences.quickCopy.siteEditor.outputFormat;" control="zotero-quickCopy-format"/>
<menulist id="zotero-quickCopy-format"/>
</vbox>
</vbox>
<script>
<![CDATA[
var io = window.arguments[0];
document.getElementById('zotero-quickCopy-domain').value = io.domain ? io.domain : '';
buildQuickCopyFormatDropDown(document.getElementById('zotero-quickCopy-format'), io.format);
]]>
</script>
</dialog>

View File

@ -570,7 +570,7 @@ Zotero.Item.prototype.setField = function(field, value, loadIn){
var fieldID = Zotero.ItemFields.getID(field);
if (!fieldID){
throw (field + ' is not a valid itemData field.');
throw ('"' + field + '" is not a valid itemData field.');
}
if (loadIn && this.isNote() && field == 110) { // title

View File

@ -1290,8 +1290,47 @@ Zotero.ItemTreeCommandController.prototype.onEvent = function(evt)
*/
Zotero.ItemTreeView.prototype.onDragStart = function (evt,transferData,action)
{
try {
transferData.data=new TransferData();
transferData.data.addDataForFlavour("zotero/item", this.saveSelection());
// Get Quick Copy format for current URL
var url = this._ownerDocument.defaultView.content.location.href;
var format = Zotero.QuickCopy.getFormatFromURL(url);
Zotero.debug("Dragging with format " + Zotero.QuickCopy.getFormattedNameFromSetting(format));
var exportCallback = function(obj, worked) {
if (!worked) {
Zotero.log(Zotero.getString("fileInterface.exportError"), 'warning');
return;
}
var text = obj.output.replace(/\r\n/g, "\n");
transferData.data.addDataForFlavour("text/unicode", text);
}
var items = Zotero.Items.get(this.saveSelection());
var [mode, ] = format.split('=');
if (mode == 'export') {
Zotero.QuickCopy.getContentFromItems(items, format, exportCallback);
}
else if (mode == 'bibliography') {
var content = Zotero.QuickCopy.getContentFromItems(items, format);
transferData.data.addDataForFlavour("text/unicode", content.text);
transferData.data.addDataForFlavour("text/html", content.html);
}
}
catch (e) {
Zotero.debug(e);
}
}
/*

View File

@ -0,0 +1,162 @@
Zotero.QuickCopy = new function() {
this.getFormattedNameFromSetting = getFormattedNameFromSetting;
this.getSettingFromFormattedName = getSettingFromFormattedName;
this.getFormatFromURL = getFormatFromURL;
this.getContentFromItems = getContentFromItems;
var _initialized = false;
var _formattedNames = {};
function getFormattedNameFromSetting(setting) {
if (!_initialized) {
_init();
}
return _formattedNames[setting];
}
function getSettingFromFormattedName(name) {
if (!_initialized) {
_init();
}
for (var setting in _formattedNames) {
if (_formattedNames[setting] == name) {
return setting;
}
}
return '';
}
function getFormatFromURL(url) {
if (!url) {
return Zotero.Prefs.get("export.quickCopy.setting");
}
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var nsIURI = ioService.newURI(url, null, null);
try {
var urlHostPort = nsIURI.hostPort;
var urlPath = nsIURI.path;
}
catch (e) {
return Zotero.Prefs.get("export.quickCopy.setting");
return;
}
var matches = [];
var sql = "SELECT key AS domainPath, value AS format FROM settings "
+ "WHERE setting='quickCopySite' AND key LIKE ?";
var urlDomain = urlHostPort.match(/[^\.]+\.[^\.]+$/);
var rows = Zotero.DB.query(sql, ['%' + urlDomain + '%']);
for each(var row in rows) {
var [domain, path] = row.domainPath.split(/\//);
path = '/' + (path ? path : '');
var re = new RegExp(domain + '$');
if (urlHostPort.match(re) && urlPath.indexOf(path) == 0) {
matches.push({
format: row.format,
domainLength: domain.length,
pathLength: path.length
});
}
}
// Give priority to longer domains, then longer paths
var sort = function(a, b) {
if (a.domainLength > b.domainLength) {
return -1;
}
else if (a.domainLength < b.domainLength) {
return 1;
}
if (a.pathLength > b.pathLength) {
return -1;
}
else if (a.pathLength < b.pathLength) {
return 1;
}
return -1;
}
if (matches.length) {
matches.sort(sort);
return matches[0].format;
}
return Zotero.Prefs.get("export.quickCopy.setting");
}
/*
* Get text and (when applicable) HTML content from items
*
* |items| is an array of Zotero.Item objects
*
* |format| is a Quick Copy format string
* (e.g. "bibliography=http://purl.org/net/xbiblio/csl/styles/apa.csl")
*
* |callback| is only necessary if using an export format and should be
* a function suitable for Zotero.Translate.setHandler, taking parameters
* |obj| and |worked|. The generated content should be placed in obj.output
* and |worked| should be true if the operation is successful.
*
* If bibliography format, the process is synchronous and an object
* contain properties 'text' and 'html' is returned.
*/
function getContentFromItems(items, format, callback) {
var [mode, format] = format.split('=');
if (mode == 'export') {
var translation = new Zotero.Translate("export");
Zotero.debug(items);
translation.setItems(items);
translation.setTranslator(format);
translation.setHandler("done", callback);
translation.translate();
return true;
}
else if (mode == 'bibliography') {
var csl = Zotero.Cite.getStyle(format);
Zotero.debug(items);
csl.preprocessItems(items);
var bibliography = {
text: csl.createBibliography(items, "Text"),
html: csl.createBibliography(items, "HTML")
};
return bibliography;
}
throw ("Invalid mode '" + mode + "' in Zotero.QuickCopy.getContentFromItems()");
}
function _init() {
var translation = new Zotero.Translate("export");
var translators = translation.getTranslators();
// add styles to list
var styles = Zotero.Cite.getStyles();
for (var i in styles) {
_formattedNames['bibliography=' + i] = styles[i];
}
for (var i=0; i<translators.length; i++) {
// Skip RDF formats
switch (translators[i].translatorID) {
case '6e372642-ed9d-4934-b5d1-c11ac758ebb7':
case '14763d24-8ba0-45df-8f52-b8d1108e7ac9':
continue;
}
_formattedNames['export=' + translators[i].translatorID] = translators[i].label;
}
}
}

View File

@ -31,9 +31,12 @@
<!ENTITY zotero.preferences.prefpane.export "Export">
<!ENTITY zotero.preferences.quickCopy.caption "Quick Copy">
<!ENTITY zotero.preferences.quickCopy.outputFormat "Output Format:">
<!ENTITY zotero.preferences.quickCopy.macWarning "Note that rich-text formatting will be lost on Mac OS X.">
<!ENTITY zotero.preferences.quickCopy.defaultOutputFormat "Default Output Format:">
<!ENTITY zotero.preferences.quickCopy.macWarning "Note: Rich-text formatting will be lost on Mac OS X.">
<!ENTITY zotero.preferences.quickCopy.siteEditor.setings "Site-Specific Settings:">
<!ENTITY zotero.preferences.quickCopy.siteEditor.domainPath "Domain/Path">
<!ENTITY zotero.preferences.quickCopy.siteEditor.domainPath.example "(e.g. wikipedia.org)">
<!ENTITY zotero.preferences.quickCopy.siteEditor.outputFormat "Output Format">
<!ENTITY zotero.preferences.prefpane.keys "Shortcut Keys">

View File

@ -295,7 +295,7 @@ zotero.preferences.openurl.resolversFound.singular = %S resolver found
zotero.preferences.openurl.resolversFound.plural = %S resolvers found
zotero.preferences.export.quickCopy.bibStyles = Bibliographic Styles
zotero.preferences.export.quickCopy.exportFormats = Export Formats
zotero.preferences.export.quickCopy.instructions = Select one or more references and press the shortcut key (%S) to copy the references to the clipboard.
zotero.preferences.export.quickCopy.instructions = Quick Copy allows you to copy selected references to the clipboard by pressing a shortcut key (%S) or dragging items into a text box on a web page.
fileInterface.itemsImported = Importing items...
fileInterface.itemsExported = Exporting items...

View File

@ -91,6 +91,10 @@ grid row hbox:first-child
/* Export pane */
#quickCopy-instructions, #zotero-prefpane-export vbox {
margin-bottom: 1em;
}
#quickCopy-menu
{
margin-top: .4em;

View File

@ -58,6 +58,10 @@ Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://zotero/content/xpcom/cite.js");
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://zotero/content/xpcom/quickCopy.js");
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://zotero/content/xpcom/report.js");

View File

@ -1,10 +1,8 @@
-- 28
-- 29
-- This file creates tables containing user-specific data -- any changes
-- to existing tables made here must be mirrored in transition steps in
-- schema.js::_migrateSchema() -- however, new tables can be added by simply
-- adding a CREATE TABLE IF NOT EXISTS statement and incrementing the version
-- number above
-- schema.js::_migrateSchema()
CREATE TABLE IF NOT EXISTS version (
@ -13,6 +11,13 @@ CREATE TABLE IF NOT EXISTS version (
);
CREATE INDEX IF NOT EXISTS schema ON version(schema);
CREATE TABLE IF NOT EXISTS settings (
setting TEXT,
key TEXT,
value,
PRIMARY KEY (setting, key)
);
-- Show or hide pre-mapped fields for system item types
CREATE TABLE IF NOT EXISTS userFieldMask (
itemTypeID INT,