]>
Commit | Line | Data |
---|---|---|
1 | /**\r | |
2 | * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.\r | |
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license\r | |
4 | */\r | |
5 | \r | |
6 | CKEDITOR.plugins.add( 'htmlwriter', {\r | |
7 | init: function( editor ) {\r | |
8 | var writer = new CKEDITOR.htmlWriter();\r | |
9 | \r | |
10 | writer.forceSimpleAmpersand = editor.config.forceSimpleAmpersand;\r | |
11 | writer.indentationChars = editor.config.dataIndentationChars || '\t';\r | |
12 | \r | |
13 | // Overwrite default basicWriter initialized in hmtlDataProcessor constructor.\r | |
14 | editor.dataProcessor.writer = writer;\r | |
15 | }\r | |
16 | } );\r | |
17 | \r | |
18 | /**\r | |
19 | * The class used to write HTML data.\r | |
20 | *\r | |
21 | * var writer = new CKEDITOR.htmlWriter();\r | |
22 | * writer.openTag( 'p' );\r | |
23 | * writer.attribute( 'class', 'MyClass' );\r | |
24 | * writer.openTagClose( 'p' );\r | |
25 | * writer.text( 'Hello' );\r | |
26 | * writer.closeTag( 'p' );\r | |
27 | * alert( writer.getHtml() ); // '<p class="MyClass">Hello</p>'\r | |
28 | *\r | |
29 | * @class\r | |
30 | * @extends CKEDITOR.htmlParser.basicWriter\r | |
31 | */\r | |
32 | CKEDITOR.htmlWriter = CKEDITOR.tools.createClass( {\r | |
33 | base: CKEDITOR.htmlParser.basicWriter,\r | |
34 | \r | |
35 | /**\r | |
36 | * Creates an `htmlWriter` class instance.\r | |
37 | *\r | |
38 | * @constructor\r | |
39 | */\r | |
40 | $: function() {\r | |
41 | // Call the base contructor.\r | |
42 | this.base();\r | |
43 | \r | |
44 | /**\r | |
45 | * The characters to be used for each indentation step.\r | |
46 | *\r | |
47 | * // Use tab for indentation.\r | |
48 | * editorInstance.dataProcessor.writer.indentationChars = '\t';\r | |
49 | */\r | |
50 | this.indentationChars = '\t';\r | |
51 | \r | |
52 | /**\r | |
53 | * The characters to be used to close "self-closing" elements, like `<br>` or `<img>`.\r | |
54 | *\r | |
55 | * // Use HTML4 notation for self-closing elements.\r | |
56 | * editorInstance.dataProcessor.writer.selfClosingEnd = '>';\r | |
57 | */\r | |
58 | this.selfClosingEnd = ' />';\r | |
59 | \r | |
60 | /**\r | |
61 | * The characters to be used for line breaks.\r | |
62 | *\r | |
63 | * // Use CRLF for line breaks.\r | |
64 | * editorInstance.dataProcessor.writer.lineBreakChars = '\r\n';\r | |
65 | */\r | |
66 | this.lineBreakChars = '\n';\r | |
67 | \r | |
68 | this.sortAttributes = 1;\r | |
69 | \r | |
70 | this._.indent = 0;\r | |
71 | this._.indentation = '';\r | |
72 | // Indicate preformatted block context status. (#5789)\r | |
73 | this._.inPre = 0;\r | |
74 | this._.rules = {};\r | |
75 | \r | |
76 | var dtd = CKEDITOR.dtd;\r | |
77 | \r | |
78 | for ( var e in CKEDITOR.tools.extend( {}, dtd.$nonBodyContent, dtd.$block, dtd.$listItem, dtd.$tableContent ) ) {\r | |
79 | this.setRules( e, {\r | |
80 | indent: !dtd[ e ][ '#' ],\r | |
81 | breakBeforeOpen: 1,\r | |
82 | breakBeforeClose: !dtd[ e ][ '#' ],\r | |
83 | breakAfterClose: 1,\r | |
84 | needsSpace: ( e in dtd.$block ) && !( e in { li: 1, dt: 1, dd: 1 } )\r | |
85 | } );\r | |
86 | }\r | |
87 | \r | |
88 | this.setRules( 'br', { breakAfterOpen: 1 } );\r | |
89 | \r | |
90 | this.setRules( 'title', {\r | |
91 | indent: 0,\r | |
92 | breakAfterOpen: 0\r | |
93 | } );\r | |
94 | \r | |
95 | this.setRules( 'style', {\r | |
96 | indent: 0,\r | |
97 | breakBeforeClose: 1\r | |
98 | } );\r | |
99 | \r | |
100 | this.setRules( 'pre', {\r | |
101 | breakAfterOpen: 1, // Keep line break after the opening tag\r | |
102 | indent: 0 // Disable indentation on <pre>.\r | |
103 | } );\r | |
104 | },\r | |
105 | \r | |
106 | proto: {\r | |
107 | /**\r | |
108 | * Writes the tag opening part for an opener tag.\r | |
109 | *\r | |
110 | * // Writes '<p'.\r | |
111 | * writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } );\r | |
112 | *\r | |
113 | * @param {String} tagName The element name for this tag.\r | |
114 | * @param {Object} attributes The attributes defined for this tag. The\r | |
115 | * attributes could be used to inspect the tag.\r | |
116 | */\r | |
117 | openTag: function( tagName ) {\r | |
118 | var rules = this._.rules[ tagName ];\r | |
119 | \r | |
120 | if ( this._.afterCloser && rules && rules.needsSpace && this._.needsSpace )\r | |
121 | this._.output.push( '\n' );\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 | this.lineBreak();\r | |
128 | this.indentation();\r | |
129 | }\r | |
130 | \r | |
131 | this._.output.push( '<', tagName );\r | |
132 | \r | |
133 | this._.afterCloser = 0;\r | |
134 | },\r | |
135 | \r | |
136 | /**\r | |
137 | * Writes the tag closing part for an opener tag.\r | |
138 | *\r | |
139 | * // Writes '>'.\r | |
140 | * writer.openTagClose( 'p', false );\r | |
141 | *\r | |
142 | * // Writes ' />'.\r | |
143 | * writer.openTagClose( 'br', true );\r | |
144 | *\r | |
145 | * @param {String} tagName The element name for this tag.\r | |
146 | * @param {Boolean} isSelfClose Indicates that this is a self-closing tag,\r | |
147 | * like `<br>` or `<img>`.\r | |
148 | */\r | |
149 | openTagClose: function( tagName, isSelfClose ) {\r | |
150 | var rules = this._.rules[ tagName ];\r | |
151 | \r | |
152 | if ( isSelfClose ) {\r | |
153 | this._.output.push( this.selfClosingEnd );\r | |
154 | \r | |
155 | if ( rules && rules.breakAfterClose )\r | |
156 | this._.needsSpace = rules.needsSpace;\r | |
157 | } else {\r | |
158 | this._.output.push( '>' );\r | |
159 | \r | |
160 | if ( rules && rules.indent )\r | |
161 | this._.indentation += this.indentationChars;\r | |
162 | }\r | |
163 | \r | |
164 | if ( rules && rules.breakAfterOpen )\r | |
165 | this.lineBreak();\r | |
166 | tagName == 'pre' && ( this._.inPre = 1 );\r | |
167 | },\r | |
168 | \r | |
169 | /**\r | |
170 | * Writes an attribute. This function should be called after opening the\r | |
171 | * tag with {@link #openTagClose}.\r | |
172 | *\r | |
173 | * // Writes ' class="MyClass"'.\r | |
174 | * writer.attribute( 'class', 'MyClass' );\r | |
175 | *\r | |
176 | * @param {String} attName The attribute name.\r | |
177 | * @param {String} attValue The attribute value.\r | |
178 | */\r | |
179 | attribute: function( attName, attValue ) {\r | |
180 | \r | |
181 | if ( typeof attValue == 'string' ) {\r | |
182 | this.forceSimpleAmpersand && ( attValue = attValue.replace( /&/g, '&' ) );\r | |
183 | // Browsers don't always escape special character in attribute values. (#4683, #4719).\r | |
184 | attValue = CKEDITOR.tools.htmlEncodeAttr( attValue );\r | |
185 | }\r | |
186 | \r | |
187 | this._.output.push( ' ', attName, '="', attValue, '"' );\r | |
188 | },\r | |
189 | \r | |
190 | /**\r | |
191 | * Writes a closer tag.\r | |
192 | *\r | |
193 | * // Writes '</p>'.\r | |
194 | * writer.closeTag( 'p' );\r | |
195 | *\r | |
196 | * @param {String} tagName The element name for this tag.\r | |
197 | */\r | |
198 | closeTag: function( tagName ) {\r | |
199 | var rules = this._.rules[ tagName ];\r | |
200 | \r | |
201 | if ( rules && rules.indent )\r | |
202 | this._.indentation = this._.indentation.substr( this.indentationChars.length );\r | |
203 | \r | |
204 | if ( this._.indent )\r | |
205 | this.indentation();\r | |
206 | // Do not break if indenting.\r | |
207 | else if ( rules && rules.breakBeforeClose ) {\r | |
208 | this.lineBreak();\r | |
209 | this.indentation();\r | |
210 | }\r | |
211 | \r | |
212 | this._.output.push( '</', tagName, '>' );\r | |
213 | tagName == 'pre' && ( this._.inPre = 0 );\r | |
214 | \r | |
215 | if ( rules && rules.breakAfterClose ) {\r | |
216 | this.lineBreak();\r | |
217 | this._.needsSpace = rules.needsSpace;\r | |
218 | }\r | |
219 | \r | |
220 | this._.afterCloser = 1;\r | |
221 | },\r | |
222 | \r | |
223 | /**\r | |
224 | * Writes text.\r | |
225 | *\r | |
226 | * // Writes 'Hello Word'.\r | |
227 | * writer.text( 'Hello Word' );\r | |
228 | *\r | |
229 | * @param {String} text The text value\r | |
230 | */\r | |
231 | text: function( text ) {\r | |
232 | if ( this._.indent ) {\r | |
233 | this.indentation();\r | |
234 | !this._.inPre && ( text = CKEDITOR.tools.ltrim( text ) );\r | |
235 | }\r | |
236 | \r | |
237 | this._.output.push( text );\r | |
238 | },\r | |
239 | \r | |
240 | /**\r | |
241 | * Writes a comment.\r | |
242 | *\r | |
243 | * // Writes "<!-- My comment -->".\r | |
244 | * writer.comment( ' My comment ' );\r | |
245 | *\r | |
246 | * @param {String} comment The comment text.\r | |
247 | */\r | |
248 | comment: function( comment ) {\r | |
249 | if ( this._.indent )\r | |
250 | this.indentation();\r | |
251 | \r | |
252 | this._.output.push( '<!--', comment, '-->' );\r | |
253 | },\r | |
254 | \r | |
255 | /**\r | |
256 | * Writes a line break. It uses the {@link #lineBreakChars} property for it.\r | |
257 | *\r | |
258 | * // Writes '\n' (e.g.).\r | |
259 | * writer.lineBreak();\r | |
260 | */\r | |
261 | lineBreak: function() {\r | |
262 | if ( !this._.inPre && this._.output.length > 0 )\r | |
263 | this._.output.push( this.lineBreakChars );\r | |
264 | this._.indent = 1;\r | |
265 | },\r | |
266 | \r | |
267 | /**\r | |
268 | * Writes the current indentation character. It uses the {@link #indentationChars}\r | |
269 | * property, repeating it for the current indentation steps.\r | |
270 | *\r | |
271 | * // Writes '\t' (e.g.).\r | |
272 | * writer.indentation();\r | |
273 | */\r | |
274 | indentation: function() {\r | |
275 | if ( !this._.inPre && this._.indentation )\r | |
276 | this._.output.push( this._.indentation );\r | |
277 | this._.indent = 0;\r | |
278 | },\r | |
279 | \r | |
280 | /**\r | |
281 | * Empties the current output buffer. It also brings back the default\r | |
282 | * values of the writer flags.\r | |
283 | *\r | |
284 | * writer.reset();\r | |
285 | */\r | |
286 | reset: function() {\r | |
287 | this._.output = [];\r | |
288 | this._.indent = 0;\r | |
289 | this._.indentation = '';\r | |
290 | this._.afterCloser = 0;\r | |
291 | this._.inPre = 0;\r | |
292 | },\r | |
293 | \r | |
294 | /**\r | |
295 | * Sets formatting rules for a given element. Possible rules are:\r | |
296 | *\r | |
297 | * * `indent` – indent the element content.\r | |
298 | * * `breakBeforeOpen` – break line before the opener tag for this element.\r | |
299 | * * `breakAfterOpen` – break line after the opener tag for this element.\r | |
300 | * * `breakBeforeClose` – break line before the closer tag for this element.\r | |
301 | * * `breakAfterClose` – break line after the closer tag for this element.\r | |
302 | *\r | |
303 | * All rules default to `false`. Each function call overrides rules that are\r | |
304 | * already present, leaving the undefined ones untouched.\r | |
305 | *\r | |
306 | * By default, all elements available in the {@link CKEDITOR.dtd#$block},\r | |
307 | * {@link CKEDITOR.dtd#$listItem}, and {@link CKEDITOR.dtd#$tableContent}\r | |
308 | * lists have all the above rules set to `true`. Additionaly, the `<br>`\r | |
309 | * element has the `breakAfterOpen` rule set to `true`.\r | |
310 | *\r | |
311 | * // Break line before and after "img" tags.\r | |
312 | * writer.setRules( 'img', {\r | |
313 | * breakBeforeOpen: true\r | |
314 | * breakAfterOpen: true\r | |
315 | * } );\r | |
316 | *\r | |
317 | * // Reset the rules for the "h1" tag.\r | |
318 | * writer.setRules( 'h1', {} );\r | |
319 | *\r | |
320 | * @param {String} tagName The name of the element for which the rules are set.\r | |
321 | * @param {Object} rules An object containing the element rules.\r | |
322 | */\r | |
323 | setRules: function( tagName, rules ) {\r | |
324 | var currentRules = this._.rules[ tagName ];\r | |
325 | \r | |
326 | if ( currentRules )\r | |
327 | CKEDITOR.tools.extend( currentRules, rules, true );\r | |
328 | else\r | |
329 | this._.rules[ tagName ] = rules;\r | |
330 | }\r | |
331 | }\r | |
332 | } );\r | |
333 | \r | |
334 | /**\r | |
335 | * Whether to force using `'&'` instead of `'&'` in element attributes\r | |
336 | * values. It is not recommended to change this setting for compliance with the\r | |
337 | * W3C XHTML 1.0 standards ([C.12, XHTML 1.0](http://www.w3.org/TR/xhtml1/#C_12)).\r | |
338 | *\r | |
339 | * // Use `'&'` instead of `'&'`\r | |
340 | * CKEDITOR.config.forceSimpleAmpersand = true;\r | |
341 | *\r | |
342 | * @cfg {Boolean} [forceSimpleAmpersand=false]\r | |
343 | * @member CKEDITOR.config\r | |
344 | */\r | |
345 | \r | |
346 | /**\r | |
347 | * The characters to be used for indenting HTML output produced by the editor.\r | |
348 | * Using characters different from `' '` (space) and `'\t'` (tab) is not recommended\r | |
349 | * as it will mess the code.\r | |
350 | *\r | |
351 | * // No indentation.\r | |
352 | * CKEDITOR.config.dataIndentationChars = '';\r | |
353 | *\r | |
354 | * // Use two spaces for indentation.\r | |
355 | * CKEDITOR.config.dataIndentationChars = ' ';\r | |
356 | *\r | |
357 | * @cfg {String} [dataIndentationChars='\t']\r | |
358 | * @member CKEDITOR.config\r | |
359 | */\r |