X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fplugins%2Fstyles%2Fplugin.js;h=2c16b7e6716096104d81c4658df10dcda2969eda;hb=2f22c0c38f17e75be5541089076885442aaa2377;hp=40dc6d18b85420f3e53ae3ae57940b31bf96a5b0;hpb=48b1db88210b4160dce439c6e3e32e14af8c106b;p=ckeditor.git diff --git a/_source/plugins/styles/plugin.js b/_source/plugins/styles/plugin.js index 40dc6d1..2c16b7e 100644 --- a/_source/plugins/styles/plugin.js +++ b/_source/plugins/styles/plugin.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -19,11 +19,11 @@ CKEDITOR.plugins.add( 'styles', }); /** - * Registers a function to be called whenever a style changes its state in the + * Registers a function to be called whenever the selection position changes in the * editing area. The current state is passed to the function. The possible * states are {@link CKEDITOR.TRISTATE_ON} and {@link CKEDITOR.TRISTATE_OFF}. * @param {CKEDITOR.style} style The style to be watched. - * @param {Function} callback The function to be called when the style state changes. + * @param {Function} callback The function to be called. * @example * // Create a style object for the <b> element. * var style = new CKEDITOR.style( { element : 'b' } ); @@ -61,17 +61,9 @@ CKEDITOR.editor.prototype.attachStyleStateChange = function( style, callback ) // callback. var currentState = callback.style.checkActive( ev.data.path ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF; - // If the state changed since the last check. - if ( callback.state !== currentState ) - { - // Call the callback function, passing the current - // state to it. - callback.fn.call( this, currentState ); - - // Save the current state, so it can be compared next - // time. - callback.state = currentState; - } + // Call the callback function, passing the current + // state to it. + callback.fn.call( this, currentState ); } }); } @@ -87,12 +79,14 @@ CKEDITOR.STYLE_OBJECT = 3; (function() { - var blockElements = { address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1 }; - var 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}; + 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 }, + 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 }; - var semicolonFixRegex = /\s*(?:;\s*|$)/; + var semicolonFixRegex = /\s*(?:;\s*|$)/, + varRegex = /#\((.+?)\)/g; - var notBookmark = CKEDITOR.dom.walker.bookmark( 0, 1 ); + var notBookmark = CKEDITOR.dom.walker.bookmark( 0, 1 ), + nonWhitespaces = CKEDITOR.dom.walker.whitespaces( 1 ); CKEDITOR.style = function( styleDefinition, variablesValues ) { @@ -104,16 +98,22 @@ CKEDITOR.STYLE_OBJECT = 3; replaceVariables( styleDefinition.styles, variablesValues ); } - var element = this.element = ( styleDefinition.element || '*' ).toLowerCase(); + var element = this.element = styleDefinition.element ? + ( typeof styleDefinition.element == 'string' ? styleDefinition.element.toLowerCase() : styleDefinition.element ) + : '*'; this.type = - ( element == '#' || blockElements[ element ] ) ? + blockElements[ element ] ? CKEDITOR.STYLE_BLOCK : objectElements[ element ] ? CKEDITOR.STYLE_OBJECT : CKEDITOR.STYLE_INLINE; + // 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 + if ( typeof this.element == 'object' ) + this.type = CKEDITOR.STYLE_OBJECT; + this._ = { definition : styleDefinition @@ -185,9 +185,12 @@ CKEDITOR.STYLE_OBJECT = 3; && ( element == elementPath.block || element == elementPath.blockLimit ) ) continue; - if( this.type == CKEDITOR.STYLE_OBJECT - && !( element.getName() in objectElements ) ) + if( this.type == CKEDITOR.STYLE_OBJECT ) + { + var name = element.getName(); + if ( !( typeof this.element == 'string' ? name == this.element : name in this.element ) ) continue; + } if ( this.checkElementRemovable( element, true ) ) return true; @@ -219,14 +222,16 @@ CKEDITOR.STYLE_OBJECT = 3; // current style definition. checkElementRemovable : function( element, fullMatch ) { - if ( !element ) + var def = this._.definition; + + if ( !element || !def.ignoreReadonly && element.isReadOnly() ) return false; - var def = this._.definition, - attribs; + var attribs, + name = element.getName(); // If the element name is the same as the style name. - if ( element.getName() == this.element ) + if ( typeof this.element == 'string' ? name == this.element : name in this.element ) { // If no attributes are defined in the element. if ( !fullMatch && !element.hasAttributes() ) @@ -294,7 +299,7 @@ CKEDITOR.STYLE_OBJECT = 3; }, // Builds the preview HTML based on the styles definition. - buildPreview : function() + buildPreview : function( label ) { var styleDefinition = this._.definition, html = [], @@ -321,7 +326,7 @@ CKEDITOR.STYLE_OBJECT = 3; if ( cssStyle ) html.push( ' style="', cssStyle, '"' ); - html.push( '>', styleDefinition.name, '' ); + html.push( '>', ( label || styleDefinition.name ), '' ); return html.join( '' ); } @@ -419,7 +424,8 @@ CKEDITOR.STYLE_OBJECT = 3; var isUnknownElement; // Indicates that fully selected read-only elements are to be included in the styling range. - var includeReadonly = def.includeReadonly; + var ignoreReadonly = def.ignoreReadonly, + includeReadonly = ignoreReadonly || def.includeReadonly; // If the read-only inclusion is not available in the definition, try // to get it from the document data. @@ -443,19 +449,22 @@ CKEDITOR.STYLE_OBJECT = 3; var styleRange; - // Check if the boundaries are inside non stylable elements. - var firstUnstylable = getUnstylableParent( firstNode ), - lastUnstylable = getUnstylableParent( lastNode ); - - // If the first element can't be styled, we'll start processing right - // after its unstylable root. - if ( firstUnstylable ) - currentNode = firstUnstylable.getNextSourceNode( true ); - - // If the last element can't be styled, we'll stop processing on its - // unstylable root. - if ( lastUnstylable ) - lastNode = lastUnstylable; + if ( !ignoreReadonly ) + { + // Check if the boundaries are inside non stylable elements. + var firstUnstylable = getUnstylableParent( firstNode ), + lastUnstylable = getUnstylableParent( lastNode ); + + // If the first element can't be styled, we'll start processing right + // after its unstylable root. + if ( firstUnstylable ) + currentNode = firstUnstylable.getNextSourceNode( true ); + + // If the last element can't be styled, we'll stop processing on its + // unstylable root. + if ( lastUnstylable ) + lastNode = lastUnstylable; + } // Do nothing if the current node now follows the last node to be processed. if ( currentNode.getPosition( lastNode ) == CKEDITOR.POSITION_FOLLOWING ) @@ -703,8 +712,10 @@ CKEDITOR.STYLE_OBJECT = 3; * them before removal. */ element.mergeSiblings(); - removeFromElement( this, element ); - + if ( element.getName() == this.element ) + removeFromElement( this, element ); + else + removeOverrides( element, getOverrides( this )[ element.getName() ] ); } } } @@ -780,7 +791,7 @@ CKEDITOR.STYLE_OBJECT = 3; breakNodes(); // Now, do the DFS walk. - var currentNode = startNode.getNext(); + var currentNode = startNode; while ( !currentNode.equals( endNode ) ) { /* @@ -813,27 +824,26 @@ CKEDITOR.STYLE_OBJECT = 3; } range.moveToBookmark( bookmark ); -} + } function applyObjectStyle( range ) { var root = range.getCommonAncestor( true, true ), - element = root.getAscendant( this.element, true ); - element && setupElement( element, this ); + element = root.getAscendant( this.element, true ); + element && !element.isReadOnly() && setupElement( element, this ); } function removeObjectStyle( range ) { var root = range.getCommonAncestor( true, true ), - element = root.getAscendant( this.element, true ); + element = root.getAscendant( this.element, true ); if ( !element ) return; - var style = this; - var def = style._.definition; - var attributes = def.attributes; - var styles = CKEDITOR.style.getStyleText( def ); + var style = this, + def = style._.definition, + attributes = def.attributes; // Remove all defined attributes. if ( attributes ) @@ -876,8 +886,11 @@ CKEDITOR.STYLE_OBJECT = 3; while ( ( block = iterator.getNextParagraph() ) ) // Only one = { - var newBlock = getElement( this, doc, block ); - replaceBlock( block, newBlock ); + if ( !block.isReadOnly() ) + { + var newBlock = getElement( this, doc, block ); + replaceBlock( block, newBlock ); + } } range.moveToBookmark( bookmark ); @@ -956,7 +969,6 @@ CKEDITOR.STYLE_OBJECT = 3; removeNoAttribsElement( newBlock ); } - var nonWhitespaces = CKEDITOR.dom.walker.whitespaces( 1 ); /** * Merge a
 block with a previous sibling if available.
 	 */
