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