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