JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.1
[ckeditor.git] / _source / plugins / htmlwriter / plugin.js
1 /*\r
2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
3 For licensing, see LICENSE.html or http://ckeditor.com/license\r
4 */\r
5 \r
6 CKEDITOR.plugins.add( 'htmlwriter' );\r
7 \r
8 /**\r
9  * Class used to write HTML data.\r
10  * @constructor\r
11  * @example\r
12  * var writer = new CKEDITOR.htmlWriter();\r
13  * writer.openTag( 'p' );\r
14  * writer.attribute( 'class', 'MyClass' );\r
15  * writer.openTagClose( 'p' );\r
16  * writer.text( 'Hello' );\r
17  * writer.closeTag( 'p' );\r
18  * alert( writer.getHtml() );  "<p class="MyClass">Hello</p>"\r
19  */\r
20 CKEDITOR.htmlWriter = CKEDITOR.tools.createClass(\r
21 {\r
22         base : CKEDITOR.htmlParser.basicWriter,\r
23 \r
24         $ : function()\r
25         {\r
26                 // Call the base contructor.\r
27                 this.base();\r
28 \r
29                 /**\r
30                  * The characters to be used for each identation step.\r
31                  * @type String\r
32                  * @default "\t" (tab)\r
33                  * @example\r
34                  * // Use two spaces for indentation.\r
35                  * editorInstance.dataProcessor.writer.indentationChars = '  ';\r
36                  */\r
37                 this.indentationChars = '\t';\r
38 \r
39                 /**\r
40                  * The characters to be used to close "self-closing" elements, like "br" or\r
41                  * "img".\r
42                  * @type String\r
43                  * @default " />"\r
44                  * @example\r
45                  * // Use HTML4 notation for self-closing elements.\r
46                  * editorInstance.dataProcessor.writer.selfClosingEnd = '>';\r
47                  */\r
48                 this.selfClosingEnd = ' />';\r
49 \r
50                 /**\r
51                  * The characters to be used for line breaks.\r
52                  * @type String\r
53                  * @default "\n" (LF)\r
54                  * @example\r
55                  * // Use CRLF for line breaks.\r
56                  * editorInstance.dataProcessor.writer.lineBreakChars = '\r\n';\r
57                  */\r
58                 this.lineBreakChars = '\n';\r
59 \r
60                 this.forceSimpleAmpersand = false;\r
61 \r
62                 this.sortAttributes = true;\r
63 \r
64                 this._.indent = false;\r
65                 this._.indentation = '';\r
66                 this._.rules = {};\r
67 \r
68                 var dtd = CKEDITOR.dtd;\r
69 \r
70                 for ( var e in CKEDITOR.tools.extend( {}, dtd.$nonBodyContent, dtd.$block, dtd.$listItem, dtd.$tableContent ) )\r
71                 {\r
72                         this.setRules( e,\r
73                                 {\r
74                                         indent : true,\r
75                                         breakBeforeOpen : true,\r
76                                         breakAfterOpen : true,\r
77                                         breakBeforeClose : !dtd[ e ][ '#' ],\r
78                                         breakAfterClose : true\r
79                                 });\r
80                 }\r
81 \r
82                 this.setRules( 'br',\r
83                         {\r
84                                 breakAfterOpen : true\r
85                         });\r
86 \r
87                 this.setRules( 'title',\r
88                         {\r
89                                 indent : false,\r
90                                 breakAfterOpen : false\r
91                         });\r
92 \r
93                 this.setRules( 'style',\r
94                         {\r
95                                 indent : false,\r
96                                 breakBeforeClose : true\r
97                         });\r
98 \r
99                 // Disable indentation on <pre>.\r
100                 this.setRules( 'pre',\r
101                         {\r
102                           indent: false\r
103                         });\r
104         },\r
105 \r
106         proto :\r
107         {\r
108                 /**\r
109                  * Writes the tag opening part for a opener tag.\r
110                  * @param {String} tagName The element name for this tag.\r
111                  * @param {Object} attributes The attributes defined for this tag. The\r
112                  *              attributes could be used to inspect the tag.\r
113                  * @example\r
114                  * // Writes "&lt;p".\r
115                  * writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } );\r
116                  */\r
117                 openTag : function( tagName, attributes )\r
118                 {\r
119                         var rules = this._.rules[ tagName ];\r
120 \r
121                         if ( this._.indent )\r
122                                 this.indentation();\r
123                         // Do not break if indenting.\r
124                         else if ( rules && rules.breakBeforeOpen )\r
125                         {\r
126                                 this.lineBreak();\r
127                                 this.indentation();\r
128                         }\r
129 \r
130                         this._.output.push( '<', tagName );\r
131                 },\r
132 \r
133                 /**\r
134                  * Writes the tag closing part for a opener tag.\r
135                  * @param {String} tagName The element name for this tag.\r
136                  * @param {Boolean} isSelfClose Indicates that this is a self-closing tag,\r
137                  *              like "br" or "img".\r
138                  * @example\r
139                  * // Writes "&gt;".\r
140                  * writer.openTagClose( 'p', false );\r
141                  * @example\r
142                  * // Writes " /&gt;".\r
143                  * writer.openTagClose( 'br', true );\r
144                  */\r
145                 openTagClose : function( tagName, isSelfClose )\r
146                 {\r
147                         var rules = this._.rules[ tagName ];\r
148 \r
149                         if ( isSelfClose )\r
150                                 this._.output.push( this.selfClosingEnd );\r
151                         else\r
152                         {\r
153                                 this._.output.push( '>' );\r
154 \r
155                                 if ( rules && rules.indent )\r
156                                         this._.indentation += this.indentationChars;\r
157                         }\r
158 \r
159                         if ( rules && rules.breakAfterOpen )\r
160                                 this.lineBreak();\r
161                 },\r
162 \r
163                 /**\r
164                  * Writes an attribute. This function should be called after opening the\r
165                  * tag with {@link #openTagClose}.\r
166                  * @param {String} attName The attribute name.\r
167                  * @param {String} attValue The attribute value.\r
168                  * @example\r
169                  * // Writes ' class="MyClass"'.\r
170                  * writer.attribute( 'class', 'MyClass' );\r
171                  */\r
172                 attribute : function( attName, attValue )\r
173                 {\r
174                         if ( this.forceSimpleAmpersand )\r
175                                 attValue = attValue.replace( /&amp;/, '&' );\r
176 \r
177                         this._.output.push( ' ', attName, '="', attValue, '"' );\r
178                 },\r
179 \r
180                 /**\r
181                  * Writes a closer tag.\r
182                  * @param {String} tagName The element name for this tag.\r
183                  * @example\r
184                  * // Writes "&lt;/p&gt;".\r
185                  * writer.closeTag( 'p' );\r
186                  */\r
187                 closeTag : function( tagName )\r
188                 {\r
189                         var rules = this._.rules[ tagName ];\r
190 \r
191                         if ( rules && rules.indent )\r
192                                 this._.indentation = this._.indentation.substr( this.indentationChars.length );\r
193 \r
194                         if ( this._.indent )\r
195                                 this.indentation();\r
196                         // Do not break if indenting.\r
197                         else if ( rules && rules.breakBeforeClose )\r
198                         {\r
199                                 this.lineBreak();\r
200                                 this.indentation();\r
201                         }\r
202 \r
203                         this._.output.push( '</', tagName, '>' );\r
204 \r
205                         if ( rules && rules.breakAfterClose )\r
206                                 this.lineBreak();\r
207                 },\r
208 \r
209                 /**\r
210                  * Writes text.\r
211                  * @param {String} text The text value\r
212                  * @example\r
213                  * // Writes "Hello Word".\r
214                  * writer.text( 'Hello Word' );\r
215                  */\r
216                 text : function( text )\r
217                 {\r
218                         if ( this._.indent )\r
219                         {\r
220                                 this.indentation();\r
221                                 text = CKEDITOR.tools.ltrim( text );\r
222                         }\r
223 \r
224                         this._.output.push( text );\r
225                 },\r
226 \r
227                 /**\r
228                  * Writes a comment.\r
229                  * @param {String} comment The comment text.\r
230                  * @example\r
231                  * // Writes "&lt;!-- My comment --&gt;".\r
232                  * writer.comment( ' My comment ' );\r
233                  */\r
234                 comment : function( comment )\r
235                 {\r
236                         if ( this._.indent )\r
237                                 this.indentation();\r
238 \r
239                         this._.output.push( '<!--', comment, '-->' );\r
240                 },\r
241 \r
242                 /**\r
243                  * Writes a line break. It uses the {@link #lineBreakChars} property for it.\r
244                  * @example\r
245                  * // Writes "\n" (e.g.).\r
246                  * writer.lineBreak();\r
247                  */\r
248                 lineBreak : function()\r
249                 {\r
250                         if ( this._.output.length > 0 )\r
251                                 this._.output.push( this.lineBreakChars );\r
252                         this._.indent = true;\r
253                 },\r
254 \r
255                 /**\r
256                  * Writes the current indentation chars. It uses the\r
257                  * {@link #indentationChars} property, repeating it for the current\r
258                  * indentation steps.\r
259                  * @example\r
260                  * // Writes "\t" (e.g.).\r
261                  * writer.indentation();\r
262                  */\r
263                 indentation : function()\r
264                 {\r
265                         this._.output.push( this._.indentation );\r
266                         this._.indent = false;\r
267                 },\r
268 \r
269                 /**\r
270                  * Sets formatting rules for a give element. The possible rules are:\r
271                  * <ul>\r
272                  *      <li><b>indent</b>: indent the element contents.</li>\r
273                  *      <li><b>breakBeforeOpen</b>: break line before the opener tag for this element.</li>\r
274                  *      <li><b>breakAfterOpen</b>: break line after the opener tag for this element.</li>\r
275                  *      <li><b>breakBeforeClose</b>: break line before the closer tag for this element.</li>\r
276                  *      <li><b>breakAfterClose</b>: break line after the closer tag for this element.</li>\r
277                  * </ul>\r
278                  *\r
279                  * All rules default to "false". Each call to the function overrides\r
280                  * already present rules, leaving the undefined untouched.\r
281                  *\r
282                  * By default, all elements available in the {@link CKEDITOR.dtd.$block),\r
283                  * {@link CKEDITOR.dtd.$listItem} and {@link CKEDITOR.dtd.$tableContent}\r
284                  * lists have all the above rules set to "true". Additionaly, the "br"\r
285                  * element has the "breakAfterOpen" set to "true".\r
286                  * @param {String} tagName The element name to which set the rules.\r
287                  * @param {Object} rules An object containing the element rules.\r
288                  * @example\r
289                  * // Break line before and after "img" tags.\r
290                  * writer.setRules( 'img',\r
291                  *     {\r
292                  *         breakBeforeOpen : true\r
293                  *         breakAfterOpen : true\r
294                  *     });\r
295                  * @example\r
296                  * // Reset the rules for the "h1" tag.\r
297                  * writer.setRules( 'h1', {} );\r
298                  */\r
299                 setRules : function( tagName, rules )\r
300                 {\r
301                         var currentRules = this._.rules[ tagName ];\r
302 \r
303                         if ( currentRules )\r
304                                 CKEDITOR.tools.extend( currentRules, rules, true );\r
305                         else\r
306                                 this._.rules[ tagName ] = rules;\r
307                 }\r
308         }\r
309 });\r