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 				}
132
133 				// The element may have been changed, so update the local
134 				// references.
135 				attributes = element.attributes;
136 			}
137
138 			// Open element tag.
139 			writer.openTag( writeName, attributes );
140
141 			if ( writer.sortAttributes )
142 			{
143 				// Copy all attributes to an array.
144 				var attribsArray = [];
145 				for ( a in attributes )
146 				{
147 					value = attributes[ a ];
148
149 					if ( filter && ( !( a = filter.onAttributeName( a ) ) || ( value = filter.onAttribute( element, a, value ) ) === false ) )
150 						continue;
151
152 					attribsArray.push( [ a, value ] );
153 				}
154
155 				// Sort the attributes by name.
156 				attribsArray.sort( sortAttribs );
157
158 				// Send the attributes.
159 				for ( var i = 0, len = attribsArray.length ; i < len ; i++ )
160 				{
161 					var attrib = attribsArray[ i ];
162 					writer.attribute( attrib[0], attrib[1] );
163 				}
164 			}
165 			else
166 			{
167 				for ( a in attributes )
168 				{
169 					writer.attribute( a, attributes[ a ] );
170 				}
171 			}
172
173 			// Close the tag.
174 			writer.openTagClose( writeName, element.isEmpty );
175
176 			if ( !element.isEmpty )
177 			{
178 				// Send children.
179 				CKEDITOR.htmlParser.fragment.prototype.writeHtml.apply( element, arguments );
180
181 				// Close the element.
182 				writer.closeTag( writeName );
183 			}
184 		}
185 	};
186 })();
187