PageRenderTime 127ms CodeModel.GetById 61ms app.highlight 32ms RepoModel.GetById 28ms app.codeStats 1ms

/static/scripts/tiny_mce/plugins/paste/editor_plugin_src.js

http://n23.googlecode.com/
JavaScript | 387 lines | 352 code | 22 blank | 13 comment | 24 complexity | 779b276f7e43fc535d1a17ba3224c40b MD5 | raw file
  1/**
  2 * $Id: editor_plugin_src.js 738 2008-03-20 20:00:48Z spocke $
  3 *
  4 * @author Moxiecode
  5 * @copyright Copyright Š 2004-2008, Moxiecode Systems AB, All rights reserved.
  6 */
  7
  8(function() {
  9	var Event = tinymce.dom.Event;
 10
 11	tinymce.create('tinymce.plugins.PastePlugin', {
 12		init : function(ed, url) {
 13			var t = this;
 14
 15			t.editor = ed; 
 16
 17			// Register commands
 18			ed.addCommand('mcePasteText', function(ui, v) {
 19				if (ui) {
 20					if ((ed.getParam('paste_use_dialog', true)) || (!tinymce.isIE)) {
 21						ed.windowManager.open({
 22							file : url + '/pastetext.htm',
 23							width : 450,
 24							height : 400,
 25							inline : 1
 26						}, {
 27							plugin_url : url
 28						});
 29					} else
 30						t._insertText(clipboardData.getData("Text"), true);
 31				} else
 32					t._insertText(v.html, v.linebreaks);
 33			});
 34
 35			ed.addCommand('mcePasteWord', function(ui, v) {
 36				if (ui) {
 37					if ((ed.getParam('paste_use_dialog', true)) || (!tinymce.isIE)) {
 38						ed.windowManager.open({
 39							file : url + '/pasteword.htm',
 40							width : 450,
 41							height : 400,
 42							inline : 1
 43						}, {
 44							plugin_url : url
 45						});
 46					} else
 47						t._insertText(t._clipboardHTML());
 48				} else
 49					t._insertWordContent(v);
 50			});
 51
 52			ed.addCommand('mceSelectAll', function() {
 53				ed.execCommand('selectall'); 
 54			});
 55
 56			// Register buttons
 57			ed.addButton('pastetext', {title : 'paste.paste_text_desc', cmd : 'mcePasteText', ui : true});
 58			ed.addButton('pasteword', {title : 'paste.paste_word_desc', cmd : 'mcePasteWord', ui : true});
 59			ed.addButton('selectall', {title : 'paste.selectall_desc', cmd : 'mceSelectAll'});
 60
 61			if (ed.getParam("paste_auto_cleanup_on_paste", false)) {
 62				ed.onPaste.add(function(ed, e) {
 63					return t._handlePasteEvent(e)
 64				});
 65			}
 66
 67			if (!tinymce.isIE && ed.getParam("paste_auto_cleanup_on_paste", false)) {
 68				// Force paste dialog if non IE browser
 69				ed.onKeyDown.add(function(ed, e) {
 70					if (e.ctrlKey && e.keyCode == 86) {
 71						window.setTimeout(function() {
 72							ed.execCommand("mcePasteText", true);
 73						}, 1);
 74
 75						Event.cancel(e);
 76					}
 77				});
 78			}
 79		},
 80
 81		getInfo : function() {
 82			return {
 83				longname : 'Paste text/word',
 84				author : 'Moxiecode Systems AB',
 85				authorurl : 'http://tinymce.moxiecode.com',
 86				infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/paste',
 87				version : tinymce.majorVersion + "." + tinymce.minorVersion
 88			};
 89		},
 90
 91		// Private methods
 92
 93		_handlePasteEvent : function(e) {
 94			var html = this._clipboardHTML(), ed = this.editor, sel = ed.selection, r;
 95
 96			// Removes italic, strong etc, the if was needed due to bug #1437114
 97			if (ed && (r = sel.getRng()) && r.text.length > 0)
 98				ed.execCommand('delete');
 99
100			if (html && html.length > 0)
101				ed.execCommand('mcePasteWord', false, html);
102
103			return Event.cancel(e);
104		},
105
106		_insertText : function(content, bLinebreaks) { 
107			if (content && content.length > 0) {
108				if (bLinebreaks) { 
109					// Special paragraph treatment 
110					if (this.editor.getParam("paste_create_paragraphs", true)) {
111						var rl = this.editor.getParam("paste_replace_list", '\u2122,<sup>TM</sup>,\u2026,...,\u201c|\u201d,",\u2019,\',\u2013|\u2014|\u2015|\u2212,-').split(',');
112						for (var i=0; i<rl.length; i+=2)
113							content = content.replace(new RegExp(rl[i], 'gi'), rl[i+1]);
114
115						content = content.replace(/\r\n\r\n/g, '</p><p>');
116						content = content.replace(/\r\r/g, '</p><p>');
117						content = content.replace(/\n\n/g, '</p><p>');
118
119						// Has paragraphs 
120						if ((pos = content.indexOf('</p><p>')) != -1) { 
121							this.editor.execCommand("Delete"); 
122
123							var node = this.editor.selection.getNode(); 
124
125							// Get list of elements to break 
126							var breakElms = [];
127
128							do { 
129								if (node.nodeType == 1) { 
130									// Don't break tables and break at body 
131									if (node.nodeName == "TD" || node.nodeName == "BODY") 
132										break; 
133			
134									breakElms[breakElms.length] = node; 
135								} 
136							} while(node = node.parentNode); 
137
138							var before = "", after = "</p>"; 
139							before += content.substring(0, pos); 
140
141							for (var i=0; i<breakElms.length; i++) { 
142								before += "</" + breakElms[i].nodeName + ">"; 
143								after += "<" + breakElms[(breakElms.length-1)-i].nodeName + ">"; 
144							} 
145
146							before += "<p>"; 
147							content = before + content.substring(pos+7) + after; 
148						} 
149					} 
150
151					if (this.editor.getParam("paste_create_linebreaks", true)) {
152						content = content.replace(/\r\n/g, '<br />');
153						content = content.replace(/\r/g, '<br />');
154						content = content.replace(/\n/g, '<br />');
155					}
156				} 
157			
158				this.editor.execCommand("mceInsertRawHTML", false, content); 
159			}
160		},
161
162		_insertWordContent : function(content) { 
163			var t = this, ed = t.editor;
164
165			if (content && content.length > 0) {
166				// Cleanup Word content
167				var bull = String.fromCharCode(8226);
168				var middot = String.fromCharCode(183);
169
170				if (ed.getParam('paste_insert_word_content_callback'))
171					content = ed.execCallback('paste_insert_word_content_callback', 'before', content);
172
173				var rl = ed.getParam("paste_replace_list", '\u2122,<sup>TM</sup>,\u2026,...,\u201c|\u201d,",\u2019,\',\u2013|\u2014|\u2015|\u2212,-').split(',');
174				for (var i=0; i<rl.length; i+=2)
175					content = content.replace(new RegExp(rl[i], 'gi'), rl[i+1]);
176
177				if (this.editor.getParam("paste_convert_headers_to_strong", false)) {
178					content = content.replace(new RegExp('<p class=MsoHeading.*?>(.*?)<\/p>', 'gi'), '<p><b>$1</b></p>');
179				}
180
181				content = content.replace(new RegExp('tab-stops: list [0-9]+.0pt">', 'gi'), '">' + "--list--");
182				content = content.replace(new RegExp(bull + "(.*?)<BR>", "gi"), "<p>" + middot + "$1</p>");
183				content = content.replace(new RegExp('<SPAN style="mso-list: Ignore">', 'gi'), "<span>" + bull); // Covert to bull list
184				content = content.replace(/<o:p><\/o:p>/gi, "");
185				content = content.replace(new RegExp('<br style="page-break-before: always;.*>', 'gi'), '-- page break --'); // Replace pagebreaks
186				content = content.replace(new RegExp('<(!--)([^>]*)(--)>', 'g'), "");  // Word comments
187
188				if (this.editor.getParam("paste_remove_spans", true))
189					content = content.replace(/<\/?span[^>]*>/gi, "");
190
191				if (this.editor.getParam("paste_remove_styles", true))
192					content = content.replace(new RegExp('<(\\w[^>]*) style="([^"]*)"([^>]*)', 'gi'), "<$1$3");
193
194				content = content.replace(/<\/?font[^>]*>/gi, "");
195
196				// Strips class attributes.
197				switch (this.editor.getParam("paste_strip_class_attributes", "all")) {
198					case "all":
199						content = content.replace(/<(\w[^>]*) class=([^ |>]*)([^>]*)/gi, "<$1$3");
200						break;
201
202					case "mso":
203						content = content.replace(new RegExp('<(\\w[^>]*) class="?mso([^ |>]*)([^>]*)', 'gi'), "<$1$3");
204						break;
205				}
206
207				content = content.replace(new RegExp('href="?' + this._reEscape("" + document.location) + '', 'gi'), 'href="' + this.editor.documentBaseURI.getURI());
208				content = content.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3");
209				content = content.replace(/<\\?\?xml[^>]*>/gi, "");
210				content = content.replace(/<\/?\w+:[^>]*>/gi, "");
211				content = content.replace(/-- page break --\s*<p>&nbsp;<\/p>/gi, ""); // Remove pagebreaks
212				content = content.replace(/-- page break --/gi, ""); // Remove pagebreaks
213
214		//		content = content.replace(/\/?&nbsp;*/gi, ""); &nbsp;
215		//		content = content.replace(/<p>&nbsp;<\/p>/gi, '');
216
217				if (!this.editor.getParam('force_p_newlines')) {
218					content = content.replace('', '' ,'gi');
219					content = content.replace('</p>', '<br /><br />' ,'gi');
220				}
221
222				if (!tinymce.isIE && !this.editor.getParam('force_p_newlines')) {
223					content = content.replace(/<\/?p[^>]*>/gi, "");
224				}
225
226				content = content.replace(/<\/?div[^>]*>/gi, "");
227
228				// Convert all middlot lists to UL lists
229				if (this.editor.getParam("paste_convert_middot_lists", true)) {
230					var div = ed.dom.create("div", null, content);
231
232					// Convert all middot paragraphs to li elements
233					var className = this.editor.getParam("paste_unindented_list_class", "unIndentedList");
234
235					while (this._convertMiddots(div, "--list--")) ; // bull
236					while (this._convertMiddots(div, middot, className)) ; // Middot
237					while (this._convertMiddots(div, bull)) ; // bull
238
239					content = div.innerHTML;
240				}
241
242				// Replace all headers with strong and fix some other issues
243				if (this.editor.getParam("paste_convert_headers_to_strong", false)) {
244					content = content.replace(/<h[1-6]>&nbsp;<\/h[1-6]>/gi, '<p>&nbsp;&nbsp;</p>');
245					content = content.replace(/<h[1-6]>/gi, '<p><b>');
246					content = content.replace(/<\/h[1-6]>/gi, '</b></p>');
247					content = content.replace(/<b>&nbsp;<\/b>/gi, '<b>&nbsp;&nbsp;</b>');
248					content = content.replace(/^(&nbsp;)*/gi, '');
249				}
250
251				content = content.replace(/--list--/gi, ""); // Remove --list--
252
253				if (ed.getParam('paste_insert_word_content_callback'))
254					content = ed.execCallback('paste_insert_word_content_callback', 'after', content);
255
256				// Insert cleaned content
257				this.editor.execCommand("mceInsertContent", false, content);
258
259				if (this.editor.getParam('paste_force_cleanup_wordpaste', true)) {
260					var ed = this.editor;
261
262					window.setTimeout(function() {
263						ed.execCommand("mceCleanup");
264					}, 1); // Do normal cleanup detached from this thread
265				}
266			}
267		},
268
269		_reEscape : function(s) {
270			var l = "?.\\*[](){}+^$:";
271			var o = "";
272
273			for (var i=0; i<s.length; i++) {
274				var c = s.charAt(i);
275
276				if (l.indexOf(c) != -1)
277					o += '\\' + c;
278				else
279					o += c;
280			}
281
282			return o;
283		},
284
285		_convertMiddots : function(div, search, class_name) {
286			var ed = this.editor, mdot = String.fromCharCode(183), bull = String.fromCharCode(8226);
287			var nodes, prevul, i, p, ul, li, np, cp, li;
288
289			nodes = div.getElementsByTagName("p");
290			for (i=0; i<nodes.length; i++) {
291				p = nodes[i];
292
293				// Is middot
294				if (p.innerHTML.indexOf(search) == 0) {
295					ul = ed.dom.create("ul");
296
297					if (class_name)
298						ul.className = class_name;
299
300					// Add the first one
301					li = ed.dom.create("li");
302					li.innerHTML = p.innerHTML.replace(new RegExp('' + mdot + '|' + bull + '|--list--|&nbsp;', "gi"), '');
303					ul.appendChild(li);
304
305					// Add the rest
306					np = p.nextSibling;
307					while (np) {
308						// If the node is whitespace, then
309						// ignore it and continue on.
310						if (np.nodeType == 3 && new RegExp('^\\s$', 'm').test(np.nodeValue)) {
311								np = np.nextSibling;
312								continue;
313						}
314
315						if (search == mdot) {
316								if (np.nodeType == 1 && new RegExp('^o(\\s+|&nbsp;)').test(np.innerHTML)) {
317										// Second level of nesting
318										if (!prevul) {
319												prevul = ul;
320												ul = ed.dom.create("ul");
321												prevul.appendChild(ul);
322										}
323										np.innerHTML = np.innerHTML.replace(/^o/, '');
324								} else {
325										// Pop the stack if we're going back up to the first level
326										if (prevul) {
327												ul = prevul;
328												prevul = null;
329										}
330										// Not element or middot paragraph
331										if (np.nodeType != 1 || np.innerHTML.indexOf(search) != 0)
332												break;
333								}
334						} else {
335								// Not element or middot paragraph
336								if (np.nodeType != 1 || np.innerHTML.indexOf(search) != 0)
337										break;
338							}
339
340						cp = np.nextSibling;
341						li = ed.dom.create("li");
342						li.innerHTML = np.innerHTML.replace(new RegExp('' + mdot + '|' + bull + '|--list--|&nbsp;', "gi"), '');
343						np.parentNode.removeChild(np);
344						ul.appendChild(li);
345						np = cp;
346					}
347
348					p.parentNode.replaceChild(ul, p);
349
350					return true;
351				}
352			}
353
354			return false;
355		},
356
357		_clipboardHTML : function() {
358			var div = document.getElementById('_TinyMCE_clipboardHTML');
359
360			if (!div) {
361				var div = document.createElement('DIV');
362				div.id = '_TinyMCE_clipboardHTML';
363
364				with (div.style) {
365					visibility = 'hidden';
366					overflow = 'hidden';
367					position = 'absolute';
368					width = 1;
369					height = 1;
370				}
371
372				document.body.appendChild(div);
373			}
374
375			div.innerHTML = '';
376			var rng = document.body.createTextRange();
377			rng.moveToElementText(div);
378			rng.execCommand('Paste');
379			var html = div.innerHTML;
380			div.innerHTML = '';
381			return html;
382		}
383	});
384
385	// Register plugin
386	tinymce.PluginManager.add('paste', tinymce.plugins.PastePlugin);
387})();