@@ -1025,6 +1037,7 @@ CKEDITOR.STYLE_OBJECT = 3;
 			} );
 		return headBookmark + str.replace( regexp, replacement ) + tailBookmark;
 	}
+
 	/**
 	 * Converting a list of 
 into blocks with format well preserved.
 	 */
@@ -1119,8 +1132,9 @@ CKEDITOR.STYLE_OBJECT = 3;
 	function removeFromElement( style, element )
 	{
 		var def = style._.definition,
-			attributes = CKEDITOR.tools.extend( {}, def.attributes, getOverrides( style )[ element.getName() ] ),
+			attributes = def.attributes,
 			styles = def.styles,
+			overrides = getOverrides( style )[ element.getName() ],
 			// If the style is only about the element itself, we have to remove the element.
 			removeEmpty = CKEDITOR.tools.isEmpty( attributes ) && CKEDITOR.tools.isEmpty( styles );
 
@@ -1146,6 +1160,9 @@ CKEDITOR.STYLE_OBJECT = 3;
 			element.removeStyle( styleName );
 		}
 
+		// Remove overrides, but don't remove the element if it's a block element
+		removeOverrides( element, overrides, blockElements[ element.getName() ] ) ;
+
 		if ( removeEmpty )
 		{
 			!CKEDITOR.dtd.$block[ element.getName() ] || style._.enterMode == CKEDITOR.ENTER_BR && !element.hasAttributes() ?
@@ -1160,9 +1177,8 @@ CKEDITOR.STYLE_OBJECT = 3;
 		var def = style._.definition,
 			attribs = def.attributes,
 			styles = def.styles,
-			overrides = getOverrides( style );
-
-		var innerElements = element.getElementsByTag( style.element );
+			overrides = getOverrides( style ),
+			innerElements = element.getElementsByTag( style.element );
 
 		for ( var i = innerElements.count(); --i >= 0 ; )
 			removeFromElement( style,  innerElements.getItem( i ) );
@@ -1181,7 +1197,6 @@ CKEDITOR.STYLE_OBJECT = 3;
 				}
 			}
 		}
