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