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 this.setRules( 'br', 82 { 83 breakAfterOpen : true 84 }); 85 // Disable indentation on <pre>. 86 this.setRules( 'pre', 87 { 88 indent: false 89 } ); 90 }, 91 92 proto : 93 { 94 /** 95 * Writes the tag opening part for a opener tag. 96 * @param {String} tagName The element name for this tag. 97 * @param {Object} attributes The attributes defined for this tag. The 98 * attributes could be used to inspect the tag. 99 * @example 100 * // Writes "<p". 101 * writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } ); 102 */ 103 openTag : function( tagName, attributes ) 104 { 105 var rules = this._.rules[ tagName ]; 106 107 if ( this._.indent ) 108 this.indentation(); 109 // Do not break if indenting. 110 else if ( rules && rules.breakBeforeOpen ) 111 { 112 this.lineBreak(); 113 this.indentation(); 114 } 115 116 this._.output.push( '<', tagName ); 117 }, 118 119 /** 120 * Writes the tag closing part for a opener tag. 121 * @param {String} tagName The element name for this tag. 122 * @param {Boolean} isSelfClose Indicates that this is a self-closing tag, 123 * like "br" or "img". 124 * @example 125 * // Writes ">". 126 * writer.openTagClose( 'p', false ); 127 * @example 128 * // Writes " />". 129 * writer.openTagClose( 'br', true ); 130 */ 131 openTagClose : function( tagName, isSelfClose ) 132 { 133 var rules = this._.rules[ tagName ]; 134 135 if ( isSelfClose ) 136 this._.output.push( this.selfClosingEnd ); 137 else 138 { 139 this._.output.push( '>' ); 140 141 if ( rules && rules.indent ) 142 this._.indentation += this.indentationChars; 143 } 144 145 if ( rules && rules.breakAfterOpen ) 146 this.lineBreak(); 147 }, 148 149 /** 150 * Writes an attribute. This function should be called after opening the 151 * tag with {@link #openTagClose}. 152 * @param {String} attName The attribute name. 153 * @param {String} attValue The attribute value. 154 * @example 155 * // Writes ' class="MyClass"'. 156 * writer.attribute( 'class', 'MyClass' ); 157 */ 158 attribute : function( attName, attValue ) 159 { 160 if ( this.forceSimpleAmpersand ) 161 attValue = attValue.replace( /&/, '&' ); 162 163 this._.output.push( ' ', attName, '="', attValue, '"' ); 164 }, 165 166 /** 167 * Writes a closer tag. 168 * @param {String} tagName The element name for this tag. 169 * @example 170 * // Writes "</p>". 171 * writer.closeTag( 'p' ); 172 */ 173 closeTag : function( tagName ) 174 { 175 var rules = this._.rules[ tagName ]; 176 177 if ( rules && rules.indent ) 178 this._.indentation = this._.indentation.substr( this.indentationChars.length ); 179 180 if ( this._.indent ) 181 this.indentation(); 182 // Do not break if indenting. 183 else if ( rules && rules.breakBeforeClose ) 184 { 185 this.lineBreak(); 186 this.indentation(); 187 } 188 189 this._.output.push( '</', tagName, '>' ); 190 191 if ( rules && rules.breakAfterClose ) 192 this.lineBreak(); 193 }, 194 195 /** 196 * Writes text. 197 * @param {String} text The text value 198 * @example 199 * // Writes "Hello Word". 200 * writer.text( 'Hello Word' ); 201 */ 202 text : function( text ) 203 { 204 if ( this._.indent ) 205 { 206 this.indentation(); 207 text = CKEDITOR.tools.ltrim( text ); 208 } 209 210 this._.output.push( text ); 211 }, 212 213 /** 214 * Writes a comment. 215 * @param {String} comment The comment text. 216 * @example 217 * // Writes "<!-- My comment -->". 218 * writer.comment( ' My comment ' ); 219 */ 220 comment : function( comment ) 221 { 222 if ( this._.indent ) 223 this.indentation(); 224 225 this._.output.push( '<!--', comment, '-->' ); 226 }, 227 228 /** 229 * Writes a line break. It uses the {@link #lineBreakChars} property for it. 230 * @example 231 * // Writes "\n" (e.g.). 232 * writer.lineBreak(); 233 */ 234 lineBreak : function() 235 { 236 if ( this._.output.length > 0 ) 237 this._.output.push( this.lineBreakChars ); 238 this._.indent = true; 239 }, 240 241 /** 242 * Writes the current indentation chars. It uses the 243 * {@link #indentationChars} property, repeating it for the current 244 * indentation steps. 245 * @example 246 * // Writes "\t" (e.g.). 247 * writer.indentation(); 248 */ 249 indentation : function() 250 { 251 this._.output.push( this._.indentation ); 252 this._.indent = false; 253 }, 254 255 /** 256 * Sets formatting rules for a give element. The possible rules are: 257 * <ul> 258 * <li><b>indent</b>: indent the element contents.</li> 259 * <li><b>breakBeforeOpen</b>: break line before the opener tag for this element.</li> 260 * <li><b>breakAfterOpen</b>: break line after the opener tag for this element.</li> 261 * <li><b>breakBeforeClose</b>: break line before the closer tag for this element.</li> 262 * <li><b>breakAfterClose</b>: break line after the closer tag for this element.</li> 263 * </ul> 264 * 265 * All rules default to "false". 266 * 267 * By default, all elements available in the {@link CKEDITOR.dtd.$block), 268 * {@link CKEDITOR.dtd.$listItem} and {@link CKEDITOR.dtd.$tableContent} 269 * lists have all the above rules set to "true". Additionaly, the "br" 270 * element has the "breakAfterOpen" set to "true". 271 * @param {String} tagName The element name to which set the rules. 272 * @param {Object} rules An object containing the element rules. 273 * @example 274 * // Break line before and after "img" tags. 275 * writer.setRules( 'img', 276 * { 277 * breakBeforeOpen : true 278 * breakAfterOpen : true 279 * }); 280 * @example 281 * // Reset the rules for the "h1" tag. 282 * writer.setRules( 'h1', {} ); 283 */ 284 setRules : function( tagName, rules ) 285 { 286 this._.rules[ tagName ] = rules; 287 } 288 } 289 }); 290