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 /**
  7  * A lightweight representation of an HTML element.
  8  * @param {String} name The element name.
  9  * @param {Object} attributes And object holding all attributes defined for
 10  *		this element.
 11  * @constructor
 12  * @example
 13  */
 14 CKEDITOR.htmlParser.element = function( name, attributes )
 15 {
 16 	/**
 17 	 * The element name.
 18 	 * @type String
 19 	 * @example
 20 	 */
 21 	this.name = name;
 22
 23 	/**
 24 	 * Holds the attributes defined for this element.
 25 	 * @type Object
 26 	 * @example
 27 	 */
 28 	this.attributes = attributes;
 29
 30 	/**
 31 	 * The nodes that are direct children of this element.
 32 	 * @type Array
 33 	 * @example
 34 	 */
 35 	this.children = [];
 36
 37 	var dtd			= CKEDITOR.dtd,
 38 		isBlockLike	= !!( dtd.$block[ name ] || dtd.$listItem[ name ] || dtd.$tableContent[ name ] ),
 39 		isEmpty		= !!dtd.$empty[ name ];
 40
 41 	this.isEmpty	= isEmpty;
 42 	this.isUnknown	= !dtd[ name ];
 43
 44 	/** @private */
 45 	this._ =
 46 	{
 47 		isBlockLike : isBlockLike,
 48 		hasInlineStarted : isEmpty || !isBlockLike
 49 	};
 50 };
 51
 52 (function()
 53 {
 54 	// Used to sort attribute entries in an array, where the first element of
 55 	// each object is the attribute name.
 56 	var sortAttribs = function( a, b )
 57 	{
 58 		a = a[0];
 59 		b = b[0];
 60 		return a < b ? -1 : a > b ? 1 : 0;
 61 	};
 62
 63 	CKEDITOR.htmlParser.element.prototype =
 64 	{
 65 		/**
 66 		 * The node type. This is a constant value set to {@link CKEDITOR.NODE_ELEMENT}.
 67 		 * @type Number
 68 		 * @example
 69 		 */
 70 		type : CKEDITOR.NODE_ELEMENT,
 71
 72 		/**
 73 		 * Adds a node to the element children list.
 74 		 * @param {Object} node The node to be added. It can be any of of the
 75 		 *		following types: {@link CKEDITOR.htmlParser.element},
 76 		 *		{@link CKEDITOR.htmlParser.text} and
 77 		 *		{@link CKEDITOR.htmlParser.comment}.
 78 		 * @function
 79 		 * @example
 80 		 */
 81 		add : CKEDITOR.htmlParser.fragment.prototype.add,
 82
 83 		/**
 84 		 * Clone this element.
 85 		 * @returns {CKEDITOR.htmlParser.element} The element clone.
 86 		 * @example
 87 		 */
 88 		clone : function()
 89 		{
 90 			return new CKEDITOR.htmlParser.element( this.name, this.attributes );
 91 		},
 92
 93 		/**
 94 		 * Writes the element HTML to a CKEDITOR.htmlWriter.
 95 		 * @param {CKEDITOR.htmlWriter} writer The writer to which write the HTML.
 96 		 * @example
 97 		 */
 98 		writeHtml : function( writer, filter )
 99 		{
100 			var attributes = this.attributes;
101
102 			// The "_cke_replacedata" indicates that this element is replacing
103 			// a data snippet, which should be outputted as is.
104 			if ( attributes._cke_replacedata )
105 			{
106 				writer.write( attributes._cke_replacedata );
107 				return;
108 			}
109
110 			// Ignore cke: prefixes when writing HTML.
111 			var element = this,
112 				writeName = element.name,
113 				a, value;
114
115 			if ( filter )
116 			{
117 				while ( true )
118 				{
119 					if ( !( writeName = filter.onElementName( writeName ) ) )
120 						return;
121
122 					element.name = writeName;
123
124 					if ( !( element = filter.onElement( element ) ) )
125 						return;
126
127 					if ( element.name == writeName )
128 						break;
129
130 					writeName = element.name;
131 					if ( !writeName )	// Send children.
132 					{
133 						CKEDITOR.htmlParser.fragment.prototype.writeHtml.apply( element, arguments );
134 						return;
135 					}
136 				}
137
138 				// The element may have been changed, so update the local
139 				// references.
140 				attributes = element.attributes;
141 			}
142
143 			// Open element tag.
144 			writer.openTag( writeName, attributes );
145
146 			if ( writer.sortAttributes )
147 			{
148 				// Copy all attributes to an array.
149 				var attribsArray = [];
150 				for ( a in attributes )
151 				{
152 					value = attributes[ a ];
153
154 					if ( filter && ( !( a = filter.onAttributeName( a ) ) || ( value = filter.onAttribute( element, a, value ) ) === false ) )
155 						continue;
156
157 					attribsArray.push( [ a, value ] );
158 				}
159
160 				// Sort the attributes by name.
161 				attribsArray.sort( sortAttribs );
162
163 				// Send the attributes.
164 				for ( var i = 0, len = attribsArray.length ; i < len ; i++ )
165 				{
166 					var attrib = attribsArray[ i ];
167 					writer.attribute( attrib[0], attrib[1] );
168 				}
169 			}
170 			else
171 			{
172 				for ( a in attributes )
173 				{
174 					value = attributes[ a ];
175
176 					if ( filter && ( !( a = filter.onAttributeName( a ) ) || ( value = filter.onAttribute( element, a, value ) ) === false ) )
177 						continue;
178
179 					writer.attribute( a, value );
180 				}
181 			}
182
183 			// Close the tag.
184 			writer.openTagClose( writeName, element.isEmpty );
185
186 			if ( !element.isEmpty )
187 			{
188 				// Send children.
189 				CKEDITOR.htmlParser.fragment.prototype.writeHtml.apply( element, arguments );
190
191 				// Close the element.
192 				writer.closeTag( writeName );
193 			}
194 		}
195 	};
196 })();
197