annotate static/js/tiny_mce/plugins/paste/editor_plugin_src.js @ 334:6805d15cda13

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