/*
Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
(function()
{
// Regex to scan for at the end of blocks, which are actually placeholders.
// Safari transforms the to \xa0. (#4172)
var tailNbspRegex = /^[\t\r\n ]*(?: |\xa0)$/;
var protectedSourceMarker = '{cke_protected}';
// Return the last non-space child node of the block (#4344).
function lastNoneSpaceChild( block )
{
var lastIndex = block.children.length,
last = block.children[ lastIndex - 1 ];
while ( last && last.type == CKEDITOR.NODE_TEXT && !CKEDITOR.tools.trim( last.value ) )
last = block.children[ --lastIndex ];
return last;
}
function trimFillers( block, fromSource )
{
// If the current node is a block, and if we're converting from source or
// we're not in IE then search for and remove any tailing BR node.
//
// Also, any at the end of blocks are fillers, remove them as well.
// (#2886)
var children = block.children, lastChild = lastNoneSpaceChild( block );
if ( lastChild )
{
if ( ( fromSource || !CKEDITOR.env.ie ) && lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.name == 'br' )
children.pop();
if ( lastChild.type == CKEDITOR.NODE_TEXT && tailNbspRegex.test( lastChild.value ) )
children.pop();
}
}
function blockNeedsExtension( block )
{
var lastChild = lastNoneSpaceChild( block );
return !lastChild
|| lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.name == 'br'
// Some of the controls in form needs extension too,
// to move cursor at the end of the form. (#4791)
|| block.name == 'form' && lastChild.name == 'input';
}
function extendBlockForDisplay( block )
{
trimFillers( block, true );
if ( blockNeedsExtension( block ) )
{
if ( CKEDITOR.env.ie )
block.add( new CKEDITOR.htmlParser.text( '\xa0' ) );
else
block.add( new CKEDITOR.htmlParser.element( 'br', {} ) );
}
}
function extendBlockForOutput( block )
{
trimFillers( block );
if ( blockNeedsExtension( block ) )
block.add( new CKEDITOR.htmlParser.text( '\xa0' ) );
}
var dtd = CKEDITOR.dtd;
// Find out the list of block-like tags that can contain
.
var blockLikeTags = CKEDITOR.tools.extend( {}, dtd.$block, dtd.$listItem, dtd.$tableContent );
for ( var i in blockLikeTags )
{
if ( ! ( 'br' in dtd[i] ) )
delete blockLikeTags[i];
}
// We just avoid filler in
right now.
// TODO: Support filler for , line break is also occupy line height.
delete blockLikeTags.pre;
var defaultDataFilterRules =
{
elements : {},
attributeNames :
[
// Event attributes (onXYZ) must not be directly set. They can become
// active in the editing area (IE|WebKit).
[ ( /^on/ ), '_cke_pa_on' ]
]
};
var defaultDataBlockFilterRules = { elements : {} };
for ( i in blockLikeTags )
defaultDataBlockFilterRules.elements[ i ] = extendBlockForDisplay;
var defaultHtmlFilterRules =
{
elementNames :
[
// Remove the "cke:" namespace prefix.
[ ( /^cke:/ ), '' ],
// Ignore tags.
[ ( /^\?xml:namespace$/ ), '' ]
],
attributeNames :
[
// Attributes saved for changes and protected attributes.
[ ( /^_cke_(saved|pa)_/ ), '' ],
// All "_cke" attributes are to be ignored.
[ ( /^_cke.*/ ), '' ],
[ 'hidefocus', '' ]
],
elements :
{
$ : function( element )
{
var attribs = element.attributes;
if ( attribs )
{
// Elements marked as temporary are to be ignored.
if ( attribs.cke_temp )
return false;
// Remove duplicated attributes - #3789.
var attributeNames = [ 'name', 'href', 'src' ],
savedAttributeName;
for ( var i = 0 ; i < attributeNames.length ; i++ )
{
savedAttributeName = '_cke_saved_' + attributeNames[ i ];
savedAttributeName in attribs && ( delete attribs[ attributeNames[ i ] ] );
}
}
return element;
},
embed : function( element )
{
var parent = element.parent;
// If the