/*\r
-Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.\r
+Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.\r
For licensing, see LICENSE.html or http://ckeditor.com/license\r
*/\r
\r
\r
(function()\r
{\r
- var blockElements = { address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1 },\r
- objectElements = { a:1,embed:1,hr:1,img:1,li:1,object:1,ol:1,table:1,td:1,tr:1,th:1,ul:1,dl:1,dt:1,dd:1,form:1};\r
+ var blockElements = { address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1,section:1,header:1,footer:1,nav:1,article:1,aside:1,figure:1,dialog:1,hgroup:1,time:1,meter:1,menu:1,command:1,keygen:1,output:1,progress:1,details:1,datagrid:1,datalist:1 },\r
+ objectElements = { a:1,embed:1,hr:1,img:1,li:1,object:1,ol:1,table:1,td:1,tr:1,th:1,ul:1,dl:1,dt:1,dd:1,form:1,audio:1,video:1 };\r
\r
var semicolonFixRegex = /\s*(?:;\s*|$)/,\r
varRegex = /#\((.+?)\)/g;\r
\r
CKEDITOR.style = function( styleDefinition, variablesValues )\r
{\r
+ // Inline style text as attribute should be converted\r
+ // to styles object.\r
+ var attrs = styleDefinition.attributes;\r
+ if ( attrs && attrs.style )\r
+ {\r
+ styleDefinition.styles = CKEDITOR.tools.extend( {},\r
+ styleDefinition.styles, parseStyleText( attrs.style ) );\r
+ delete attrs.style;\r
+ }\r
+\r
if ( variablesValues )\r
{\r
styleDefinition = CKEDITOR.tools.clone( styleDefinition );\r
replaceVariables( styleDefinition.styles, variablesValues );\r
}\r
\r
- var element = this.element = ( styleDefinition.element || '*' ).toLowerCase();\r
+ var element = this.element = styleDefinition.element ?\r
+ ( typeof styleDefinition.element == 'string' ? styleDefinition.element.toLowerCase() : styleDefinition.element )\r
+ : '*';\r
\r
this.type =\r
blockElements[ element ] ?\r
:\r
CKEDITOR.STYLE_INLINE;\r
\r
+ // If the 'element' property is an object with a set of possible element, it will be applied like an object style: only to existing elements\r
+ if ( typeof this.element == 'object' )\r
+ this.type = CKEDITOR.STYLE_OBJECT;\r
+\r
this._ =\r
{\r
definition : styleDefinition\r
&& ( element == elementPath.block || element == elementPath.blockLimit ) )\r
continue;\r
\r
- if( this.type == CKEDITOR.STYLE_OBJECT\r
- && !( element.getName() in objectElements ) )\r
+ if( this.type == CKEDITOR.STYLE_OBJECT )\r
+ {\r
+ var name = element.getName();\r
+ if ( !( typeof this.element == 'string' ? name == this.element : name in this.element ) )\r
continue;\r
+ }\r
\r
if ( this.checkElementRemovable( element, true ) )\r
return true;\r
return true;\r
},\r
\r
- // Checks if an element, or any of its attributes, is removable by the\r
- // current style definition.\r
- checkElementRemovable : function( element, fullMatch )\r
+ // Check if the element matches the current style definition.\r
+ checkElementMatch : function( element, fullMatch )\r
{\r
- if ( !element )\r
+ var def = this._.definition;\r
+\r
+ if ( !element || !def.ignoreReadonly && element.isReadOnly() )\r
return false;\r
\r
- var def = this._.definition,\r
- attribs;\r
+ var attribs,\r
+ name = element.getName();\r
\r
// If the element name is the same as the style name.\r
- if ( element.getName() == this.element )\r
+ if ( typeof this.element == 'string' ? name == this.element : name in this.element )\r
{\r
// If no attributes are defined in the element.\r
if ( !fullMatch && !element.hasAttributes() )\r
return true;\r
}\r
\r
- // Check if the element can be somehow overriden.\r
+ return false;\r
+ },\r
+\r
+ // Checks if an element, or any of its attributes, is removable by the\r
+ // current style definition.\r
+ checkElementRemovable : function( element, fullMatch )\r
+ {\r
+ // Check element matches the style itself.\r
+ if ( this.checkElementMatch( element, fullMatch ) )\r
+ return true;\r
+\r
+ // Check if the element matches the style overrides.\r
var override = getOverrides( this )[ element.getName() ] ;\r
if ( override )\r
{\r
+ var attribs, attName;\r
+\r
// If no attributes have been defined, remove the element.\r
if ( !( attribs = override.attributes ) )\r
return true;\r
},\r
\r
// Builds the preview HTML based on the styles definition.\r
- buildPreview : function()\r
+ buildPreview : function( label )\r
{\r
var styleDefinition = this._.definition,\r
html = [],\r
if ( cssStyle )\r
html.push( ' style="', cssStyle, '"' );\r
\r
- html.push( '>', styleDefinition.name, '</', elementName, '>' );\r
+ html.push( '>', ( label || styleDefinition.name ), '</', elementName, '>' );\r
\r
return html.join( '' );\r
}\r
var isUnknownElement;\r
\r
// Indicates that fully selected read-only elements are to be included in the styling range.\r
- var includeReadonly = def.includeReadonly;\r
+ var ignoreReadonly = def.ignoreReadonly,\r
+ includeReadonly = ignoreReadonly || def.includeReadonly;\r
\r
// If the read-only inclusion is not available in the definition, try\r
// to get it from the document data.\r
\r
var styleRange;\r
\r
- // Check if the boundaries are inside non stylable elements.\r
- var firstUnstylable = getUnstylableParent( firstNode ),\r
- lastUnstylable = getUnstylableParent( lastNode );\r
-\r
- // If the first element can't be styled, we'll start processing right\r
- // after its unstylable root.\r
- if ( firstUnstylable )\r
- currentNode = firstUnstylable.getNextSourceNode( true );\r
-\r
- // If the last element can't be styled, we'll stop processing on its\r
- // unstylable root.\r
- if ( lastUnstylable )\r
- lastNode = lastUnstylable;\r
+ if ( !ignoreReadonly )\r
+ {\r
+ // Check if the boundaries are inside non stylable elements.\r
+ var firstUnstylable = getUnstylableParent( firstNode ),\r
+ lastUnstylable = getUnstylableParent( lastNode );\r
+\r
+ // If the first element can't be styled, we'll start processing right\r
+ // after its unstylable root.\r
+ if ( firstUnstylable )\r
+ currentNode = firstUnstylable.getNextSourceNode( true );\r
+\r
+ // If the last element can't be styled, we'll stop processing on its\r
+ // unstylable root.\r
+ if ( lastUnstylable )\r
+ lastNode = lastUnstylable;\r
+ }\r
\r
// Do nothing if the current node now follows the last node to be processed.\r
if ( currentNode.getPosition( lastNode ) == CKEDITOR.POSITION_FOLLOWING )\r
breakNodes();\r
\r
// Now, do the DFS walk.\r
- var currentNode = startNode.getNext();\r
+ var currentNode = startNode;\r
while ( !currentNode.equals( endNode ) )\r
{\r
/*\r
var style = this,\r
def = style._.definition,\r
attributes = def.attributes;\r
- var styles = CKEDITOR.style.getStyleText( def );\r
\r
// Remove all defined attributes.\r
if ( attributes )\r
function removeFromElement( style, element )\r
{\r
var def = style._.definition,\r
- attributes = CKEDITOR.tools.extend( {}, def.attributes, getOverrides( style )[ element.getName() ] ),\r
+ attributes = def.attributes,\r
styles = def.styles,\r
+ overrides = getOverrides( style )[ element.getName() ],\r
// If the style is only about the element itself, we have to remove the element.\r
removeEmpty = CKEDITOR.tools.isEmpty( attributes ) && CKEDITOR.tools.isEmpty( styles );\r
\r
element.removeStyle( styleName );\r
}\r
\r
+ // Remove overrides, but don't remove the element if it's a block element\r
+ removeOverrides( element, overrides, blockElements[ element.getName() ] ) ;\r
+\r
if ( removeEmpty )\r
{\r
!CKEDITOR.dtd.$block[ element.getName() ] || style._.enterMode == CKEDITOR.ENTER_BR && !element.hasAttributes() ?\r
* Note: Remove the element if no attributes remain.\r
* @param {Object} element\r
* @param {Object} overrides\r
+ * @param {Boolean} Don't remove the element\r
*/\r
- function removeOverrides( element, overrides )\r
+ function removeOverrides( element, overrides, dontRemove )\r
{\r
var attributes = overrides && overrides.attributes ;\r
\r
}\r
}\r
\r
- removeNoAttribsElement( element );\r
+ if ( !dontRemove )\r
+ removeNoAttribsElement( element );\r
}\r
\r
// If the element has no more attributes, remove it.\r
function applyStyle( document, remove )\r
{\r
var selection = document.getSelection(),\r
+ // Bookmark the range so we can re-select it after processing.\r
+ bookmarks = selection.createBookmarks( 1 ),\r
ranges = selection.getRanges(),\r
func = remove ? this.removeFromRange : this.applyToRange,\r
range;\r
while ( ( range = iterator.getNextRange() ) )\r
func.call( this, range );\r
\r
- selection.selectRanges( ranges );\r
+ if ( bookmarks.length == 1 && bookmarks[ 0 ].collapsed )\r
+ {\r
+ selection.selectRanges( ranges );\r
+ document.getById( bookmarks[ 0 ].startNode ).remove();\r
+ }\r
+ else\r
+ selection.selectBookmarks( bookmarks );\r
\r
document.removeCustomData( 'doc_processing_style' );\r
}\r