/* Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ (function() { CKEDITOR.htmlParser.filter = CKEDITOR.tools.createClass( { $ : function( rules ) { this._ = { elementNames : [], attributeNames : [], elements : { $length : 0 }, attributes : { $length : 0 } }; if ( rules ) this.addRules( rules, 10 ); }, proto : { addRules : function( rules, priority ) { if ( typeof priority != 'number' ) priority = 10; // Add the elementNames. addItemsToList( this._.elementNames, rules.elementNames, priority ); // Add the attributeNames. addItemsToList( this._.attributeNames, rules.attributeNames, priority ); // Add the elements. addNamedItems( this._.elements, rules.elements, priority ); // Add the attributes. addNamedItems( this._.attributes, rules.attributes, priority ); // Add the text. this._.text = transformNamedItem( this._.text, rules.text, priority ) || this._.text; // Add the comment. this._.comment = transformNamedItem( this._.comment, rules.comment, priority ) || this._.comment; // Add root fragment. this._.root = transformNamedItem( this._.root, rules.root, priority ) || this._.root; }, onElementName : function( name ) { return filterName( name, this._.elementNames ); }, onAttributeName : function( name ) { return filterName( name, this._.attributeNames ); }, onText : function( text ) { var textFilter = this._.text; return textFilter ? textFilter.filter( text ) : text; }, onComment : function( commentText, comment ) { var textFilter = this._.comment; return textFilter ? textFilter.filter( commentText, comment ) : commentText; }, onFragment : function( element ) { var rootFilter = this._.root; return rootFilter ? rootFilter.filter( element ) : element; }, onElement : function( element ) { // We must apply filters set to the specific element name as // well as those set to the generic $ name. So, add both to an // array and process them in a small loop. var filters = [ this._.elements[ '^' ], this._.elements[ element.name ], this._.elements.$ ], filter, ret; for ( var i = 0 ; i < 3 ; i++ ) { filter = filters[ i ]; if ( filter ) { ret = filter.filter( element, this ); if ( ret === false ) return null; if ( ret && ret != element ) return this.onNode( ret ); // The non-root element has been dismissed by one of the filters. if ( element.parent && !element.name ) break; } } return element; }, onNode : function( node ) { var type = node.type; return type == CKEDITOR.NODE_ELEMENT ? this.onElement( node ) : type == CKEDITOR.NODE_TEXT ? new CKEDITOR.htmlParser.text( this.onText( node.value ) ) : type == CKEDITOR.NODE_COMMENT ? new CKEDITOR.htmlParser.comment( this.onComment( node.value ) ): null; }, onAttribute : function( element, name, value ) { var filter = this._.attributes[ name ]; if ( filter ) { var ret = filter.filter( value, element, this ); if ( ret === false ) return false; if ( typeof ret != 'undefined' ) return ret; } return value; } } }); function filterName( name, filters ) { for ( var i = 0 ; name && i < filters.length ; i++ ) { var filter = filters[ i ]; name = name.replace( filter[ 0 ], filter[ 1 ] ); } return name; } function addItemsToList( list, items, priority ) { if ( typeof items == 'function' ) items = [ items ]; var i, j, listLength = list.length, itemsLength = items && items.length; if ( itemsLength ) { // Find the index to insert the items at. for ( i = 0 ; i < listLength && list[ i ].pri < priority ; i++ ) { /*jsl:pass*/ } // Add all new items to the list at the specific index. for ( j = itemsLength - 1 ; j >= 0 ; j-- ) { var item = items[ j ]; if ( item ) { item.pri = priority; list.splice( i, 0, item ); } } } } function addNamedItems( hashTable, items, priority ) { if ( items ) { for ( var name in items ) { var current = hashTable[ name ]; hashTable[ name ] = transformNamedItem( current, items[ name ], priority ); if ( !current ) hashTable.$length++; } } } function transformNamedItem( current, item, priority ) { if ( item ) { item.pri = priority; if ( current ) { // If the current item is not an Array, transform it. if ( !current.splice ) { if ( current.pri > priority ) current = [ item, current ]; else current = [ current, item ]; current.filter = callItems; } else addItemsToList( current, item, priority ); return current; } else { item.filter = item; return item; } } } // Invoke filters sequentially on the array, break the iteration // when it doesn't make sense to continue anymore. function callItems( currentEntry ) { var isNode = currentEntry.type || currentEntry instanceof CKEDITOR.htmlParser.fragment; for ( var i = 0 ; i < this.length ; i++ ) { // Backup the node info before filtering. if ( isNode ) { var orgType = currentEntry.type, orgName = currentEntry.name; } var item = this[ i ], ret = item.apply( window, arguments ); if ( ret === false ) return ret; // We're filtering node (element/fragment). if ( isNode ) { // No further filtering if it's not anymore // fitable for the subsequent filters. if ( ret && ( ret.name != orgName || ret.type != orgType ) ) { return ret; } } // Filtering value (nodeName/textValue/attrValue). else { // No further filtering if it's not // any more values. if ( typeof ret != 'string' ) return ret; } ret != undefined && ( currentEntry = ret ); } return currentEntry; } })(); // "entities" plugin /* { text : function( text ) { // TODO : Process entities. return text.toUpperCase(); } }; */