headingengine.js 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /**
  2. * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /**
  6. * @module heading/headingengine
  7. */
  8. import Plugin from '../core/plugin.js';
  9. import buildModelConverter from '../engine/conversion/buildmodelconverter.js';
  10. import buildViewConverter from '../engine/conversion/buildviewconverter.js';
  11. import Paragraph from '../paragraph/paragraph.js';
  12. import HeadingCommand from './headingcommand.js';
  13. const formats = [
  14. { id: 'paragraph', viewElement: 'p', label: 'Paragraph' },
  15. { id: 'heading1', viewElement: 'h2', label: 'Heading 1' },
  16. { id: 'heading2', viewElement: 'h3', label: 'Heading 2' },
  17. { id: 'heading3', viewElement: 'h4', label: 'Heading 3' }
  18. ];
  19. /**
  20. * The headings engine feature. It handles switching between block formats – headings and paragraph.
  21. * This class represents the engine part of the heading feature. See also {@link module:heading/heading~Heading}.
  22. *
  23. * @extends modules:core/plugin~Plugin
  24. */
  25. export default class HeadingEngine extends Plugin {
  26. /**
  27. * @inheritDoc
  28. */
  29. static get requires() {
  30. return [ Paragraph ];
  31. }
  32. /**
  33. * @inheritDoc
  34. */
  35. init() {
  36. const editor = this.editor;
  37. const data = editor.data;
  38. const editing = editor.editing;
  39. for ( let format of formats ) {
  40. // Skip paragraph - it is defined in required Paragraph feature.
  41. if ( format.id !== 'paragraph' ) {
  42. // Schema.
  43. editor.document.schema.registerItem( format.id, '$block' );
  44. // Build converter from model to view for data and editing pipelines.
  45. buildModelConverter().for( data.modelToView, editing.modelToView )
  46. .fromElement( format.id )
  47. .toElement( format.viewElement );
  48. // Build converter from view to model for data pipeline.
  49. buildViewConverter().for( data.viewToModel )
  50. .fromElement( format.viewElement )
  51. .toElement( format.id );
  52. }
  53. }
  54. // Register the heading command.
  55. const command = new HeadingCommand( editor, formats );
  56. editor.commands.set( 'heading', command );
  57. }
  58. /**
  59. * @inheritDoc
  60. */
  61. afterInit() {
  62. // If the enter command is added to the editor, alter its behavior.
  63. // Enter at the end of a heading element should create a paragraph.
  64. const editor = this.editor;
  65. const command = editor.commands.get( 'heading' );
  66. const enterCommand = editor.commands.get( 'enter' );
  67. if ( enterCommand ) {
  68. this.listenTo( enterCommand, 'afterExecute', ( evt, data ) => {
  69. const positionParent = editor.document.selection.getFirstPosition().parent;
  70. const batch = data.batch;
  71. const isHeading = formats.some( ( format ) => format.id == positionParent.name );
  72. if ( isHeading && positionParent.name != command.defaultFormat.id && positionParent.childCount === 0 ) {
  73. batch.rename( positionParent, command.defaultFormat.id );
  74. }
  75. } );
  76. }
  77. }
  78. }