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, pluginPath ) 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