JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.4.2
[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 = 0;\r
61 \r
62                 this.sortAttributes = 1;\r
63 \r
64                 this._.indent = 0;\r
65                 this._.indentation = '';\r
66                 // Indicate preformatted block context status. (#5789)\r
67                 this._.inPre = 0;\r
68                 this._.rules = {};\r
69 \r
70                 var dtd = CKEDITOR.dtd;\r
71 \r
72                 for ( var e in CKEDITOR.tools.extend( {}, dtd.$nonBodyContent, dtd.$block, dtd.$listItem, dtd.$tableContent ) )\r
73                 {\r
74                         this.setRules( e,\r
75                                 {\r
76                                         indent : 1,\r
77                                         breakBeforeOpen : 1,\r
78                                         breakAfterOpen : 1,\r
79                                         breakBeforeClose : !dtd[ e ][ '#' ],\r
80                                         breakAfterClose : 1\r
81                                 });\r
82                 }\r
83 \r
84                 this.setRules( 'br',\r
85                         {\r
86                                 breakAfterOpen : 1\r
87                         });\r
88 \r
89                 this.setRules( 'title',\r
90                         {\r
91                                 indent : 0,\r
92                                 breakAfterOpen : 0\r
93                         });\r
94 \r
95                 this.setRules( 'style',\r
96                         {\r
97                                 indent : 0,\r
98                                 breakBeforeClose : 1\r
99                         });\r
100 \r
101                 // Disable indentation on <pre>.\r
102                 this.setRules( 'pre',\r
103                         {\r
104                           indent : 0\r
105                         });\r
106         },\r
107 \r
108         proto :\r
109         {\r
110                 /**\r
111                  * Writes the tag opening part for a opener tag.\r
112                  * @param {String} tagName The element name for this tag.\r
113                  * @param {Object} attributes The attributes defined for this tag. The\r
114                  *              attributes could be used to inspect the tag.\r
115                  * @example\r
116                  * // Writes "&lt;p".\r
117                  * writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } );\r
118                  */\r
119                 openTag : function( tagName, attributes )\r
120                 {\r
121                         var rules = this._.rules[ tagName ];\r
122 \r
123                         if ( this._.indent )\r
124                                 this.indentation();\r
125                         // Do not break if indenting.\r
126                         else if ( rules && rules.breakBeforeOpen )\r
127                         {\r
128                                 this.lineBreak();\r
129                                 this.indentation();\r
130                         }\r
131 \r
132                         this._.output.push( '<', tagName );\r
133                 },\r
134 \r
135                 /**\r
136                  * Writes the tag closing part for a opener tag.\r
137                  * @param {String} tagName The element name for this tag.\r
138                  * @param {Boolean} isSelfClose Indicates that this is a self-closing tag,\r
139                  *              like "br" or "img".\r
140                  * @example\r
141                  * // Writes "&gt;".\r
142                  * writer.openTagClose( 'p', false );\r
143                  * @example\r
144                  * // Writes " /&gt;".\r
145                  * writer.openTagClose( 'br', true );\r
146                  */\r
147                 openTagClose : function( tagName, isSelfClose )\r
148                 {\r
149                         var rules = this._.rules[ tagName ];\r
150 \r
151                         if ( isSelfClose )\r
152                                 this._.output.push( this.selfClosingEnd );\r
153                         else\r
154                         {\r
155                                 this._.output.push( '>' );\r
156 \r
157                                 if ( rules && rules.indent )\r
158                                         this._.indentation += this.indentationChars;\r
159                         }\r
160 \r
161                         if ( rules && rules.breakAfterOpen )\r
162                                 this.lineBreak();\r
163                         tagName == 'pre' && ( this._.inPre = 1 );\r
164                 },\r
165 \r
166                 /**\r
167                  * Writes an attribute. This function should be called after opening the\r
168                  * tag with {@link #openTagClose}.\r
169                  * @param {String} attName The attribute name.\r
170                  * @param {String} attValue The attribute value.\r
171                  * @example\r
172                  * // Writes ' class="MyClass"'.\r
173                  * writer.attribute( 'class', 'MyClass' );\r
174                  */\r
175                 attribute : function( attName, attValue )\r
176                 {\r
177 \r
178                         if ( typeof attValue == 'string' )\r
179                         {\r
180                                 this.forceSimpleAmpersand && ( attValue = attValue.replace( /&amp;/g, '&' ) );\r
181                                 // Browsers don't always escape special character in attribute values. (#4683, #4719).\r
182                                 attValue = CKEDITOR.tools.htmlEncodeAttr( attValue );\r
183                         }\r
184 \r
185                         this._.output.push( ' ', attName, '="', attValue, '"' );\r
186                 },\r
187 \r
188                 /**\r
189                  * Writes a closer tag.\r
190                  * @param {String} tagName The element name for this tag.\r
191                  * @example\r
192                  * // Writes "&lt;/p&gt;".\r
193                  * writer.closeTag( 'p' );\r
194                  */\r
195                 closeTag : function( tagName )\r
196                 {\r
197                         var rules = this._.rules[ tagName ];\r
198 \r
199                         if ( rules && rules.indent )\r
200                                 this._.indentation = this._.indentation.substr( this.indentationChars.length );\r
201 \r
202                         if ( this._.indent )\r
203                                 this.indentation();\r
204                         // Do not break if indenting.\r
205                         else if ( rules && rules.breakBeforeClose )\r
206                         {\r
207                                 this.lineBreak();\r
208                                 this.indentation();\r
209                         }\r
210 \r
211                         this._.output.push( '</', tagName, '>' );\r
212                         tagName == 'pre' && ( this._.inPre = 0 );\r
213 \r
214                         if ( rules && rules.breakAfterClose )\r
215                                 this.lineBreak();\r
216                 },\r
217 \r
218                 /**\r
219                  * Writes text.\r
220                  * @param {String} text The text value\r
221                  * @example\r
222                  * // Writes "Hello Word".\r
223                  * writer.text( 'Hello Word' );\r
224                  */\r
225                 text : function( text )\r
226                 {\r
227                         if ( this._.indent )\r
228                         {\r
229                                 this.indentation();\r
230                                 !this._.inPre  && ( text = CKEDITOR.tools.ltrim( text ) );\r
231                         }\r
232 \r
233                         this._.output.push( text );\r
234                 },\r
235 \r
236                 /**\r
237                  * Writes a comment.\r
238                  * @param {String} comment The comment text.\r
239                  * @example\r
240                  * // Writes "&lt;!-- My comment --&gt;".\r
241                  * writer.comment( ' My comment ' );\r
242                  */\r
243                 comment : function( comment )\r
244                 {\r
245                         if ( this._.indent )\r
246                                 this.indentation();\r
247 \r
248                         this._.output.push( '<!--', comment, '-->' );\r
249                 },\r
250 \r
251                 /**\r
252                  * Writes a line break. It uses the {@link #lineBreakChars} property for it.\r
253                  * @example\r
254                  * // Writes "\n" (e.g.).\r
255                  * writer.lineBreak();\r
256                  */\r
257                 lineBreak : function()\r
258                 {\r
259                         if ( !this._.inPre && this._.output.length > 0 )\r
260                                 this._.output.push( this.lineBreakChars );\r
261                         this._.indent = 1;\r
262                 },\r
263 \r
264                 /**\r
265                  * Writes the current indentation chars. It uses the\r
266                  * {@link #indentationChars} property, repeating it for the current\r
267                  * indentation steps.\r
268                  * @example\r
269                  * // Writes "\t" (e.g.).\r
270                  * writer.indentation();\r
271                  */\r
272                 indentation : function()\r
273                 {\r
274                         if( !this._.inPre )\r
275                                 this._.output.push( this._.indentation );\r
276                         this._.indent = 0;\r
277                 },\r
278 \r
279                 /**\r
280                  * Sets formatting rules for a give element. The possible rules are:\r
281                  * <ul>\r
282                  *      <li><b>indent</b>: indent the element contents.</li>\r
283                  *      <li><b>breakBeforeOpen</b>: break line before the opener tag for this element.</li>\r
284                  *      <li><b>breakAfterOpen</b>: break line after the opener tag for this element.</li>\r
285                  *      <li><b>breakBeforeClose</b>: break line before the closer tag for this element.</li>\r
286                  *      <li><b>breakAfterClose</b>: break line after the closer tag for this element.</li>\r
287                  * </ul>\r
288                  *\r
289                  * All rules default to "false". Each call to the function overrides\r
290                  * already present rules, leaving the undefined untouched.\r
291                  *\r
292                  * By default, all elements available in the {@link CKEDITOR.dtd.$block),\r
293                  * {@link CKEDITOR.dtd.$listItem} and {@link CKEDITOR.dtd.$tableContent}\r
294                  * lists have all the above rules set to "true". Additionaly, the "br"\r
295                  * element has the "breakAfterOpen" set to "true".\r
296                  * @param {String} tagName The element name to which set the rules.\r
297                  * @param {Object} rules An object containing the element rules.\r
298                  * @example\r
299                  * // Break line before and after "img" tags.\r
300                  * writer.setRules( 'img',\r
301                  *     {\r
302                  *         breakBeforeOpen : true\r
303                  *         breakAfterOpen : true\r
304                  *     });\r
305                  * @example\r
306                  * // Reset the rules for the "h1" tag.\r
307                  * writer.setRules( 'h1', {} );\r
308                  */\r
309                 setRules : function( tagName, rules )\r
310                 {\r
311                         var currentRules = this._.rules[ tagName ];\r
312 \r
313                         if ( currentRules )\r
314                                 CKEDITOR.tools.extend( currentRules, rules, true );\r
315                         else\r
316                                 this._.rules[ tagName ] = rules;\r
317                 }\r
318         }\r
319 });\r