      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