headingcommand.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /**
  2. * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /**
  6. * @module heading/headingcommand
  7. */
  8. import Command from '@ckeditor/ckeditor5-core/src/command';
  9. import first from '@ckeditor/ckeditor5-utils/src/first';
  10. /**
  11. * The heading command. It is used by the {@link module:heading/heading~Heading heading feature} to apply headings.
  12. *
  13. * @extends module:core/command~Command
  14. */
  15. export default class HeadingCommand extends Command {
  16. /**
  17. * Creates an instance of the command.
  18. *
  19. * @param {module:core/editor/editor~Editor} editor Editor instance.
  20. * @param {String} modelElement Name of the element which this command will apply in the model.
  21. */
  22. constructor( editor, modelElement ) {
  23. super( editor );
  24. /**
  25. * Whether the selection starts in a heading of {@link #modelElement this level}.
  26. *
  27. * @observable
  28. * @readonly
  29. * @member {Boolean} #value
  30. */
  31. /**
  32. * Unique identifier of the command, also element's name in the model.
  33. * See {@link module:heading/heading~HeadingOption}.
  34. *
  35. * @readonly
  36. * @member {String}
  37. */
  38. this.modelElement = modelElement;
  39. }
  40. /**
  41. * @inheritDoc
  42. */
  43. refresh() {
  44. const block = first( this.editor.model.document.selection.getSelectedBlocks() );
  45. this.value = !!block && block.is( this.modelElement );
  46. this.isEnabled = !!block && checkCanBecomeHeading( block, this.modelElement, this.editor.model.schema );
  47. }
  48. /**
  49. * Executes the command. Applies the heading to the selected blocks or, if the first selected
  50. * block is a heading already, turns selected headings (of this level only) to paragraphs.
  51. *
  52. * @fires execute
  53. */
  54. execute() {
  55. const model = this.editor.model;
  56. const document = model.document;
  57. model.change( writer => {
  58. const blocks = Array.from( document.selection.getSelectedBlocks() )
  59. .filter( block => {
  60. return checkCanBecomeHeading( block, this.modelElement, model.schema );
  61. } );
  62. for ( const block of blocks ) {
  63. if ( !block.is( this.modelElement ) ) {
  64. writer.rename( block, this.modelElement );
  65. }
  66. }
  67. } );
  68. }
  69. }
  70. // Checks whether the given block can be replaced by a specific heading.
  71. //
  72. // @private
  73. // @param {module:engine/model/element~Element} block A block to be tested.
  74. // @param {module:heading/headingcommand~HeadingCommand#modelElement} heading Command element name in the model.
  75. // @param {module:engine/model/schema~Schema} schema The schema of the document.
  76. // @returns {Boolean}
  77. function checkCanBecomeHeading( block, heading, schema ) {
  78. return schema.checkChild( block.parent, heading ) && !schema.isObject( block );
  79. }