8
0

headingediting.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /**
  6. * @module heading/headingediting
  7. */
  8. import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
  9. import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
  10. import HeadingCommand from './headingcommand';
  11. import priorities from '@ckeditor/ckeditor5-utils/src/priorities';
  12. const defaultModelElement = 'paragraph';
  13. /**
  14. * The headings engine feature. It handles switching between block formats – headings and paragraph.
  15. * This class represents the engine part of the heading feature. See also {@link module:heading/heading~Heading}.
  16. * It introduces `heading1`-`headingN` commands which allow to convert paragraphs into headings.
  17. *
  18. * @extends module:core/plugin~Plugin
  19. */
  20. export default class HeadingEditing extends Plugin {
  21. /**
  22. * @inheritDoc
  23. */
  24. static get pluginName() {
  25. return 'HeadingEditing';
  26. }
  27. /**
  28. * @inheritDoc
  29. */
  30. constructor( editor ) {
  31. super( editor );
  32. editor.config.define( 'heading', {
  33. options: [
  34. { model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },
  35. { model: 'heading1', view: 'h2', title: 'Heading 1', class: 'ck-heading_heading1' },
  36. { model: 'heading2', view: 'h3', title: 'Heading 2', class: 'ck-heading_heading2' },
  37. { model: 'heading3', view: 'h4', title: 'Heading 3', class: 'ck-heading_heading3' }
  38. ]
  39. } );
  40. }
  41. /**
  42. * @inheritDoc
  43. */
  44. static get requires() {
  45. return [ Paragraph ];
  46. }
  47. /**
  48. * @inheritDoc
  49. */
  50. init() {
  51. const editor = this.editor;
  52. const options = editor.config.get( 'heading.options' );
  53. const modelElements = [];
  54. for ( const option of options ) {
  55. // Skip paragraph - it is defined in required Paragraph feature.
  56. if ( option.model !== defaultModelElement ) {
  57. // Schema.
  58. editor.model.schema.register( option.model, {
  59. inheritAllFrom: '$block'
  60. } );
  61. editor.conversion.elementToElement( option );
  62. modelElements.push( option.model );
  63. }
  64. }
  65. this._addDefaultH1Conversion( editor );
  66. // Register the heading command for this option.
  67. editor.commands.add( 'heading', new HeadingCommand( editor, modelElements ) );
  68. }
  69. /**
  70. * @inheritDoc
  71. */
  72. afterInit() {
  73. // If the enter command is added to the editor, alter its behavior.
  74. // Enter at the end of a heading element should create a paragraph.
  75. const editor = this.editor;
  76. const enterCommand = editor.commands.get( 'enter' );
  77. const options = editor.config.get( 'heading.options' );
  78. if ( enterCommand ) {
  79. this.listenTo( enterCommand, 'afterExecute', ( evt, data ) => {
  80. const positionParent = editor.model.document.selection.getFirstPosition().parent;
  81. const isHeading = options.some( option => positionParent.is( option.model ) );
  82. if ( isHeading && !positionParent.is( defaultModelElement ) && positionParent.childCount === 0 ) {
  83. data.writer.rename( positionParent, defaultModelElement );
  84. }
  85. } );
  86. }
  87. }
  88. /**
  89. * Adds default conversion for `h1` -> `heading1` with a low priority.
  90. *
  91. * @private
  92. * @param {module:core/editor/editor~Editor} editor Editor instance on which to add the `h1` conversion.
  93. */
  94. _addDefaultH1Conversion( editor ) {
  95. editor.conversion.for( 'upcast' ).elementToElement( {
  96. model: 'heading1',
  97. view: 'h1',
  98. // With a `low` priority, `paragraph` plugin autoparagraphing mechanism is executed. Make sure
  99. // this listener is called before it. If not, `h1` will be transformed into a paragraph.
  100. converterPriority: priorities.get( 'low' ) + 1
  101. } );
  102. }
  103. }