initial commit
[namibia] / public / scripts / ckeditor / _source / core / htmlparser / filter.js
1 /*
2 Copyright (c) 2003-2011, 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                                 // Add root fragment.
50                                 this._.root = transformNamedItem( this._.root, rules.root, priority ) || this._.root;
51                         },
52
53                         onElementName : function( name )
54                         {
55                                 return filterName( name, this._.elementNames );
56                         },
57
58                         onAttributeName : function( name )
59                         {
60                                 return filterName( name, this._.attributeNames );
61                         },
62
63                         onText : function( text )
64                         {
65                                 var textFilter = this._.text;
66                                 return textFilter ? textFilter.filter( text ) : text;
67                         },
68
69                         onComment : function( commentText, comment )
70                         {
71                                 var textFilter = this._.comment;
72                                 return textFilter ? textFilter.filter( commentText, comment ) : commentText;
73                         },
74
75                         onFragment : function( element )
76                         {
77                                 var rootFilter = this._.root;
78                                 return rootFilter ? rootFilter.filter( element ) : element;
79                         },
80
81                         onElement : function( element )
82                         {
83                                 // We must apply filters set to the specific element name as
84                                 // well as those set to the generic $ name. So, add both to an
85                                 // array and process them in a small loop.
86                                 var filters = [ this._.elements[ '^' ], this._.elements[ element.name ], this._.elements.$ ],
87                                         filter, ret;
88
89                                 for ( var i = 0 ; i < 3 ; i++ )
90                                 {
91                                         filter = filters[ i ];
92                                         if ( filter )
93                                         {
94                                                 ret = filter.filter( element, this );
95
96                                                 if ( ret === false )
97                                                         return null;
98
99                                                 if ( ret && ret != element )
100                                                         return this.onNode( ret );
101
102                                                 // The non-root element has been dismissed by one of the filters.
103                                                 if ( element.parent && !element.name )
104                                                         break;
105                                         }
106                                 }
107
108                                 return element;
109                         },
110
111                         onNode : function( node )
112                         {
113                                 var type = node.type;
114
115                                 return type == CKEDITOR.NODE_ELEMENT ? this.onElement( node ) :
116                                         type == CKEDITOR.NODE_TEXT ? new CKEDITOR.htmlParser.text( this.onText( node.value ) ) :
117                                         type == CKEDITOR.NODE_COMMENT ? new CKEDITOR.htmlParser.comment( this.onComment( node.value ) ):
118                                         null;
119                         },
120
121                         onAttribute : function( element, name, value )
122                         {
123                                 var filter = this._.attributes[ name ];
124
125                                 if ( filter )
126                                 {
127                                         var ret = filter.filter( value, element, this );
128
129                                         if ( ret === false )
130                                                 return false;
131
132                                         if ( typeof ret != 'undefined' )
133                                                 return ret;
134                                 }
135
136                                 return value;
137                         }
138                 }
139         });
140
141         function filterName( name, filters )
142         {
143                 for ( var i = 0 ; name && i < filters.length ; i++ )
144                 {
145                         var filter = filters[ i ];
146                         name = name.replace( filter[ 0 ], filter[ 1 ] );
147                 }
148                 return name;
149         }
150
151         function addItemsToList( list, items, priority )
152         {
153                 if ( typeof items == 'function' )
154                         items = [ items ];
155
156                 var i, j,
157                         listLength = list.length,
158                         itemsLength = items && items.length;
159
160                 if ( itemsLength )
161                 {
162                         // Find the index to insert the items at.
163                         for ( i = 0 ; i < listLength && list[ i ].pri < priority ; i++ )
164                         { /*jsl:pass*/ }
165
166                         // Add all new items to the list at the specific index.
167                         for ( j = itemsLength - 1 ; j >= 0 ; j-- )
168                         {
169                                 var item = items[ j ];
170                                 if ( item )
171                                 {
172                                         item.pri = priority;
173                                         list.splice( i, 0, item );
174                                 }
175                         }
176                 }
177         }
178
179         function addNamedItems( hashTable, items, priority )
180         {
181                 if ( items )
182                 {
183                         for ( var name in items )
184                         {
185                                 var current = hashTable[ name ];
186
187                                 hashTable[ name ] =
188                                         transformNamedItem(
189                                                 current,
190                                                 items[ name ],
191                                                 priority );
192
193                                 if ( !current )
194                                         hashTable.$length++;
195                         }
196                 }
197         }
198
199         function transformNamedItem( current, item, priority )
200         {
201                 if ( item )
202                 {
203                         item.pri = priority;
204
205                         if ( current )
206                         {
207                                 // If the current item is not an Array, transform it.
208                                 if ( !current.splice )
209                                 {
210                                         if ( current.pri > priority )
211                                                 current = [ item, current ];
212                                         else
213                                                 current = [ current, item ];
214
215                                         current.filter = callItems;
216                                 }
217                                 else
218                                         addItemsToList( current, item, priority );
219
220                                 return current;
221                         }
222                         else
223                         {
224                                 item.filter = item;
225                                 return item;
226                         }
227                 }
228         }
229
230         // Invoke filters sequentially on the array, break the iteration
231         // when it doesn't make sense to continue anymore.
232         function callItems( currentEntry )
233         {
234                 var isNode = currentEntry.type
235                         || currentEntry instanceof CKEDITOR.htmlParser.fragment;
236
237                 for ( var i = 0 ; i < this.length ; i++ )
238                 {
239                         // Backup the node info before filtering.
240                         if ( isNode )
241                         {
242                                 var orgType = currentEntry.type,
243                                                 orgName = currentEntry.name;
244                         }
245
246                         var item = this[ i ],
247                                 ret = item.apply( window, arguments );
248
249                         if ( ret === false )
250                                 return ret;
251
252                         // We're filtering node (element/fragment).
253                         if ( isNode )
254                         {
255                                 // No further filtering if it's not anymore
256                                 // fitable for the subsequent filters.
257                                 if ( ret && ( ret.name != orgName
258                                         || ret.type != orgType ) )
259                                 {
260                                         return ret;
261                                 }
262                         }
263                         // Filtering value (nodeName/textValue/attrValue).
264                         else
265                         {
266                                 // No further filtering if it's not
267                                 // any more values.
268                                 if ( typeof ret != 'string' )
269                                         return ret;
270                         }
271
272                         ret != undefined && ( currentEntry = ret );
273                 }
274
275                 return currentEntry;
276         }
277 })();
278
279 // "entities" plugin
280 /*
281 {
282         text : function( text )
283         {
284                 // TODO : Process entities.
285                 return text.toUpperCase();
286         }
287 };
288 */