-
 	}
 
 	/**
@@ -1189,8 +1204,9 @@ CKEDITOR.STYLE_OBJECT = 3;
 	 *  Note: Remove the element if no attributes remain.
 	 * @param {Object} element
 	 * @param {Object} overrides
+	 * @param {Boolean} Don't remove the element
 	 */
-	function removeOverrides( element, overrides )
+	function removeOverrides( element, overrides, dontRemove )
 	{
 		var attributes = overrides && overrides.attributes ;
 
@@ -1218,7 +1234,8 @@ CKEDITOR.STYLE_OBJECT = 3;
 			}
 		}
 
-		removeNoAttribsElement( element );
+		if ( !dontRemove )
+			removeNoAttribsElement( element );
 	}
 
 	// If the element has no more attributes, remove it.
@@ -1265,11 +1282,9 @@ CKEDITOR.STYLE_OBJECT = 3;
 
 	function getElement( style, targetDocument, element )
 	{
-		var el;
-
-		var def = style._.definition;
-
-		var elementName = style.element;
+		var el,
+			def = style._.definition,
+			elementName = style.element;
 
 		// The "*" element name will always be a span for this function.
 		if ( elementName == '*' )
@@ -1295,9 +1310,9 @@ CKEDITOR.STYLE_OBJECT = 3;
 
 	function setupElement( el, style )
 	{
-		var def = style._.definition;
-		var attributes = def.attributes;
-		var styles = CKEDITOR.style.getStyleText( def );
+		var def = style._.definition,
+			attributes = def.attributes,
+			styles = CKEDITOR.style.getStyleText( def );
 
 		// Assign all defined attributes.
 		if ( attributes )
@@ -1315,7 +1330,6 @@ CKEDITOR.STYLE_OBJECT = 3;
 		return el;
 	}
 
-	var varRegex = /#\((.+?)\)/g;
 	function replaceVariables( list, variablesValues )
 	{
 		for ( var item in list )
@@ -1327,7 +1341,6 @@ CKEDITOR.STYLE_OBJECT = 3;
 		}
 	}
 
