      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 (function()
      7 {
      8 	CKEDITOR.htmlParser.filter = CKEDITOR.tools.createClass(
      9 	{
     10 		$ : function( rules )
     11 		{
     12 			this._ =
     13 			{
     14 				elementNames : [],
     15 				attributeNames : [],
     16 				elements : { $length : 0 },
     17 				attributes : { $length : 0 }
     18 			};
     19
     20 			if ( rules )
     21 				this.addRules( rules, 10 );
     22 		},
     23
     24 		proto :
     25 		{
     26 			addRules : function( rules, priority )
     27 			{
     28 				if ( typeof priority != 'number' )
     29 					priority = 10;
     30
     31 				// Add the elementNames.
     32 				addItemsToList( this._.elementNames, rules.elementNames, priority );
     33
     34 				// Add the attributeNames.
     35 				addItemsToList( this._.attributeNames, rules.attributeNames, priority );
     36
     37 				// Add the elements.
     38 				addNamedItems( this._.elements, rules.elements, priority );
     39
     40 				// Add the attributes.
     41 				addNamedItems( this._.attributes, rules.attributes, priority );
     42
     43 				// Add the text.
     44 				this._.text = transformNamedItem( this._.text, rules.text, priority ) || this._.text;
     45
     46 				// Add the comment.
     47 				this._.comment = transformNamedItem( this._.comment, rules.comment, priority ) || this._.comment;
     48 			},
     49
     50 			onElementName : function( name )
     51 			{
     52 				return filterName( name, this._.elementNames );
     53 			},
     54
     55 			onAttributeName : function( name )
     56 			{
     57 				return filterName( name, this._.attributeNames );
     58 			},
     59
     60 			onText : function( text )
     61 			{
     62 				var textFilter = this._.text;
     63 				return textFilter ? textFilter.filter( text ) : text;
     64 			},
     65
     66 			onComment : function( commentText )
     67 			{
     68 				var textFilter = this._.comment;
     69 				return textFilter ? textFilter.filter( commentText ) : commentText;
     70 			},
     71
     72 			onElement : function( element )
     73 			{
     74 				// We must apply filters set to the specific element name as
     75 				// well as those set to the generic $ name. So, add both to an
     76 				// array and process them in a small loop.
     77 				var filters = [ this._.elements[ element.name ], this._.elements.$ ],
     78 					filter, ret;
     79
     80 				for ( var i = 0 ; i < 2 ; i++ )
     81 				{
     82 					filter = filters[ i ];
     83 					if ( filter )
     84 					{
     85 						ret = filter.filter( element, this );
     86
     87 						if ( ret === false )
     88 							return null;
     89
     90 						if ( ret && ret != element )
     91 							return this.onElement( ret );
     92 					}
     93 				}
     94
     95 				return element;
     96 			},
     97
     98 			onAttribute : function( element, name, value )
     99 			{
    100 				var filter = this._.attributes[ name ];
    101
    102 				if ( filter )
    103 				{
    104 					var ret = filter.filter( value, element, this );
    105
    106 					if ( ret === false )
    107 						return false;
    108
    109 					if ( typeof ret != 'undefined' )
    110 						return ret;
    111 				}
    112
    113 				return value;
    114 			}
    115 		}
    116 	});
    117
    118 	function filterName( name, filters )
    119 	{
    120 		for ( var i = 0 ; name && i < filters.length ; i++ )
    121 		{
    122 			var filter = filters[ i ];
    123 			name = name.replace( filter[ 0 ], filter[ 1 ] );
    124 		}
    125 		return name;
    126 	}
    127
    128 	function addItemsToList( list, items, priority )
    129 	{
    130 		var i, j,
    131 			listLength = list.length,
    132 			itemsLength = items && items.length;
    133
    134 		if ( itemsLength )
    135 		{
    136 			// Find the index to insert the items at.
    137 			for ( i = 0 ; i < listLength && list[ i ].pri < priority ; i++ )
    138 			{ /*jsl:pass*/ }
    139
    140 			// Add all new items to the list at the specific index.
    141 			for ( j = itemsLength - 1 ; j >= 0 ; j-- )
    142 			{
    143 				var item = items[ j ];
    144 				item.pri = priority;
    145 				list.splice( i, 0, item );
    146 			}
    147 		}
    148 	}
    149
    150 	function addNamedItems( hashTable, items, priority )
    151 	{
    152 		if ( items )
    153 		{
    154 			for ( var name in items )
    155 			{
    156 				var current = hashTable[ name ];
    157
    158 				hashTable[ name ] =
    159 					transformNamedItem(
    160 						current,
    161 						items[ name ],
    162 						priority );
    163
    164 				if ( !current )
    165 					hashTable.$length++;
    166 			}
    167 		}
    168 	}
    169
    170 	function transformNamedItem( current, item, priority )
    171 	{
    172 		if ( item )
    173 		{
    174 			item.pri = priority;
    175
    176 			if ( current )
    177 			{
    178 				// If the current item is not an Array, transform it.
    179 				if ( !current.splice )
    180 				{
    181 					if ( current.pri > priority )
    182 						current = [ item, current ];
    183 					else
    184 						current = [ current, item ];
    185
    186 					current.filter = callItems;
    187 				}
    188 				else
    189 					addItemsToList( current, item, priority );
    190
    191 				return current;
    192 			}
    193 			else
    194 			{
    195 				item.filter = item;
    196 				return item;
    197 			}
    198 		}
    199 	}
    200
    201 	function callItems( currentEntry )
    202 	{
    203 		var isObject = ( typeof currentEntry == 'object' );
    204
    205 		for ( var i = 0 ; i < this.length ; i++ )
    206 		{
    207 			var item = this[ i ],
    208 				ret = item.apply( window, arguments );
    209
    210 			if ( typeof ret != 'undefined' )
    211 			{
    212 				if ( ret === false )
    213 					return false;
    214
    215 				if ( isObject && ret != currentEntry )
    216 					return ret;
    217 			}
    218 		}
    219
    220 		return null;
    221 	}
    222 })();
    223
    224 // "entities" plugin
    225 /*
    226 {
    227 	text : function( text )
    228 	{
    229 		// TODO : Process entities.
    230 		return text.toUpperCase();
    231 	}
    232 };
    233 */
    234