annotate static/js/tiny_mce/plugins/paste/editor_plugin_src.js @ 645:99f7917702ca

Fix 081a88b3bfc8, javascript resize of forum images. Commit 081a88b3bfc8 broke those pages that loaded forums.js but did not load the imagesLoaded jQuery extension. Now we have arranged it so that only the forums topic view loads imagesLoaded and put the resizing javascript inline.
author Brian Neal <bgneal@gmail.com>
date Mon, 11 Mar 2013 15:30:25 -0500
parents 6c182ceb7147
children
rev   line source
bgneal@312 1 /**
bgneal@312 2 * editor_plugin_src.js
bgneal@312 3 *
bgneal@312 4 * Copyright 2009, Moxiecode Systems AB
bgneal@312 5 * Released under LGPL License.
bgneal@312 6 *
bgneal@312 7 * License: http://tinymce.moxiecode.com/license
bgneal@312 8 * Contributing: http://tinymce.moxiecode.com/contributing
bgneal@312 9 */
bgneal@312 10
bgneal@312 11 (function() {
bgneal@312 12 var each = tinymce.each,
bgneal@312 13 defs = {
bgneal@312 14 paste_auto_cleanup_on_paste : true,
bgneal@442 15 paste_enable_default_filters : true,
bgneal@312 16 paste_block_drop : false,
bgneal@312 17 paste_retain_style_properties : "none",
bgneal@312 18 paste_strip_class_attributes : "mso",
bgneal@312 19 paste_remove_spans : false,
bgneal@312 20 paste_remove_styles : false,
bgneal@312 21 paste_remove_styles_if_webkit : true,
bgneal@312 22 paste_convert_middot_lists : true,
bgneal@312 23 paste_convert_headers_to_strong : false,
bgneal@312 24 paste_dialog_width : "450",
bgneal@312 25 paste_dialog_height : "400",
bgneal@312 26 paste_text_use_dialog : false,
bgneal@312 27 paste_text_sticky : false,
bgneal@442 28 paste_text_sticky_default : false,
bgneal@312 29 paste_text_notifyalways : false,
bgneal@312 30 paste_text_linebreaktype : "p",
bgneal@312 31 paste_text_replacements : [
bgneal@312 32 [/\u2026/g, "..."],
bgneal@312 33 [/[\x93\x94\u201c\u201d]/g, '"'],
bgneal@312 34 [/[\x60\x91\x92\u2018\u2019]/g, "'"]
bgneal@312 35 ]
bgneal@312 36 };
bgneal@312 37
bgneal@312 38 function getParam(ed, name) {
bgneal@312 39 return ed.getParam(name, defs[name]);
bgneal@312 40 }
bgneal@312 41
bgneal@312 42 tinymce.create('tinymce.plugins.PastePlugin', {
bgneal@312 43 init : function(ed, url) {
bgneal@312 44 var t = this;
bgneal@312 45
bgneal@312 46 t.editor = ed;
bgneal@312 47 t.url = url;
bgneal@312 48
bgneal@312 49 // Setup plugin events
bgneal@312 50 t.onPreProcess = new tinymce.util.Dispatcher(t);
bgneal@312 51 t.onPostProcess = new tinymce.util.Dispatcher(t);
bgneal@312 52
bgneal@312 53 // Register default handlers
bgneal@312 54 t.onPreProcess.add(t._preProcess);
bgneal@312 55 t.onPostProcess.add(t._postProcess);
bgneal@312 56
bgneal@312 57 // Register optional preprocess handler
bgneal@312 58 t.onPreProcess.add(function(pl, o) {
bgneal@312 59 ed.execCallback('paste_preprocess', pl, o);
bgneal@312 60 });
bgneal@312 61
bgneal@312 62 // Register optional postprocess
bgneal@312 63 t.onPostProcess.add(function(pl, o) {
bgneal@312 64 ed.execCallback('paste_postprocess', pl, o);
bgneal@312 65 });
bgneal@312 66
bgneal@442 67 ed.onKeyDown.addToTop(function(ed, e) {
bgneal@442 68 // Block ctrl+v from adding an undo level since the default logic in tinymce.Editor will add that
bgneal@442 69 if (((tinymce.isMac ? e.metaKey : e.ctrlKey) && e.keyCode == 86) || (e.shiftKey && e.keyCode == 45))
bgneal@442 70 return false; // Stop other listeners
bgneal@442 71 });
bgneal@442 72
bgneal@312 73 // Initialize plain text flag
bgneal@442 74 ed.pasteAsPlainText = getParam(ed, 'paste_text_sticky_default');
bgneal@312 75
bgneal@312 76 // This function executes the process handlers and inserts the contents
bgneal@312 77 // force_rich overrides plain text mode set by user, important for pasting with execCommand
bgneal@312 78 function process(o, force_rich) {
bgneal@442 79 var dom = ed.dom, rng, nodes;
bgneal@312 80
bgneal@312 81 // Execute pre process handlers
bgneal@312 82 t.onPreProcess.dispatch(t, o);
bgneal@312 83
bgneal@312 84 // Create DOM structure
bgneal@312 85 o.node = dom.create('div', 0, o.content);
bgneal@312 86
bgneal@442 87 // If pasting inside the same element and the contents is only one block
bgneal@442 88 // remove the block and keep the text since Firefox will copy parts of pre and h1-h6 as a pre element
bgneal@442 89 if (tinymce.isGecko) {
bgneal@442 90 rng = ed.selection.getRng(true);
bgneal@442 91 if (rng.startContainer == rng.endContainer && rng.startContainer.nodeType == 3) {
bgneal@442 92 nodes = dom.select('p,h1,h2,h3,h4,h5,h6,pre', o.node);
bgneal@442 93
bgneal@442 94 // Is only one block node and it doesn't contain word stuff
bgneal@442 95 if (nodes.length == 1 && o.content.indexOf('__MCE_ITEM__') === -1)
bgneal@442 96 dom.remove(nodes.reverse(), true);
bgneal@442 97 }
bgneal@442 98 }
bgneal@442 99
bgneal@312 100 // Execute post process handlers
bgneal@312 101 t.onPostProcess.dispatch(t, o);
bgneal@312 102
bgneal@312 103 // Serialize content
bgneal@312 104 o.content = ed.serializer.serialize(o.node, {getInner : 1});
bgneal@312 105
bgneal@312 106 // Plain text option active?
bgneal@312 107 if ((!force_rich) && (ed.pasteAsPlainText)) {
bgneal@312 108 t._insertPlainText(ed, dom, o.content);
bgneal@312 109
bgneal@312 110 if (!getParam(ed, "paste_text_sticky")) {
bgneal@312 111 ed.pasteAsPlainText = false;
bgneal@312 112 ed.controlManager.setActive("pastetext", false);
bgneal@312 113 }
bgneal@312 114 } else {
bgneal@312 115 t._insert(o.content);
bgneal@312 116 }
bgneal@312 117 }
bgneal@312 118
bgneal@312 119 // Add command for external usage
bgneal@312 120 ed.addCommand('mceInsertClipboardContent', function(u, o) {
bgneal@312 121 process(o, true);
bgneal@312 122 });
bgneal@312 123
bgneal@312 124 if (!getParam(ed, "paste_text_use_dialog")) {
bgneal@312 125 ed.addCommand('mcePasteText', function(u, v) {
bgneal@312 126 var cookie = tinymce.util.Cookie;
bgneal@312 127
bgneal@312 128 ed.pasteAsPlainText = !ed.pasteAsPlainText;
bgneal@312 129 ed.controlManager.setActive('pastetext', ed.pasteAsPlainText);
bgneal@312 130
bgneal@312 131 if ((ed.pasteAsPlainText) && (!cookie.get("tinymcePasteText"))) {
bgneal@312 132 if (getParam(ed, "paste_text_sticky")) {
bgneal@312 133 ed.windowManager.alert(ed.translate('paste.plaintext_mode_sticky'));
bgneal@312 134 } else {
bgneal@312 135 ed.windowManager.alert(ed.translate('paste.plaintext_mode_sticky'));
bgneal@312 136 }
bgneal@312 137
bgneal@312 138 if (!getParam(ed, "paste_text_notifyalways")) {
bgneal@312 139 cookie.set("tinymcePasteText", "1", new Date(new Date().getFullYear() + 1, 12, 31))
bgneal@312 140 }
bgneal@312 141 }
bgneal@312 142 });
bgneal@312 143 }
bgneal@312 144
bgneal@312 145 ed.addButton('pastetext', {title: 'paste.paste_text_desc', cmd: 'mcePasteText'});
bgneal@312 146 ed.addButton('selectall', {title: 'paste.selectall_desc', cmd: 'selectall'});
bgneal@312 147
bgneal@312 148 // This function grabs the contents from the clipboard by adding a
bgneal@312 149 // hidden div and placing the caret inside it and after the browser paste
bgneal@312 150 // is done it grabs that contents and processes that
bgneal@312 151 function grabContent(e) {
bgneal@442 152 var n, or, rng, oldRng, sel = ed.selection, dom = ed.dom, body = ed.getBody(), posY, textContent;
bgneal@312 153
bgneal@312 154 // Check if browser supports direct plaintext access
bgneal@442 155 if (e.clipboardData || dom.doc.dataTransfer) {
bgneal@442 156 textContent = (e.clipboardData || dom.doc.dataTransfer).getData('Text');
bgneal@442 157
bgneal@442 158 if (ed.pasteAsPlainText) {
bgneal@442 159 e.preventDefault();
bgneal@442 160 process({content : textContent.replace(/\r?\n/g, '<br />')});
bgneal@442 161 return;
bgneal@442 162 }
bgneal@312 163 }
bgneal@312 164
bgneal@312 165 if (dom.get('_mcePaste'))
bgneal@312 166 return;
bgneal@312 167
bgneal@312 168 // Create container to paste into
bgneal@442 169 n = dom.add(body, 'div', {id : '_mcePaste', 'class' : 'mcePaste', 'data-mce-bogus' : '1'}, '\uFEFF\uFEFF');
bgneal@312 170
bgneal@312 171 // If contentEditable mode we need to find out the position of the closest element
bgneal@312 172 if (body != ed.getDoc().body)
bgneal@312 173 posY = dom.getPos(ed.selection.getStart(), body).y;
bgneal@312 174 else
bgneal@442 175 posY = body.scrollTop + dom.getViewPort().y;
bgneal@312 176
bgneal@312 177 // Styles needs to be applied after the element is added to the document since WebKit will otherwise remove all styles
bgneal@312 178 dom.setStyles(n, {
bgneal@312 179 position : 'absolute',
bgneal@312 180 left : -10000,
bgneal@312 181 top : posY,
bgneal@312 182 width : 1,
bgneal@312 183 height : 1,
bgneal@312 184 overflow : 'hidden'
bgneal@312 185 });
bgneal@312 186
bgneal@312 187 if (tinymce.isIE) {
bgneal@442 188 // Store away the old range
bgneal@442 189 oldRng = sel.getRng();
bgneal@442 190
bgneal@312 191 // Select the container
bgneal@312 192 rng = dom.doc.body.createTextRange();
bgneal@312 193 rng.moveToElementText(n);
bgneal@312 194 rng.execCommand('Paste');
bgneal@312 195
bgneal@312 196 // Remove container
bgneal@312 197 dom.remove(n);
bgneal@312 198
bgneal@312 199 // Check if the contents was changed, if it wasn't then clipboard extraction failed probably due
bgneal@312 200 // to IE security settings so we pass the junk though better than nothing right
bgneal@442 201 if (n.innerHTML === '\uFEFF\uFEFF') {
bgneal@312 202 ed.execCommand('mcePasteWord');
bgneal@312 203 e.preventDefault();
bgneal@312 204 return;
bgneal@312 205 }
bgneal@312 206
bgneal@442 207 // Restore the old range and clear the contents before pasting
bgneal@442 208 sel.setRng(oldRng);
bgneal@442 209 sel.setContent('');
bgneal@442 210
bgneal@442 211 // For some odd reason we need to detach the the mceInsertContent call from the paste event
bgneal@442 212 // It's like IE has a reference to the parent element that you paste in and the selection gets messed up
bgneal@442 213 // when it tries to restore the selection
bgneal@442 214 setTimeout(function() {
bgneal@442 215 // Process contents
bgneal@442 216 process({content : n.innerHTML});
bgneal@442 217 }, 0);
bgneal@312 218
bgneal@312 219 // Block the real paste event
bgneal@312 220 return tinymce.dom.Event.cancel(e);
bgneal@312 221 } else {
bgneal@312 222 function block(e) {
bgneal@312 223 e.preventDefault();
bgneal@312 224 };
bgneal@312 225
bgneal@312 226 // Block mousedown and click to prevent selection change
bgneal@312 227 dom.bind(ed.getDoc(), 'mousedown', block);
bgneal@312 228 dom.bind(ed.getDoc(), 'keydown', block);
bgneal@312 229
bgneal@312 230 or = ed.selection.getRng();
bgneal@312 231
bgneal@442 232 // Move select contents inside DIV
bgneal@312 233 n = n.firstChild;
bgneal@312 234 rng = ed.getDoc().createRange();
bgneal@312 235 rng.setStart(n, 0);
bgneal@442 236 rng.setEnd(n, 2);
bgneal@312 237 sel.setRng(rng);
bgneal@312 238
bgneal@312 239 // Wait a while and grab the pasted contents
bgneal@312 240 window.setTimeout(function() {
bgneal@442 241 var h = '', nl;
bgneal@312 242
bgneal@442 243 // Paste divs duplicated in paste divs seems to happen when you paste plain text so lets first look for that broken behavior in WebKit
bgneal@442 244 if (!dom.select('div.mcePaste > div.mcePaste').length) {
bgneal@442 245 nl = dom.select('div.mcePaste');
bgneal@312 246
bgneal@442 247 // WebKit will split the div into multiple ones so this will loop through then all and join them to get the whole HTML string
bgneal@442 248 each(nl, function(n) {
bgneal@442 249 var child = n.firstChild;
bgneal@312 250
bgneal@442 251 // WebKit inserts a DIV container with lots of odd styles
bgneal@442 252 if (child && child.nodeName == 'DIV' && child.style.marginTop && child.style.backgroundColor) {
bgneal@442 253 dom.remove(child, 1);
bgneal@442 254 }
bgneal@442 255
bgneal@442 256 // Remove apply style spans
bgneal@442 257 each(dom.select('span.Apple-style-span', n), function(n) {
bgneal@442 258 dom.remove(n, 1);
bgneal@442 259 });
bgneal@442 260
bgneal@442 261 // Remove bogus br elements
bgneal@442 262 each(dom.select('br[data-mce-bogus]', n), function(n) {
bgneal@442 263 dom.remove(n);
bgneal@442 264 });
bgneal@442 265
bgneal@442 266 // WebKit will make a copy of the DIV for each line of plain text pasted and insert them into the DIV
bgneal@442 267 if (n.parentNode.className != 'mcePaste')
bgneal@442 268 h += n.innerHTML;
bgneal@312 269 });
bgneal@442 270 } else {
bgneal@442 271 // Found WebKit weirdness so force the content into plain text mode
bgneal@442 272 h = '<pre>' + dom.encode(textContent).replace(/\r?\n/g, '<br />') + '</pre>';
bgneal@442 273 }
bgneal@312 274
bgneal@312 275 // Remove the nodes
bgneal@442 276 each(dom.select('div.mcePaste'), function(n) {
bgneal@312 277 dom.remove(n);
bgneal@312 278 });
bgneal@312 279
bgneal@312 280 // Restore the old selection
bgneal@312 281 if (or)
bgneal@312 282 sel.setRng(or);
bgneal@312 283
bgneal@312 284 process({content : h});
bgneal@312 285
bgneal@312 286 // Unblock events ones we got the contents
bgneal@312 287 dom.unbind(ed.getDoc(), 'mousedown', block);
bgneal@312 288 dom.unbind(ed.getDoc(), 'keydown', block);
bgneal@312 289 }, 0);
bgneal@312 290 }
bgneal@312 291 }
bgneal@312 292
bgneal@312 293 // Check if we should use the new auto process method
bgneal@312 294 if (getParam(ed, "paste_auto_cleanup_on_paste")) {
bgneal@312 295 // Is it's Opera or older FF use key handler
bgneal@312 296 if (tinymce.isOpera || /Firefox\/2/.test(navigator.userAgent)) {
bgneal@442 297 ed.onKeyDown.addToTop(function(ed, e) {
bgneal@312 298 if (((tinymce.isMac ? e.metaKey : e.ctrlKey) && e.keyCode == 86) || (e.shiftKey && e.keyCode == 45))
bgneal@312 299 grabContent(e);
bgneal@312 300 });
bgneal@312 301 } else {
bgneal@312 302 // Grab contents on paste event on Gecko and WebKit
bgneal@312 303 ed.onPaste.addToTop(function(ed, e) {
bgneal@312 304 return grabContent(e);
bgneal@312 305 });
bgneal@312 306 }
bgneal@312 307 }
bgneal@312 308
bgneal@442 309 ed.onInit.add(function() {
bgneal@442 310 ed.controlManager.setActive("pastetext", ed.pasteAsPlainText);
bgneal@442 311
bgneal@442 312 // Block all drag/drop events
bgneal@442 313 if (getParam(ed, "paste_block_drop")) {
bgneal@312 314 ed.dom.bind(ed.getBody(), ['dragend', 'dragover', 'draggesture', 'dragdrop', 'drop', 'drag'], function(e) {
bgneal@312 315 e.preventDefault();
bgneal@312 316 e.stopPropagation();
bgneal@312 317
bgneal@312 318 return false;
bgneal@312 319 });
bgneal@442 320 }
bgneal@442 321 });
bgneal@312 322
bgneal@312 323 // Add legacy support
bgneal@312 324 t._legacySupport();
bgneal@312 325 },
bgneal@312 326
bgneal@312 327 getInfo : function() {
bgneal@312 328 return {
bgneal@312 329 longname : 'Paste text/word',
bgneal@312 330 author : 'Moxiecode Systems AB',
bgneal@312 331 authorurl : 'http://tinymce.moxiecode.com',
bgneal@312 332 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/paste',
bgneal@312 333 version : tinymce.majorVersion + "." + tinymce.minorVersion
bgneal@312 334 };
bgneal@312 335 },
bgneal@312 336
bgneal@312 337 _preProcess : function(pl, o) {
bgneal@312 338 var ed = this.editor,
bgneal@312 339 h = o.content,
bgneal@312 340 grep = tinymce.grep,
bgneal@312 341 explode = tinymce.explode,
bgneal@312 342 trim = tinymce.trim,
bgneal@312 343 len, stripClass;
bgneal@312 344
bgneal@442 345 //console.log('Before preprocess:' + o.content);
bgneal@442 346
bgneal@312 347 function process(items) {
bgneal@312 348 each(items, function(v) {
bgneal@312 349 // Remove or replace
bgneal@312 350 if (v.constructor == RegExp)
bgneal@312 351 h = h.replace(v, '');
bgneal@312 352 else
bgneal@312 353 h = h.replace(v[0], v[1]);
bgneal@312 354 });
bgneal@312 355 }
bgneal@442 356
bgneal@442 357 if (ed.settings.paste_enable_default_filters == false) {
bgneal@442 358 return;
bgneal@442 359 }
bgneal@442 360
bgneal@442 361 // IE9 adds BRs before/after block elements when contents is pasted from word or for example another browser
bgneal@442 362 if (tinymce.isIE && document.documentMode >= 9)
bgneal@442 363 process([[/(?:<br>&nbsp;[\s\r\n]+|<br>)*(<\/?(h[1-6r]|p|div|address|pre|form|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|blockquote|center|dl|dt|dd|dir|fieldset)[^>]*>)(?:<br>&nbsp;[\s\r\n]+|<br>)*/g, '$1']]);
bgneal@312 364
bgneal@312 365 // Detect Word content and process it more aggressive
bgneal@312 366 if (/class="?Mso|style="[^"]*\bmso-|w:WordDocument/i.test(h) || o.wordContent) {
bgneal@312 367 o.wordContent = true; // Mark the pasted contents as word specific content
bgneal@312 368 //console.log('Word contents detected.');
bgneal@312 369
bgneal@312 370 // Process away some basic content
bgneal@312 371 process([
bgneal@312 372 /^\s*(&nbsp;)+/gi, // &nbsp; entities at the start of contents
bgneal@312 373 /(&nbsp;|<br[^>]*>)+\s*$/gi // &nbsp; entities at the end of contents
bgneal@312 374 ]);
bgneal@312 375
bgneal@312 376 if (getParam(ed, "paste_convert_headers_to_strong")) {
bgneal@312 377 h = h.replace(/<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "<p><strong>$1</strong></p>");
bgneal@312 378 }
bgneal@312 379
bgneal@312 380 if (getParam(ed, "paste_convert_middot_lists")) {
bgneal@312 381 process([
bgneal@312 382 [/<!--\[if !supportLists\]-->/gi, '$&__MCE_ITEM__'], // Convert supportLists to a list item marker
bgneal@442 383 [/(<span[^>]+(?:mso-list:|:\s*symbol)[^>]+>)/gi, '$1__MCE_ITEM__'], // Convert mso-list and symbol spans to item markers
bgneal@442 384 [/(<p[^>]+(?:MsoListParagraph)[^>]+>)/gi, '$1__MCE_ITEM__'] // Convert mso-list and symbol paragraphs to item markers (FF)
bgneal@312 385 ]);
bgneal@312 386 }
bgneal@312 387
bgneal@312 388 process([
bgneal@312 389 // Word comments like conditional comments etc
bgneal@312 390 /<!--[\s\S]+?-->/gi,
bgneal@312 391
bgneal@312 392 // Remove comments, scripts (e.g., msoShowComment), XML tag, VML content, MS Office namespaced tags, and a few other tags
bgneal@312 393 /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,
bgneal@312 394
bgneal@312 395 // Convert <s> into <strike> for line-though
bgneal@312 396 [/<(\/?)s>/gi, "<$1strike>"],
bgneal@312 397
bgneal@312 398 // Replace nsbp entites to char since it's easier to handle
bgneal@312 399 [/&nbsp;/gi, "\u00a0"]
bgneal@312 400 ]);
bgneal@312 401
bgneal@312 402 // Remove bad attributes, with or without quotes, ensuring that attribute text is really inside a tag.
bgneal@312 403 // If JavaScript had a RegExp look-behind, we could have integrated this with the last process() array and got rid of the loop. But alas, it does not, so we cannot.
bgneal@312 404 do {
bgneal@312 405 len = h.length;
bgneal@312 406 h = h.replace(/(<[a-z][^>]*\s)(?:id|name|language|type|on\w+|\w+:\w+)=(?:"[^"]*"|\w+)\s?/gi, "$1");
bgneal@312 407 } while (len != h.length);
bgneal@312 408
bgneal@312 409 // Remove all spans if no styles is to be retained
bgneal@312 410 if (getParam(ed, "paste_retain_style_properties").replace(/^none$/i, "").length == 0) {
bgneal@312 411 h = h.replace(/<\/?span[^>]*>/gi, "");
bgneal@312 412 } else {
bgneal@312 413 // We're keeping styles, so at least clean them up.
bgneal@312 414 // CSS Reference: http://msdn.microsoft.com/en-us/library/aa155477.aspx
bgneal@312 415
bgneal@312 416 process([
bgneal@312 417 // Convert <span style="mso-spacerun:yes">___</span> to string of alternating breaking/non-breaking spaces of same length
bgneal@312 418 [/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi,
bgneal@312 419 function(str, spaces) {
bgneal@312 420 return (spaces.length > 0)? spaces.replace(/./, " ").slice(Math.floor(spaces.length/2)).split("").join("\u00a0") : "";
bgneal@312 421 }
bgneal@312 422 ],
bgneal@312 423
bgneal@312 424 // Examine all styles: delete junk, transform some, and keep the rest
bgneal@312 425 [/(<[a-z][^>]*)\sstyle="([^"]*)"/gi,
bgneal@312 426 function(str, tag, style) {
bgneal@312 427 var n = [],
bgneal@312 428 i = 0,
bgneal@312 429 s = explode(trim(style).replace(/&quot;/gi, "'"), ";");
bgneal@312 430
bgneal@312 431 // Examine each style definition within the tag's style attribute
bgneal@312 432 each(s, function(v) {
bgneal@312 433 var name, value,
bgneal@312 434 parts = explode(v, ":");
bgneal@312 435
bgneal@312 436 function ensureUnits(v) {
bgneal@312 437 return v + ((v !== "0") && (/\d$/.test(v)))? "px" : "";
bgneal@312 438 }
bgneal@312 439
bgneal@312 440 if (parts.length == 2) {
bgneal@312 441 name = parts[0].toLowerCase();
bgneal@312 442 value = parts[1].toLowerCase();
bgneal@312 443
bgneal@312 444 // Translate certain MS Office styles into their CSS equivalents
bgneal@312 445 switch (name) {
bgneal@312 446 case "mso-padding-alt":
bgneal@312 447 case "mso-padding-top-alt":
bgneal@312 448 case "mso-padding-right-alt":
bgneal@312 449 case "mso-padding-bottom-alt":
bgneal@312 450 case "mso-padding-left-alt":
bgneal@312 451 case "mso-margin-alt":
bgneal@312 452 case "mso-margin-top-alt":
bgneal@312 453 case "mso-margin-right-alt":
bgneal@312 454 case "mso-margin-bottom-alt":
bgneal@312 455 case "mso-margin-left-alt":
bgneal@312 456 case "mso-table-layout-alt":
bgneal@312 457 case "mso-height":
bgneal@312 458 case "mso-width":
bgneal@312 459 case "mso-vertical-align-alt":
bgneal@312 460 n[i++] = name.replace(/^mso-|-alt$/g, "") + ":" + ensureUnits(value);
bgneal@312 461 return;
bgneal@312 462
bgneal@312 463 case "horiz-align":
bgneal@312 464 n[i++] = "text-align:" + value;
bgneal@312 465 return;
bgneal@312 466
bgneal@312 467 case "vert-align":
bgneal@312 468 n[i++] = "vertical-align:" + value;
bgneal@312 469 return;
bgneal@312 470
bgneal@312 471 case "font-color":
bgneal@312 472 case "mso-foreground":
bgneal@312 473 n[i++] = "color:" + value;
bgneal@312 474 return;
bgneal@312 475
bgneal@312 476 case "mso-background":
bgneal@312 477 case "mso-highlight":
bgneal@312 478 n[i++] = "background:" + value;
bgneal@312 479 return;
bgneal@312 480
bgneal@312 481 case "mso-default-height":
bgneal@312 482 n[i++] = "min-height:" + ensureUnits(value);
bgneal@312 483 return;
bgneal@312 484
bgneal@312 485 case "mso-default-width":
bgneal@312 486 n[i++] = "min-width:" + ensureUnits(value);
bgneal@312 487 return;
bgneal@312 488
bgneal@312 489 case "mso-padding-between-alt":
bgneal@312 490 n[i++] = "border-collapse:separate;border-spacing:" + ensureUnits(value);
bgneal@312 491 return;
bgneal@312 492
bgneal@312 493 case "text-line-through":
bgneal@312 494 if ((value == "single") || (value == "double")) {
bgneal@312 495 n[i++] = "text-decoration:line-through";
bgneal@312 496 }
bgneal@312 497 return;
bgneal@312 498
bgneal@312 499 case "mso-zero-height":
bgneal@312 500 if (value == "yes") {
bgneal@312 501 n[i++] = "display:none";
bgneal@312 502 }
bgneal@312 503 return;
bgneal@312 504 }
bgneal@312 505
bgneal@312 506 // Eliminate all MS Office style definitions that have no CSS equivalent by examining the first characters in the name
bgneal@312 507 if (/^(mso|column|font-emph|lang|layout|line-break|list-image|nav|panose|punct|row|ruby|sep|size|src|tab-|table-border|text-(?!align|decor|indent|trans)|top-bar|version|vnd|word-break)/.test(name)) {
bgneal@312 508 return;
bgneal@312 509 }
bgneal@312 510
bgneal@312 511 // If it reached this point, it must be a valid CSS style
bgneal@312 512 n[i++] = name + ":" + parts[1]; // Lower-case name, but keep value case
bgneal@312 513 }
bgneal@312 514 });
bgneal@312 515
bgneal@312 516 // If style attribute contained any valid styles the re-write it; otherwise delete style attribute.
bgneal@312 517 if (i > 0) {
bgneal@312 518 return tag + ' style="' + n.join(';') + '"';
bgneal@312 519 } else {
bgneal@312 520 return tag;
bgneal@312 521 }
bgneal@312 522 }
bgneal@312 523 ]
bgneal@312 524 ]);
bgneal@312 525 }
bgneal@312 526 }
bgneal@312 527
bgneal@312 528 // Replace headers with <strong>
bgneal@312 529 if (getParam(ed, "paste_convert_headers_to_strong")) {
bgneal@312 530 process([
bgneal@312 531 [/<h[1-6][^>]*>/gi, "<p><strong>"],
bgneal@312 532 [/<\/h[1-6][^>]*>/gi, "</strong></p>"]
bgneal@312 533 ]);
bgneal@312 534 }
bgneal@312 535
bgneal@442 536 process([
bgneal@442 537 // Copy paste from Java like Open Office will produce this junk on FF
bgneal@442 538 [/Version:[\d.]+\nStartHTML:\d+\nEndHTML:\d+\nStartFragment:\d+\nEndFragment:\d+/gi, '']
bgneal@442 539 ]);
bgneal@442 540
bgneal@312 541 // Class attribute options are: leave all as-is ("none"), remove all ("all"), or remove only those starting with mso ("mso").
bgneal@312 542 // Note:- paste_strip_class_attributes: "none", verify_css_classes: true is also a good variation.
bgneal@312 543 stripClass = getParam(ed, "paste_strip_class_attributes");
bgneal@312 544
bgneal@312 545 if (stripClass !== "none") {
bgneal@312 546 function removeClasses(match, g1) {
bgneal@312 547 if (stripClass === "all")
bgneal@312 548 return '';
bgneal@312 549
bgneal@312 550 var cls = grep(explode(g1.replace(/^(["'])(.*)\1$/, "$2"), " "),
bgneal@312 551 function(v) {
bgneal@312 552 return (/^(?!mso)/i.test(v));
bgneal@312 553 }
bgneal@312 554 );
bgneal@312 555
bgneal@312 556 return cls.length ? ' class="' + cls.join(" ") + '"' : '';
bgneal@312 557 };
bgneal@312 558
bgneal@312 559 h = h.replace(/ class="([^"]+)"/gi, removeClasses);
bgneal@442 560 h = h.replace(/ class=([\-\w]+)/gi, removeClasses);
bgneal@312 561 }
bgneal@312 562
bgneal@312 563 // Remove spans option
bgneal@312 564 if (getParam(ed, "paste_remove_spans")) {
bgneal@312 565 h = h.replace(/<\/?span[^>]*>/gi, "");
bgneal@312 566 }
bgneal@312 567
bgneal@312 568 //console.log('After preprocess:' + h);
bgneal@312 569
bgneal@312 570 o.content = h;
bgneal@312 571 },
bgneal@312 572
bgneal@312 573 /**
bgneal@312 574 * Various post process items.
bgneal@312 575 */
bgneal@312 576 _postProcess : function(pl, o) {
bgneal@312 577 var t = this, ed = t.editor, dom = ed.dom, styleProps;
bgneal@312 578
bgneal@442 579 if (ed.settings.paste_enable_default_filters == false) {
bgneal@442 580 return;
bgneal@442 581 }
bgneal@442 582
bgneal@312 583 if (o.wordContent) {
bgneal@312 584 // Remove named anchors or TOC links
bgneal@312 585 each(dom.select('a', o.node), function(a) {
bgneal@312 586 if (!a.href || a.href.indexOf('#_Toc') != -1)
bgneal@312 587 dom.remove(a, 1);
bgneal@312 588 });
bgneal@312 589
bgneal@312 590 if (getParam(ed, "paste_convert_middot_lists")) {
bgneal@312 591 t._convertLists(pl, o);
bgneal@312 592 }
bgneal@312 593
bgneal@312 594 // Process styles
bgneal@312 595 styleProps = getParam(ed, "paste_retain_style_properties"); // retained properties
bgneal@312 596
bgneal@312 597 // Process only if a string was specified and not equal to "all" or "*"
bgneal@312 598 if ((tinymce.is(styleProps, "string")) && (styleProps !== "all") && (styleProps !== "*")) {
bgneal@312 599 styleProps = tinymce.explode(styleProps.replace(/^none$/i, ""));
bgneal@312 600
bgneal@312 601 // Retains some style properties
bgneal@312 602 each(dom.select('*', o.node), function(el) {
bgneal@312 603 var newStyle = {}, npc = 0, i, sp, sv;
bgneal@312 604
bgneal@312 605 // Store a subset of the existing styles
bgneal@312 606 if (styleProps) {
bgneal@312 607 for (i = 0; i < styleProps.length; i++) {
bgneal@312 608 sp = styleProps[i];
bgneal@312 609 sv = dom.getStyle(el, sp);
bgneal@312 610
bgneal@312 611 if (sv) {
bgneal@312 612 newStyle[sp] = sv;
bgneal@312 613 npc++;
bgneal@312 614 }
bgneal@312 615 }
bgneal@312 616 }
bgneal@312 617
bgneal@312 618 // Remove all of the existing styles
bgneal@312 619 dom.setAttrib(el, 'style', '');
bgneal@312 620
bgneal@312 621 if (styleProps && npc > 0)
bgneal@312 622 dom.setStyles(el, newStyle); // Add back the stored subset of styles
bgneal@312 623 else // Remove empty span tags that do not have class attributes
bgneal@312 624 if (el.nodeName == 'SPAN' && !el.className)
bgneal@312 625 dom.remove(el, true);
bgneal@312 626 });
bgneal@312 627 }
bgneal@312 628 }
bgneal@312 629
bgneal@312 630 // Remove all style information or only specifically on WebKit to avoid the style bug on that browser
bgneal@312 631 if (getParam(ed, "paste_remove_styles") || (getParam(ed, "paste_remove_styles_if_webkit") && tinymce.isWebKit)) {
bgneal@312 632 each(dom.select('*[style]', o.node), function(el) {
bgneal@312 633 el.removeAttribute('style');
bgneal@442 634 el.removeAttribute('data-mce-style');
bgneal@312 635 });
bgneal@312 636 } else {
bgneal@312 637 if (tinymce.isWebKit) {
bgneal@312 638 // We need to compress the styles on WebKit since if you paste <img border="0" /> it will become <img border="0" style="... lots of junk ..." />
bgneal@312 639 // Removing the mce_style that contains the real value will force the Serializer engine to compress the styles
bgneal@312 640 each(dom.select('*', o.node), function(el) {
bgneal@442 641 el.removeAttribute('data-mce-style');
bgneal@312 642 });
bgneal@312 643 }
bgneal@312 644 }
bgneal@312 645 },
bgneal@312 646
bgneal@312 647 /**
bgneal@312 648 * Converts the most common bullet and number formats in Office into a real semantic UL/LI list.
bgneal@312 649 */
bgneal@312 650 _convertLists : function(pl, o) {
bgneal@312 651 var dom = pl.editor.dom, listElm, li, lastMargin = -1, margin, levels = [], lastType, html;
bgneal@312 652
bgneal@312 653 // Convert middot lists into real semantic lists
bgneal@312 654 each(dom.select('p', o.node), function(p) {
bgneal@312 655 var sib, val = '', type, html, idx, parents;
bgneal@312 656
bgneal@312 657 // Get text node value at beginning of paragraph
bgneal@312 658 for (sib = p.firstChild; sib && sib.nodeType == 3; sib = sib.nextSibling)
bgneal@312 659 val += sib.nodeValue;
bgneal@312 660
bgneal@312 661 val = p.innerHTML.replace(/<\/?\w+[^>]*>/gi, '').replace(/&nbsp;/g, '\u00a0');
bgneal@312 662
bgneal@312 663 // Detect unordered lists look for bullets
bgneal@442 664 if (/^(__MCE_ITEM__)+[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*\u00a0*/.test(val))
bgneal@312 665 type = 'ul';
bgneal@312 666
bgneal@312 667 // Detect ordered lists 1., a. or ixv.
bgneal@442 668 if (/^__MCE_ITEM__\s*\w+\.\s*\u00a0+/.test(val))
bgneal@312 669 type = 'ol';
bgneal@312 670
bgneal@312 671 // Check if node value matches the list pattern: o&nbsp;&nbsp;
bgneal@312 672 if (type) {
bgneal@312 673 margin = parseFloat(p.style.marginLeft || 0);
bgneal@312 674
bgneal@312 675 if (margin > lastMargin)
bgneal@312 676 levels.push(margin);
bgneal@312 677
bgneal@312 678 if (!listElm || type != lastType) {
bgneal@312 679 listElm = dom.create(type);
bgneal@312 680 dom.insertAfter(listElm, p);
bgneal@312 681 } else {
bgneal@312 682 // Nested list element
bgneal@312 683 if (margin > lastMargin) {
bgneal@312 684 listElm = li.appendChild(dom.create(type));
bgneal@312 685 } else if (margin < lastMargin) {
bgneal@312 686 // Find parent level based on margin value
bgneal@312 687 idx = tinymce.inArray(levels, margin);
bgneal@312 688 parents = dom.getParents(listElm.parentNode, type);
bgneal@312 689 listElm = parents[parents.length - 1 - idx] || listElm;
bgneal@312 690 }
bgneal@312 691 }
bgneal@312 692
bgneal@312 693 // Remove middot or number spans if they exists
bgneal@312 694 each(dom.select('span', p), function(span) {
bgneal@312 695 var html = span.innerHTML.replace(/<\/?\w+[^>]*>/gi, '');
bgneal@312 696
bgneal@312 697 // Remove span with the middot or the number
bgneal@442 698 if (type == 'ul' && /^__MCE_ITEM__[\u2022\u00b7\u00a7\u00d8o\u25CF]/.test(html))
bgneal@312 699 dom.remove(span);
bgneal@442 700 else if (/^__MCE_ITEM__[\s\S]*\w+\.(&nbsp;|\u00a0)*\s*/.test(html))
bgneal@312 701 dom.remove(span);
bgneal@312 702 });
bgneal@312 703
bgneal@312 704 html = p.innerHTML;
bgneal@312 705
bgneal@312 706 // Remove middot/list items
bgneal@312 707 if (type == 'ul')
bgneal@442 708 html = p.innerHTML.replace(/__MCE_ITEM__/g, '').replace(/^[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*(&nbsp;|\u00a0)+\s*/, '');
bgneal@312 709 else
bgneal@312 710 html = p.innerHTML.replace(/__MCE_ITEM__/g, '').replace(/^\s*\w+\.(&nbsp;|\u00a0)+\s*/, '');
bgneal@312 711
bgneal@312 712 // Create li and add paragraph data into the new li
bgneal@312 713 li = listElm.appendChild(dom.create('li', 0, html));
bgneal@312 714 dom.remove(p);
bgneal@312 715
bgneal@312 716 lastMargin = margin;
bgneal@312 717 lastType = type;
bgneal@312 718 } else
bgneal@312 719 listElm = lastMargin = 0; // End list element
bgneal@312 720 });
bgneal@312 721
bgneal@312 722 // Remove any left over makers
bgneal@312 723 html = o.node.innerHTML;
bgneal@312 724 if (html.indexOf('__MCE_ITEM__') != -1)
bgneal@312 725 o.node.innerHTML = html.replace(/__MCE_ITEM__/g, '');
bgneal@312 726 },
bgneal@312 727
bgneal@312 728 /**
bgneal@312 729 * Inserts the specified contents at the caret position.
bgneal@312 730 */
bgneal@312 731 _insert : function(h, skip_undo) {
bgneal@312 732 var ed = this.editor, r = ed.selection.getRng();
bgneal@312 733
bgneal@312 734 // First delete the contents seems to work better on WebKit when the selection spans multiple list items or multiple table cells.
bgneal@312 735 if (!ed.selection.isCollapsed() && r.startContainer != r.endContainer)
bgneal@312 736 ed.getDoc().execCommand('Delete', false, null);
bgneal@312 737
bgneal@442 738 ed.execCommand('mceInsertContent', false, h, {skip_undo : skip_undo});
bgneal@312 739 },
bgneal@312 740
bgneal@312 741 /**
bgneal@312 742 * Instead of the old plain text method which tried to re-create a paste operation, the
bgneal@312 743 * new approach adds a plain text mode toggle switch that changes the behavior of paste.
bgneal@312 744 * This function is passed the same input that the regular paste plugin produces.
bgneal@312 745 * It performs additional scrubbing and produces (and inserts) the plain text.
bgneal@312 746 * This approach leverages all of the great existing functionality in the paste
bgneal@312 747 * plugin, and requires minimal changes to add the new functionality.
bgneal@312 748 * Speednet - June 2009
bgneal@312 749 */
bgneal@312 750 _insertPlainText : function(ed, dom, h) {
bgneal@312 751 var i, len, pos, rpos, node, breakElms, before, after,
bgneal@312 752 w = ed.getWin(),
bgneal@312 753 d = ed.getDoc(),
bgneal@312 754 sel = ed.selection,
bgneal@312 755 is = tinymce.is,
bgneal@312 756 inArray = tinymce.inArray,
bgneal@312 757 linebr = getParam(ed, "paste_text_linebreaktype"),
bgneal@312 758 rl = getParam(ed, "paste_text_replacements");
bgneal@312 759
bgneal@312 760 function process(items) {
bgneal@312 761 each(items, function(v) {
bgneal@312 762 if (v.constructor == RegExp)
bgneal@312 763 h = h.replace(v, "");
bgneal@312 764 else
bgneal@312 765 h = h.replace(v[0], v[1]);
bgneal@312 766 });
bgneal@312 767 };
bgneal@312 768
bgneal@312 769 if ((typeof(h) === "string") && (h.length > 0)) {
bgneal@312 770 // If HTML content with line-breaking tags, then remove all cr/lf chars because only tags will break a line
bgneal@312 771 if (/<(?:p|br|h[1-6]|ul|ol|dl|table|t[rdh]|div|blockquote|fieldset|pre|address|center)[^>]*>/i.test(h)) {
bgneal@312 772 process([
bgneal@312 773 /[\n\r]+/g
bgneal@312 774 ]);
bgneal@312 775 } else {
bgneal@312 776 // Otherwise just get rid of carriage returns (only need linefeeds)
bgneal@312 777 process([
bgneal@312 778 /\r+/g
bgneal@312 779 ]);
bgneal@312 780 }
bgneal@312 781
bgneal@312 782 process([
bgneal@312 783 [/<\/(?:p|h[1-6]|ul|ol|dl|table|div|blockquote|fieldset|pre|address|center)>/gi, "\n\n"], // Block tags get a blank line after them
bgneal@312 784 [/<br[^>]*>|<\/tr>/gi, "\n"], // Single linebreak for <br /> tags and table rows
bgneal@312 785 [/<\/t[dh]>\s*<t[dh][^>]*>/gi, "\t"], // Table cells get tabs betweem them
bgneal@312 786 /<[a-z!\/?][^>]*>/gi, // Delete all remaining tags
bgneal@312 787 [/&nbsp;/gi, " "], // Convert non-break spaces to regular spaces (remember, *plain text*)
bgneal@312 788 [/(?:(?!\n)\s)*(\n+)(?:(?!\n)\s)*/gi, "$1"], // Cool little RegExp deletes whitespace around linebreak chars.
bgneal@312 789 [/\n{3,}/g, "\n\n"], // Max. 2 consecutive linebreaks
bgneal@312 790 /^\s+|\s+$/g // Trim the front & back
bgneal@312 791 ]);
bgneal@312 792
bgneal@442 793 h = dom.decode(tinymce.html.Entities.encodeRaw(h));
bgneal@312 794
bgneal@312 795 // Delete any highlighted text before pasting
bgneal@312 796 if (!sel.isCollapsed()) {
bgneal@312 797 d.execCommand("Delete", false, null);
bgneal@312 798 }
bgneal@312 799
bgneal@312 800 // Perform default or custom replacements
bgneal@312 801 if (is(rl, "array") || (is(rl, "array"))) {
bgneal@312 802 process(rl);
bgneal@312 803 }
bgneal@312 804 else if (is(rl, "string")) {
bgneal@312 805 process(new RegExp(rl, "gi"));
bgneal@312 806 }
bgneal@312 807
bgneal@312 808 // Treat paragraphs as specified in the config
bgneal@312 809 if (linebr == "none") {
bgneal@312 810 process([
bgneal@312 811 [/\n+/g, " "]
bgneal@312 812 ]);
bgneal@312 813 }
bgneal@312 814 else if (linebr == "br") {
bgneal@312 815 process([
bgneal@312 816 [/\n/g, "<br />"]
bgneal@312 817 ]);
bgneal@312 818 }
bgneal@312 819 else {
bgneal@312 820 process([
bgneal@312 821 /^\s+|\s+$/g,
bgneal@312 822 [/\n\n/g, "</p><p>"],
bgneal@312 823 [/\n/g, "<br />"]
bgneal@312 824 ]);
bgneal@312 825 }
bgneal@312 826
bgneal@312 827 // This next piece of code handles the situation where we're pasting more than one paragraph of plain
bgneal@312 828 // text, and we are pasting the content into the middle of a block node in the editor. The block
bgneal@312 829 // node gets split at the selection point into "Para A" and "Para B" (for the purposes of explaining).
bgneal@312 830 // The first paragraph of the pasted text is appended to "Para A", and the last paragraph of the
bgneal@312 831 // pasted text is prepended to "Para B". Any other paragraphs of pasted text are placed between
bgneal@312 832 // "Para A" and "Para B". This code solves a host of problems with the original plain text plugin and
bgneal@312 833 // now handles styles correctly. (Pasting plain text into a styled paragraph is supposed to make the
bgneal@312 834 // plain text take the same style as the existing paragraph.)
bgneal@312 835 if ((pos = h.indexOf("</p><p>")) != -1) {
bgneal@312 836 rpos = h.lastIndexOf("</p><p>");
bgneal@312 837 node = sel.getNode();
bgneal@312 838 breakElms = []; // Get list of elements to break
bgneal@312 839
bgneal@312 840 do {
bgneal@312 841 if (node.nodeType == 1) {
bgneal@312 842 // Don't break tables and break at body
bgneal@312 843 if (node.nodeName == "TD" || node.nodeName == "BODY") {
bgneal@312 844 break;
bgneal@312 845 }
bgneal@312 846
bgneal@312 847 breakElms[breakElms.length] = node;
bgneal@312 848 }
bgneal@312 849 } while (node = node.parentNode);
bgneal@312 850
bgneal@312 851 // Are we in the middle of a block node?
bgneal@312 852 if (breakElms.length > 0) {
bgneal@312 853 before = h.substring(0, pos);
bgneal@312 854 after = "";
bgneal@312 855
bgneal@312 856 for (i=0, len=breakElms.length; i<len; i++) {
bgneal@312 857 before += "</" + breakElms[i].nodeName.toLowerCase() + ">";
bgneal@312 858 after += "<" + breakElms[breakElms.length-i-1].nodeName.toLowerCase() + ">";
bgneal@312 859 }
bgneal@312 860
bgneal@312 861 if (pos == rpos) {
bgneal@312 862 h = before + after + h.substring(pos+7);
bgneal@312 863 }
bgneal@312 864 else {
bgneal@312 865 h = before + h.substring(pos+4, rpos+4) + after + h.substring(rpos+7);
bgneal@312 866 }
bgneal@312 867 }
bgneal@312 868 }
bgneal@312 869
bgneal@312 870 // Insert content at the caret, plus add a marker for repositioning the caret
bgneal@312 871 ed.execCommand("mceInsertRawHTML", false, h + '<span id="_plain_text_marker">&nbsp;</span>');
bgneal@312 872
bgneal@312 873 // Reposition the caret to the marker, which was placed immediately after the inserted content.
bgneal@312 874 // Needs to be done asynchronously (in window.setTimeout) or else it doesn't work in all browsers.
bgneal@312 875 // The second part of the code scrolls the content up if the caret is positioned off-screen.
bgneal@312 876 // This is only necessary for WebKit browsers, but it doesn't hurt to use for all.
bgneal@312 877 window.setTimeout(function() {
bgneal@312 878 var marker = dom.get('_plain_text_marker'),
bgneal@312 879 elm, vp, y, elmHeight;
bgneal@312 880
bgneal@312 881 sel.select(marker, false);
bgneal@312 882 d.execCommand("Delete", false, null);
bgneal@312 883 marker = null;
bgneal@312 884
bgneal@312 885 // Get element, position and height
bgneal@312 886 elm = sel.getStart();
bgneal@312 887 vp = dom.getViewPort(w);
bgneal@312 888 y = dom.getPos(elm).y;
bgneal@312 889 elmHeight = elm.clientHeight;
bgneal@312 890
bgneal@312 891 // Is element within viewport if not then scroll it into view
bgneal@312 892 if ((y < vp.y) || (y + elmHeight > vp.y + vp.h)) {
bgneal@312 893 d.body.scrollTop = y < vp.y ? y : y - vp.h + 25;
bgneal@312 894 }
bgneal@312 895 }, 0);
bgneal@312 896 }
bgneal@312 897 },
bgneal@312 898
bgneal@312 899 /**
bgneal@312 900 * This method will open the old style paste dialogs. Some users might want the old behavior but still use the new cleanup engine.
bgneal@312 901 */
bgneal@312 902 _legacySupport : function() {
bgneal@312 903 var t = this, ed = t.editor;
bgneal@312 904
bgneal@312 905 // Register command(s) for backwards compatibility
bgneal@312 906 ed.addCommand("mcePasteWord", function() {
bgneal@312 907 ed.windowManager.open({
bgneal@312 908 file: t.url + "/pasteword.htm",
bgneal@312 909 width: parseInt(getParam(ed, "paste_dialog_width")),
bgneal@312 910 height: parseInt(getParam(ed, "paste_dialog_height")),
bgneal@312 911 inline: 1
bgneal@312 912 });
bgneal@312 913 });
bgneal@312 914
bgneal@312 915 if (getParam(ed, "paste_text_use_dialog")) {
bgneal@312 916 ed.addCommand("mcePasteText", function() {
bgneal@312 917 ed.windowManager.open({
bgneal@312 918 file : t.url + "/pastetext.htm",
bgneal@312 919 width: parseInt(getParam(ed, "paste_dialog_width")),
bgneal@312 920 height: parseInt(getParam(ed, "paste_dialog_height")),
bgneal@312 921 inline : 1
bgneal@312 922 });
bgneal@312 923 });
bgneal@312 924 }
bgneal@312 925
bgneal@312 926 // Register button for backwards compatibility
bgneal@312 927 ed.addButton("pasteword", {title : "paste.paste_word_desc", cmd : "mcePasteWord"});
bgneal@312 928 }
bgneal@312 929 });
bgneal@312 930
bgneal@312 931 // Register plugin
bgneal@312 932 tinymce.PluginManager.add("paste", tinymce.plugins.PastePlugin);
bgneal@312 933 })();