-
 	// Returns an object that can be used for style matching comparison.
 	// Attributes names and values are all lowercased, and the styles get
 	// merged with the style attribute.
@@ -1456,6 +1469,16 @@ CKEDITOR.STYLE_OBJECT = 3;
 		else
 			styleText = unparsedCssText;
 
+		// Normalize font-family property, ignore quotes and being case insensitive. (#7322)
+		// http://www.w3.org/TR/css3-fonts/#font-family-the-font-family-property
+		styleText = styleText.replace( /(font-family:)(.*?)(?=;|$)/, function ( match, prop, val )
+		{
+			var names = val.split( ',' );
+			for ( var i = 0; i < names.length; i++ )
+				names[ i ] = CKEDITOR.tools.trim( names[ i ].replace( /["']/g, '' ) );
+			return prop + names.join( ',' );
+		});
+
 		// Shrinking white-spaces around colon and semi-colon (#4147).
 		// Compensate tail semi-colon.
 		return styleText.replace( /\s*([;:])\s*/, '$1' )
@@ -1507,6 +1530,8 @@ CKEDITOR.STYLE_OBJECT = 3;
 	function applyStyle( document, remove )
 	{
 		var selection = document.getSelection(),
+			// Bookmark the range so we can re-select it after processing.
+			bookmarks = selection.createBookmarks( 1 ),
 			ranges = selection.getRanges(),
 			func = remove ? this.removeFromRange : this.applyToRange,
 			range;
@@ -1515,7 +1540,13 @@ CKEDITOR.STYLE_OBJECT = 3;
 		while ( ( range = iterator.getNextRange() ) )
 			func.call( this, range );
 
-		selection.selectRanges( ranges );
+		if ( bookmarks.length == 1 && bookmarks[ 0 ].collapsed )
+		{
+			selection.selectRanges( ranges );
+			document.getById( bookmarks[ 0 ].startNode ).remove();
+		}
+		else
+			selection.selectBookmarks( bookmarks );
 
 		document.removeCustomData( 'doc_processing_style' );
 	}
@@ -1543,6 +1574,37 @@ CKEDITOR.styleCommand.prototype.exec = function( editor )
 	return !!doc;
 };
 
+/**
+ * Manages styles registration and loading. See also {@link CKEDITOR.config.stylesSet}.
+ * @namespace
+ * @augments CKEDITOR.resourceManager
+ * @constructor
+ * @since 3.2
+ * @example
+ * // The set of styles for the Styles combo
+ * CKEDITOR.stylesSet.add( 'default',
+ * [
+ * 	// Block Styles
+ * 	{ name : 'Blue Title'		, element : 'h3', styles : { 'color' : 'Blue' } },
+ * 	{ name : 'Red Title'		, element : 'h3', styles : { 'color' : 'Red' } },
+ *
+ * 	// Inline Styles
+ * 	{ name : 'Marker: Yellow'	, element : 'span', styles : { 'background-color' : 'Yellow' } },
+ * 	{ name : 'Marker: Green'	, element : 'span', styles : { 'background-color' : 'Lime' } },
+ *
+ * 	// Object Styles
+ * 	{
+ * 		name : 'Image on Left',
+ * 		element : 'img',
+ * 		attributes :
+ * 		{
+ * 			'style' : 'padding: 5px; margin-right: 5px',
+ * 			'border' : '2',
+ * 			'align' : 'left'
+ * 		}
+ * 	}
+ * ]);
+ */
 CKEDITOR.stylesSet = new CKEDITOR.resourceManager( '', 'stylesSet' );
 
 // Backward compatibility (#5025).