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