diff --git a/chrome/content/zotero/tinymce/note.html b/chrome/content/zotero/tinymce/note.html
index 7c899df859..a1c7a975d1 100755
--- a/chrome/content/zotero/tinymce/note.html
+++ b/chrome/content/zotero/tinymce/note.html
@@ -31,7 +31,7 @@
fix_list_elements : true,
fix_table_elements : true,
- /*plugins : "xhtmlxtras",*/
+ plugins : "paste,contextmenu",
// Theme options
theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,sub,sup,|,forecolor,backcolor,|,blockquote,|,link,unlink",
diff --git a/chrome/content/zotero/tinymce/plugins/contextmenu/editor_plugin.js b/chrome/content/zotero/tinymce/plugins/contextmenu/editor_plugin.js
new file mode 100644
index 0000000000..57fb72cc59
--- /dev/null
+++ b/chrome/content/zotero/tinymce/plugins/contextmenu/editor_plugin.js
@@ -0,0 +1,98 @@
+/**
+ * $Id: editor_plugin_src.js 848 2008-05-15 11:54:40Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved.
+ *
+ * Contains modifications by Zotero (commented)
+ */
+
+(function() {
+ var Event = tinymce.dom.Event, each = tinymce.each, DOM = tinymce.DOM;
+
+ tinymce.create('tinymce.plugins.ContextMenu', {
+ init : function(ed) {
+ var t = this;
+
+ t.editor = ed;
+ t.onContextMenu = new tinymce.util.Dispatcher(this);
+
+ ed.onContextMenu.add(function(ed, e) {
+ if (!e.ctrlKey) {
+ t._getMenu(ed).showMenu(e.clientX, e.clientY);
+ Event.add(ed.getDoc(), 'click', hide);
+ Event.cancel(e);
+ }
+ });
+
+ function hide() {
+ if (t._menu) {
+ t._menu.removeAll();
+ t._menu.destroy();
+ Event.remove(ed.getDoc(), 'click', hide);
+ }
+ };
+
+ ed.onMouseDown.add(hide);
+ ed.onKeyDown.add(hide);
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Contextmenu',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/contextmenu',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ _getMenu : function(ed) {
+ var t = this, m = t._menu, se = ed.selection, col = se.isCollapsed(), el = se.getNode() || ed.getBody(), am, p1, p2;
+
+ if (m) {
+ m.removeAll();
+ m.destroy();
+ }
+
+ p1 = DOM.getPos(ed.getContentAreaContainer());
+ p2 = DOM.getPos(ed.getContainer());
+
+ m = ed.controlManager.createDropMenu('contextmenu', {
+ offset_x : p1.x + ed.getParam('contextmenu_offset_x', 0),
+ offset_y : p1.y + ed.getParam('contextmenu_offset_y', 0),
+ constrain : 1
+ });
+
+ t._menu = m;
+
+ m.add({title : 'advanced.cut_desc', icon : 'cut', cmd : 'Cut'}).setDisabled(col);
+ m.add({title : 'advanced.copy_desc', icon : 'copy', cmd : 'Copy'}).setDisabled(col);
+ m.add({title : 'advanced.paste_desc', icon : 'paste', cmd : 'Paste'});
+
+ if ((el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) || !col) {
+ m.addSeparator();
+ m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true});
+ m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'});
+ }
+
+ // Disabled by Dan S./Zotero
+ //m.addSeparator();
+ //m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true});
+
+ m.addSeparator();
+ am = m.addMenu({title : 'contextmenu.align'});
+ am.add({title : 'contextmenu.left', icon : 'justifyleft', cmd : 'JustifyLeft'});
+ am.add({title : 'contextmenu.center', icon : 'justifycenter', cmd : 'JustifyCenter'});
+ am.add({title : 'contextmenu.right', icon : 'justifyright', cmd : 'JustifyRight'});
+ am.add({title : 'contextmenu.full', icon : 'justifyfull', cmd : 'JustifyFull'});
+
+ t.onContextMenu.dispatch(t, m, el, col);
+
+ return m;
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('contextmenu', tinymce.plugins.ContextMenu);
+})();
diff --git a/chrome/content/zotero/tinymce/plugins/paste/editor_plugin.js b/chrome/content/zotero/tinymce/plugins/paste/editor_plugin.js
new file mode 100644
index 0000000000..8f363a5bd5
--- /dev/null
+++ b/chrome/content/zotero/tinymce/plugins/paste/editor_plugin.js
@@ -0,0 +1,512 @@
+/**
+ * $Id: editor_plugin_src.js 1143 2009-05-27 10:05:31Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved.
+ */
+
+(function() {
+ var each = tinymce.each;
+
+ tinymce.create('tinymce.plugins.PastePlugin', {
+ init : function(ed, url) {
+ var t = this, cb;
+
+ t.editor = ed;
+ t.url = url;
+
+ // Setup plugin events
+ t.onPreProcess = new tinymce.util.Dispatcher(t);
+ t.onPostProcess = new tinymce.util.Dispatcher(t);
+
+ // Register default handlers
+ t.onPreProcess.add(t._preProcess);
+ t.onPostProcess.add(t._postProcess);
+
+ // Register optional preprocess handler
+ t.onPreProcess.add(function(pl, o) {
+ ed.execCallback('paste_preprocess', pl, o);
+ });
+
+ // Register optional postprocess
+ t.onPostProcess.add(function(pl, o) {
+ ed.execCallback('paste_postprocess', pl, o);
+ });
+
+ // This function executes the process handlers and inserts the contents
+ function process(o) {
+ var dom = ed.dom;
+
+ // Execute pre process handlers
+ t.onPreProcess.dispatch(t, o);
+
+ // Create DOM structure
+ o.node = dom.create('div', 0, o.content);
+
+ // Execute post process handlers
+ t.onPostProcess.dispatch(t, o);
+
+ // Serialize content
+ o.content = ed.serializer.serialize(o.node, {getInner : 1});
+
+ // Insert cleaned content. We need to handle insertion of contents containing block elements separately
+ if (/<(p|h[1-6]|ul|ol)/.test(o.content))
+ t._insertBlockContent(ed, dom, o.content);
+ else
+ t._insert(o.content);
+ };
+
+ // Add command for external usage
+ ed.addCommand('mceInsertClipboardContent', function(u, o) {
+ process(o);
+ });
+
+ // This function grabs the contents from the clipboard by adding a
+ // hidden div and placing the caret inside it and after the browser paste
+ // is done it grabs that contents and processes that
+ function grabContent(e) {
+ var n, or, rng, sel = ed.selection, dom = ed.dom, body = ed.getBody(), posY;
+
+ if (dom.get('_mcePaste'))
+ return;
+
+ // Create container to paste into
+ n = dom.add(body, 'div', {id : '_mcePaste'}, ' ');
+
+ // If contentEditable mode we need to find out the position of the closest element
+ if (body != ed.getDoc().body)
+ posY = dom.getPos(ed.selection.getStart(), body).y;
+ else
+ posY = body.scrollTop;
+
+ // Styles needs to be applied after the element is added to the document since WebKit will otherwise remove all styles
+ dom.setStyles(n, {
+ position : 'absolute',
+ left : -10000,
+ top : posY,
+ width : 1,
+ height : 1,
+ overflow : 'hidden'
+ });
+
+ if (tinymce.isIE) {
+ // Select the container
+ rng = dom.doc.body.createTextRange();
+ rng.moveToElementText(n);
+ rng.execCommand('Paste');
+
+ // Remove container
+ dom.remove(n);
+
+ // Process contents
+ process({content : n.innerHTML});
+
+ return tinymce.dom.Event.cancel(e);
+ } else {
+ or = ed.selection.getRng();
+
+ // Move caret into hidden div
+ n = n.firstChild;
+ rng = ed.getDoc().createRange();
+ rng.setStart(n, 0);
+ rng.setEnd(n, 1);
+ sel.setRng(rng);
+
+ // Wait a while and grab the pasted contents
+ window.setTimeout(function() {
+ var n = dom.get('_mcePaste'), h;
+
+ // Webkit clones the _mcePaste div for some odd reason so this will ensure that we get the real new div not the old empty one
+ n.id = '_mceRemoved';
+ dom.remove(n);
+ n = dom.get('_mcePaste') || n;
+
+ // Grab the HTML contents
+ // We need to look for a apple style wrapper on webkit it also adds a div wrapper if you copy/paste the body of the editor
+ // It's amazing how strange the contentEditable mode works in WebKit
+ h = (dom.select('> span.Apple-style-span div', n)[0] || dom.select('> span.Apple-style-span', n)[0] || n).innerHTML;
+
+ // Remove hidden div and restore selection
+ dom.remove(n);
+
+ // Restore the old selection
+ if (or)
+ sel.setRng(or);
+
+ process({content : h});
+ }, 0);
+ }
+ };
+
+ // Check if we should use the new auto process method
+ if (ed.getParam('paste_auto_cleanup_on_paste', true)) {
+ // Is it's Opera or older FF use key handler
+ if (tinymce.isOpera || /Firefox\/2/.test(navigator.userAgent)) {
+ ed.onKeyDown.add(function(ed, e) {
+ if (((tinymce.isMac ? e.metaKey : e.ctrlKey) && e.keyCode == 86) || (e.shiftKey && e.keyCode == 45))
+ grabContent(e);
+ });
+ } else {
+ // Grab contents on paste event on Gecko and WebKit
+ ed.onPaste.addToTop(function(ed, e) {
+ return grabContent(e);
+ });
+ }
+ }
+
+ // Block all drag/drop events
+ if (ed.getParam('paste_block_drop')) {
+ ed.onInit.add(function() {
+ ed.dom.bind(ed.getBody(), ['dragend', 'dragover', 'draggesture', 'dragdrop', 'drop', 'drag'], function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+
+ return false;
+ });
+ });
+ }
+
+ // Add legacy support
+ t._legacySupport();
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Paste text/word',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/paste',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ _preProcess : function(pl, o) {
+ var ed = this.editor, h = o.content, process, stripClass;
+
+ //console.log('Before preprocess:' + o.content);
+
+ function process(items) {
+ each(items, function(v) {
+ // Remove or replace
+ if (v.constructor == RegExp)
+ h = h.replace(v, '');
+ else
+ h = h.replace(v[0], v[1]);
+ });
+ };
+
+ // Process away some basic content
+ process([
+ /^\s*( )+/g, // nbsp entities at the start of contents
+ /( |
]*>)+\s*$/g // nbsp entities at the end of contents
+ ]);
+
+ // Detect Word content and process it more aggressive
+ if (/(class=\"?Mso|style=\"[^\"]*\bmso\-|w:WordDocument)/.test(h) || o.wordContent) {
+ o.wordContent = true; // Mark the pasted contents as word specific content
+ //console.log('Word contents detected.');
+
+ if (ed.getParam('paste_convert_middot_lists', true)) {
+ process([
+ [//gi, '$&__MCE_ITEM__'], // Convert supportLists to a list item marker
+ [/(]+:\s*symbol[^>]+>)/gi, '$1__MCE_ITEM__'], // Convert symbol spans to list items
+ [/(]+mso-list:[^>]+>)/gi, '$1__MCE_ITEM__'] // Convert mso-list to item marker
+ ]);
+ }
+
+ process([
+ //gi, // Word comments
+ /<\/?(img|font|meta|link|style|div|v:\w+)[^>]*>/gi, // Remove some tags including VML content
+ /<\\?\?xml[^>]*>/gi, // XML namespace declarations
+ /<\/?o:[^>]*>/gi, // MS namespaced elements
+ / (id|name|language|type|on\w+|v:\w+)=\"([^\"]*)\"/gi, // on.., class, style and language attributes with quotes
+ / (id|name|language|type|on\w+|v:\w+)=(\w+)/gi, // on.., class, style and language attributes without quotes (IE)
+ [/<(\/?)s>/gi, '<$1strike>'], // Convert into for line-though
+ /