Protect against pasting HTML-formatted text into QuickFormat dialog
This commit is contained in:
parent
c0f3e3c425
commit
a7984916ad
3 changed files with 68 additions and 37 deletions
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue