Protect against pasting HTML-formatted text into QuickFormat dialog

This commit is contained in:
Simon Kornblith 2013-05-24 00:39:19 -04:00
parent c0f3e3c425
commit a7984916ad
3 changed files with 68 additions and 37 deletions

View file

@ -241,30 +241,11 @@ var Zotero_File_Interface = new function() {
* Imports from clipboard
*/
this.importFromClipboard = function () {
var clip = Components.classes["@mozilla.org/widget/clipboard;1"]
.getService(Components.interfaces.nsIClipboard);
if (!clip.hasDataMatchingFlavors(["text/unicode"], 1, clip.kGlobalClipboard)) {
var str = Zotero.Utilities.Internal.getClipboard("text/unicode");
if(!str) {
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
ps.alert(null, "", Zotero.getString('fileInterface.importClipboardNoDataError'));
return;
}
var trans = Components.classes["@mozilla.org/widget/transferable;1"]
.createInstance(Components.interfaces.nsITransferable);
trans.addDataFlavor("text/unicode");
clip.getData(trans, clip.kGlobalClipboard);
var str = {};
try {
trans.getTransferData("text/unicode", str, {});
str = str.value.QueryInterface(Components.interfaces.nsISupportsString).data;
}
catch (e) {
Zotero.debug(e);
return;
}
if (!str) {
Zotero.debug("No clipboard text to import");
return;
}
var translate = new Zotero.Translate.Import();

View file

@ -22,6 +22,7 @@
***** END LICENSE BLOCK *****
*/
Components.utils.import("resource://gre/modules/Services.jsm");
var Zotero_QuickFormat = new function () {
const pixelRe = /^([0-9]+)px$/
@ -36,10 +37,8 @@ var Zotero_QuickFormat = new function () {
keepSorted, showEditor, referencePanel, referenceBox, referenceHeight = 0,
separatorHeight = 0, currentLocator, currentLocatorLabel, currentSearchTime, dragging,
panel, panelPrefix, panelSuffix, panelSuppressAuthor, panelLocatorLabel, panelLocator,
panelLibraryLink, panelInfo, panelRefersToBubble, panelFrameHeight = 0, accepted = false;
// A variable that contains the timeout object for the latest onKeyPress event
var eventTimeout = null;
panelLibraryLink, panelInfo, panelRefersToBubble, panelFrameHeight = 0, accepted = false,
searchTimeout;
const SHOWN_REFERENCES = 7;
@ -120,6 +119,7 @@ var Zotero_QuickFormat = new function () {
qfb.addEventListener("keypress", _onQuickSearchKeyPress, false);
qfe = qfiDocument.getElementById("quick-format-editor");
qfe.addEventListener("drop", _onBubbleDrop, false);
qfe.addEventListener("paste", _onPaste, false);
}
}
@ -180,11 +180,17 @@ var Zotero_QuickFormat = new function () {
var range = selection.getRangeAt(0);
var node = range.startContainer;
if(node !== range.endContainer || node.nodeType !== Node.TEXT_NODE ) {
return false;
if(node !== range.endContainer) return false;
if(node.nodeType === Node.TEXT_NODE) return node;
// Range could be referenced to the body element
if(node === qfe) {
var offset = range.startOffset;
if(offset !== range.endOffset) return false;
node = qfe.childNodes[Math.min(qfe.childNodes.length-1, offset)];
if(node.nodeType === Node.TEXT_NODE) return node;
}
return node;
return false;
}
/**
@ -193,7 +199,7 @@ var Zotero_QuickFormat = new function () {
*/
function _getEditorContent(clear) {
var node = _getCurrentEditorTextNode();
return node ? node.textContent : false;
return node ? node.wholeText : false;
}
/**
@ -1011,8 +1017,13 @@ var Zotero_QuickFormat = new function () {
}
/**
*
* Reset timer that controls when search takes place. We use this to avoid searching after each
* keypress, since searches can be slow.
*/
function _resetSearchTimer() {
if(searchTimeout) clearTimeout(searchTimeout);
searchTimeout = setTimeout(_quickFormat, 250);
}
/**
* Handle return or escape
@ -1038,9 +1049,7 @@ var Zotero_QuickFormat = new function () {
}
_resize();
if(Zotero_QuickFormat.eventTimeout) clearTimeout(Zotero_QuickFormat.eventTimeout);
Zotero_QuickFormat.eventTimeout = setTimeout(_quickFormat, 250);
_resetSearchTimer();
} else if(keyCode === event.DOM_VK_LEFT || keyCode === event.DOM_VK_RIGHT) {
var right = keyCode === event.DOM_VK_RIGHT,
bubble = _getSelectedBubble(right);
@ -1102,9 +1111,7 @@ var Zotero_QuickFormat = new function () {
};
}
} else {
// Use a timeout so that _quickFormat gets called after update
if(Zotero_QuickFormat.eventTimeout) clearTimeout(Zotero_QuickFormat.eventTimeout);
Zotero_QuickFormat.eventTimeout = setTimeout(_quickFormat, 250);
_resetSearchTimer();
}
}
@ -1163,6 +1170,24 @@ var Zotero_QuickFormat = new function () {
_moveCursorToEnd();
_showCitationProperties(event.currentTarget);
}
/**
* Called when the user attempts to paste
*/
function _onPaste(event) {
event.stopPropagation();
event.preventDefault();
var str = Zotero.Utilities.Internal.getClipboard("text/unicode");
if(str) {
var selection = qfiWindow.getSelection();
var range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(str.replace(/[\r\n]/g, " ").trim()));
range.collapse(false);
_resetSearchTimer();
}
}
/**
* Handle changes to citation properties

View file

@ -199,6 +199,31 @@ Zotero.Utilities.Internal = {
}});
return deferred.promise;
},
/**
* Get string data from the clipboard
* @param {String[]} mimeType MIME type of data to get
* @return {String|null} Clipboard data, or null if none was available
*/
"getClipboard":function(mimeType) {
var clip = Services.clipboard;
if (!clip.hasDataMatchingFlavors([mimeType], 1, clip.kGlobalClipboard)) {
return null;
}
var trans = Components.classes["@mozilla.org/widget/transferable;1"]
.createInstance(Components.interfaces.nsITransferable);
trans.addDataFlavor(mimeType);
clip.getData(trans, clip.kGlobalClipboard);
var str = {};
try {
trans.getTransferData(mimeType, str, {});
str = str.value.QueryInterface(Components.interfaces.nsISupportsString).data;
}
catch (e) {
return null;
}
return str;
}
}