      1 ﻿/*
      2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
      3 For licensing, see LICENSE.html or http://ckeditor.com/license
      4 */
      5
      6 CKEDITOR.plugins.add( 'removeformat',
      7 {
      8 	requires : [ 'selection' ],
      9
     10 	init : function( editor )
     11 	{
     12 		editor.addCommand( 'removeFormat', CKEDITOR.plugins.removeformat.commands.removeformat );
     13 		editor.ui.addButton( 'RemoveFormat',
     14 			{
     15 				label : editor.lang.removeFormat,
     16 				command : 'removeFormat'
     17 			});
     18 	}
     19 });
     20
     21 CKEDITOR.plugins.removeformat =
     22 {
     23 	commands :
     24 	{
     25 		removeformat :
     26 		{
     27 			exec : function( editor )
     28 			{
     29 				var tagsRegex = editor._.removeFormatRegex ||
     30 					( editor._.removeFormatRegex = new RegExp( '^(?:' + editor.config.removeFormatTags.replace( /,/g,'|' ) + ')$', 'i' ) );
     31
     32 				var removeAttributes = editor._.removeAttributes ||
     33 					( editor._.removeAttributes = editor.config.removeFormatAttributes.split( ',' ) );
     34
     35 				var ranges = editor.getSelection().getRanges();
     36
     37 				for ( var i = 0, range ; range = ranges[ i ] ; i++ )
     38 				{
     39 					if ( range.collapsed )
     40 						continue;
     41
     42 					range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
     43
     44 					// Bookmark the range so we can re-select it after processing.
     45 					var bookmark = range.createBookmark();
     46
     47 					// The style will be applied within the bookmark boundaries.
     48 					var startNode	= bookmark.startNode;
     49 					var endNode		= bookmark.endNode;
     50
     51 					// We need to check the selection boundaries (bookmark spans) to break
     52 					// the code in a way that we can properly remove partially selected nodes.
     53 					// For example, removing a <b> style from
     54 					//		<b>This is [some text</b> to show <b>the] problem</b>
     55 					// ... where [ and ] represent the selection, must result:
     56 					//		<b>This is </b>[some text to show the]<b> problem</b>
     57 					// The strategy is simple, we just break the partial nodes before the
     58 					// removal logic, having something that could be represented this way:
     59 					//		<b>This is </b>[<b>some text</b> to show <b>the</b>]<b> problem</b>
     60
     61 					var breakParent = function( node )
     62 					{
     63 						// Let's start checking the start boundary.
     64 						var path = new CKEDITOR.dom.elementPath( node );
     65 						var pathElements = path.elements;
     66
     67 						for ( var i = 1, pathElement ; pathElement = pathElements[ i ] ; i++ )
     68 						{
     69 							if ( pathElement.equals( path.block ) || pathElement.equals( path.blockLimit ) )
     70 								break;
     71
     72 							// If this element can be removed (even partially).
     73 							if ( tagsRegex.test( pathElement.getName() ) )
     74 								node.breakParent( pathElement );
     75 						}
     76 					};
     77
     78 					breakParent( startNode );
     79 					breakParent( endNode );
     80
     81 					// Navigate through all nodes between the bookmarks.
     82 					var currentNode = startNode.getNextSourceNode( true, CKEDITOR.NODE_ELEMENT );
     83
     84 					while ( currentNode )
     85 					{
     86 						// If we have reached the end of the selection, stop looping.
     87 						if ( currentNode.equals( endNode ) )
     88 							break;
     89
     90 						// Cache the next node to be processed. Do it now, because
     91 						// currentNode may be removed.
     92 						var nextNode = currentNode.getNextSourceNode( false, CKEDITOR.NODE_ELEMENT );
     93
     94 						// This node must not be a fake element.
     95 						if ( currentNode.getName() != 'img' || !currentNode.getAttribute( '_cke_protected_html' ) )
     96 						{
     97 							// Remove elements nodes that match with this style rules.
     98 							if ( tagsRegex.test( currentNode.getName() ) )
     99 								currentNode.remove( true );
    100 							else
    101 								currentNode.removeAttributes( removeAttributes );
    102 						}
    103
    104 						currentNode = nextNode;
    105 					}
    106
    107 					range.moveToBookmark( bookmark );
    108 				}
    109
    110 				editor.getSelection().selectRanges( ranges );
    111 			}
    112 		}
    113 	}
    114 };
    115
    116 // Only inline elements are valid.
    117 CKEDITOR.config.removeFormatTags = 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var';
    118
    119 CKEDITOR.config.removeFormatAttributes = 'class,style,lang,width,height,align,hspace,valign';
    120