Index: /CKEditor/branches/prototype/_source/plugins/wysiwygarea/plugin.js
===================================================================
--- /CKEditor/branches/prototype/_source/plugins/wysiwygarea/plugin.js	(revision 2253)
+++ /CKEditor/branches/prototype/_source/plugins/wysiwygarea/plugin.js	(revision 2254)
@@ -25,205 +25,257 @@
  */
 
-CKEDITOR.plugins.add( 'wysiwygarea',
+(function()
 {
-	init : function( editor, pluginPath )
+	// Matches all self-closing tags that are not defined as empty elements in
+	// the DTD (like &lt;span/&gt;).
+	var invalidSelfCloseTagsRegex = /(<(?!br|hr|base|meta|link|param|img|area|input|col)([a-zA-Z0-9:]+)[^>]*)\/>/gi;
+
+	// #### protectEvents - START
+
+	// Matches all tags that have event attributes (onXYZ).
+	var tagsWithEventRegex = /<[^\>]+ on\w+\s*=[\s\S]+?\>/g;
+
+	// Matches all event attributes.
+	var eventAttributesRegex = /\s(on\w+)(?=\s*=\s*?('|")[\s\S]*?\2)/g;
+
+	// Matches the protected attribute prefix.
+	var protectedEventsRegex = /_cke_pa_/g;
+
+	var protectEvents = function( html )
 	{
-		editor.on( 'editingBlockReady', function()
-			{
-				var mainElement,
-					iframe,
-					isLoadingData,
-					isPendingFocus;
-
-				// The following information is needed for IE only.
-				var isCustomDomain = CKEDITOR.env.ie && document.domain != window.location.hostname;
-
-				// Creates the iframe that holds the editable document.
-				var createIFrame = function()
+		return html.replace( tagsWithEventRegex, protectEvents_ReplaceTags );
+	};
+
+	var protectEvents_ReplaceTags = function( tagMatch )
+	{
+		// Appends the "_cke_pa_" prefix to the event name.
+		return tagMatch.replace( eventAttributesRegex, ' _cke_pa_$1' );
+	};
+
+	var protectEventsRestore = function( html )
+	{
+		return html.replace( protectedEventsRegex, '' ) ;
+	};
+
+	// #### protectEvents - END
+
+	CKEDITOR.plugins.add( 'wysiwygarea',
+	{
+		init : function( editor, pluginPath )
+		{
+			editor.on( 'editingBlockReady', function()
 				{
-					if ( iframe )
-						iframe.remove();
-
-					iframe = new CKEDITOR.dom.element( 'iframe' )
-						.setAttributes({
-							frameBorder : 0,
-							allowTransparency : true })
-						.setStyles({
-							width : '100%',
-							height : '100%' });
-
-					if ( CKEDITOR.env.ie )
+					var mainElement,
+						iframe,
+						isLoadingData,
+						isPendingFocus;
+
+					// The following information is needed for IE only.
+					var isCustomDomain = CKEDITOR.env.ie && document.domain != window.location.hostname;
+
+					// Creates the iframe that holds the editable document.
+					var createIFrame = function()
 					{
-						if ( isCustomDomain )
+						if ( iframe )
+							iframe.remove();
+
+						iframe = new CKEDITOR.dom.element( 'iframe' )
+							.setAttributes({
+								frameBorder : 0,
+								allowTransparency : true })
+							.setStyles({
+								width : '100%',
+								height : '100%' });
+
+						if ( CKEDITOR.env.ie )
 						{
-							// The document domain must be set within the src
-							// attribute.
-							iframe.setAttribute( 'src',
-								'javascript:void( (function(){' +
-									'document.open();' +
-									'document.domain="' + document.domain + '";' +
-									'document.write( window.parent._cke_htmlToLoad_' + editor.name + ' );' +
-									'document.close();' +
-									'window.parent._cke_htmlToLoad_' + editor.name + ' = null;' +
-								'})() )' );
+							if ( isCustomDomain )
+							{
+								// The document domain must be set within the src
+								// attribute.
+								iframe.setAttribute( 'src',
+									'javascript:void( (function(){' +
+										'document.open();' +
+										'document.domain="' + document.domain + '";' +
+										'document.write( window.parent._cke_htmlToLoad_' + editor.name + ' );' +
+										'document.close();' +
+										'window.parent._cke_htmlToLoad_' + editor.name + ' = null;' +
+									'})() )' );
+							}
+							else
+								// To avoid HTTPS warnings.
+								iframe.setAttribute( 'src', 'javascript:void(0)' );
+						}
+
+						// Append the new IFRAME to the main element. For IE, it
+						// must be done after setting the "src", to avoid the
+						// "secure/unsecure" message under HTTPS.
+						mainElement.append( iframe );
+					};
+
+					// The script that is appended to the data being loaded. It
+					// enables editing, and makes some
+					var activationScript =
+						'<script id="cke_actscrpt" type="text/javascript">' +
+							'window.onload = function()' +
+							'{' +
+								// Remove this script from the DOM.
+								'var s = document.getElementById( "cke_actscrpt" );' +
+								's.parentNode.removeChild( s );' +
+
+								// Call the temporary function for the editing
+								// boostrap.
+								'window.parent.CKEDITOR.instances.' + editor.name + '._.contentDomReady( window );' +
+							'}' +
+						'</script>';
+
+					// Editing area bootstrap code.
+					var contentDomReady = function( domWindow )
+					{
+						delete editor._.contentDomReady;
+
+						var domDocument = domWindow.document,
+							body = domDocument.body;
+
+						body.spellcheck = !editor.config.disableNativeSpellChecker;
+
+						if ( CKEDITOR.env.ie )
+						{
+							// Disable and re-enable the body to avoid IE from
+							// taking the editing focus at startup. (#141 / #523)
+							body.disabled = true;
+							body.contentEditable = true;
+							body.removeAttribute( 'disabled' );
 						}
 						else
-							// To avoid HTTPS warnings.
-							iframe.setAttribute( 'src', 'javascript:void(0)' );
-					}
-
-					// Append the new IFRAME to the main element. For IE, it
-					// must be done after setting the "src", to avoid the
-					// "secure/unsecure" message under HTTPS.
-					mainElement.append( iframe );
-				};
-
-				// The script that is appended to the data being loaded. It
-				// enables editing, and makes some
-				var activationScript =
-					'<script id="cke_actscrpt" type="text/javascript">' +
-						'window.onload = function()' +
-						'{' +
-							// Remove this script from the DOM.
-							'var s = document.getElementById( "cke_actscrpt" );' +
-							's.parentNode.removeChild( s );' +
-
-							// Call the temporary function for the editing
-							// boostrap.
-							'window.parent.CKEDITOR.instances.' + editor.name + '._.contentDomReady( window );' +
-						'}' +
-					'</script>';
-
-				// Editing area bootstrap code.
-				var contentDomReady = function( domWindow )
-				{
-					delete editor._.contentDomReady;
-
-					var domDocument = domWindow.document,
-						body = domDocument.body;
-
-					body.spellcheck = !editor.config.disableNativeSpellChecker;
-
-					if ( CKEDITOR.env.ie )
-					{
-						// Disable and re-enable the body to avoid IE from
-						// taking the editing focus at startup. (#141 / #523)
-						body.disabled = true;
-						body.contentEditable = true;
-						body.removeAttribute( 'disabled' );
-					}
-					else
-						domDocument.designMode = 'on';
-
-					// IE, Opera and Safari may not support it and throw
-					// errors.
-					try { domDocument.execCommand( 'enableObjectResizing', false, !editor.config.disableObjectResizing ) ; } catch(e) {}
-					try { domDocument.execCommand( 'enableInlineTableEditing', false, !editor.config.disableNativeTableHandles ) ; } catch(e) {}
-
-					editor.window	= new CKEDITOR.dom.window( domWindow );
-					editor.document	= new CKEDITOR.dom.document( domDocument );
-
-					editor.fire( 'contentDom' );
-
-					isLoadingData = false;
-
-					if ( isPendingFocus )
-						editor.focus();
-				};
-
-				editor.addMode( 'wysiwyg',
-					{
-						load : function( holderElement, data, isSnapshot )
+							domDocument.designMode = 'on';
+
+						// IE, Opera and Safari may not support it and throw
+						// errors.
+						try { domDocument.execCommand( 'enableObjectResizing', false, !editor.config.disableObjectResizing ) ; } catch(e) {}
+						try { domDocument.execCommand( 'enableInlineTableEditing', false, !editor.config.disableNativeTableHandles ) ; } catch(e) {}
+
+						editor.window	= new CKEDITOR.dom.window( domWindow );
+						editor.document	= new CKEDITOR.dom.document( domDocument );
+
+						editor.fire( 'contentDom' );
+
+						isLoadingData = false;
+
+						if ( isPendingFocus )
+							editor.focus();
+					};
+
+					editor.addMode( 'wysiwyg',
 						{
-							mainElement = holderElement;
-
-							// Create the iframe at load for all browsers
-							// except FF and IE with custom domain.
-							if ( !isCustomDomain || !CKEDITOR.env.gecko )
-								createIFrame();
-
-							if ( isSnapshot )
-								this.loadSnapshotData( data );
-							else
-								this.loadData( data );
-						},
-
-						loadData : function( data )
-						{
-							isLoadingData = true;
-
-							data =
-								CKEDITOR.config.docType +
-								'<html dir="' + CKEDITOR.config.contentLangDirection + '">' +
-								'<head>' +
-									'<link href="' + CKEDITOR.config.contentsCss + '" type="text/css" rel="stylesheet" _fcktemp="true"/>' +
-								'</head>' +
-								'<body>' +
-									editor.dataProcessor.toHtml( data ) +
-								'</body>' +
-								'</html>' +
-								activationScript;
-
-							// For custom domain in IE, set the global variable
-							// that will temporarily hold the editor data. This
-							// reference will be used in the ifram src.
-							if ( isCustomDomain )
-								window[ '_cke_htmlToLoad_' + editor.name ] = data;
-
-							editor._.contentDomReady = contentDomReady;
-
-							// We need to recreate the iframe in FF for every
-							// data load, otherwise the following spellcheck
-							// and execCommand features will be active only for
-							// the first time.
-							// The same is valid for IE with custom domain,
-							// because the iframe src must be reset every time.
-							if ( isCustomDomain || CKEDITOR.env.gecko )
-								createIFrame();
-
-							// For custom domain in IE, the data loading is
-							// done through the src attribute of the iframe.
-							if ( !isCustomDomain )
-							{
-								var doc = iframe.$.contentWindow.document;
-								doc.open();
-								doc.write( data );
-								doc.close();
+							load : function( holderElement, data, isSnapshot )
+							{
+								mainElement = holderElement;
+
+								// Create the iframe at load for all browsers
+								// except FF and IE with custom domain.
+								if ( !isCustomDomain || !CKEDITOR.env.gecko )
+									createIFrame();
+
+								if ( isSnapshot )
+									this.loadSnapshotData( data );
+								else
+									this.loadData( data );
+							},
+
+							loadData : function( data )
+							{
+								isLoadingData = true;
+
+								// Fix for invalid self-closing tags (see #152).
+								// TODO: Check if this fix is really needed as
+								// soon as we have the XHTML generator.
+								if ( CKEDITOR.env.ie )
+									data = data.replace( invalidSelfCloseTagsRegex, '$1></$2>' );
+
+								// Prevent event attributes (like "onclick") to
+								// execute while editing.
+								if ( CKEDITOR.env.ie || CKEDITOR.env.webkit )
+									data = protectEvents( data );
+
+								data =
+									CKEDITOR.config.docType +
+									'<html dir="' + CKEDITOR.config.contentLangDirection + '">' +
+									'<head>' +
+										'<link href="' + CKEDITOR.config.contentsCss + '" type="text/css" rel="stylesheet" _fcktemp="true"/>' +
+									'</head>' +
+									'<body>' +
+										editor.dataProcessor.toHtml( data ) +
+									'</body>' +
+									'</html>' +
+									activationScript;
+
+								// For custom domain in IE, set the global variable
+								// that will temporarily hold the editor data. This
+								// reference will be used in the ifram src.
+								if ( isCustomDomain )
+									window[ '_cke_htmlToLoad_' + editor.name ] = data;
+
+								editor._.contentDomReady = contentDomReady;
+
+								// We need to recreate the iframe in FF for every
+								// data load, otherwise the following spellcheck
+								// and execCommand features will be active only for
+								// the first time.
+								// The same is valid for IE with custom domain,
+								// because the iframe src must be reset every time.
+								if ( isCustomDomain || CKEDITOR.env.gecko )
+									createIFrame();
+
+								// For custom domain in IE, the data loading is
+								// done through the src attribute of the iframe.
+								if ( !isCustomDomain )
+								{
+									var doc = iframe.$.contentWindow.document;
+									doc.open();
+									doc.write( data );
+									doc.close();
+								}
+							},
+
+							getData : function()
+							{
+								var data = editor.dataProcessor.toDataFormat( new CKEDITOR.dom.element( iframe.$.contentWindow.document.body ) );
+
+								// Restore protected attributes.
+								data = protectEventsRestore( data );
+
+								return data;
+							},
+
+							getSnapshotData : function()
+							{
+								return iframe.$.contentWindow.document.body.innerHTML;
+							},
+
+							loadSnapshotData : function( data )
+							{
+								iframe.$.contentWindow.document.body.innerHTML = data;
+							},
+
+							unload : function( holderElement )
+							{
+								editor.window = editor.document = iframe = mainElement = isPendingFocus = null;
+
+								editor.fire( 'contentDomUnload' );
+							},
+
+							focus : function()
+							{
+								if ( isLoadingData )
+									isPendingFocus = true;
+								else if ( editor.window )
+									editor.window.focus();
 							}
-						},
-
-						getData : function()
-						{
-							return editor.dataProcessor.toDataFormat( new CKEDITOR.dom.element( iframe.$.contentWindow.document.body ) );
-						},
-
-						getSnapshotData : function()
-						{
-							return iframe.$.contentWindow.document.body.innerHTML;
-						},
-
-						loadSnapshotData : function( data )
-						{
-							iframe.$.contentWindow.document.body.innerHTML = data;
-						},
-
-						unload : function( holderElement )
-						{
-							editor.window = editor.document = iframe = mainElement = isPendingFocus = null;
-
-							editor.fire( 'contentDomUnload' );
-						},
-
-						focus : function()
-						{
-							if ( isLoadingData )
-								isPendingFocus = true;
-							else if ( editor.window )
-								editor.window.focus();
-						}
-					});
-			});
-	}
-});
+						});
+				});
+		}
+	});
+})();
 
 /**
