plugin.js 9.9 KB

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