removeformatcommand.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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 remove-format/removeformatcommand
  7. */
  8. import Command from '@ckeditor/ckeditor5-core/src/command';
  9. import first from '@ckeditor/ckeditor5-utils/src/first';
  10. /**
  11. * The remove format command.
  12. *
  13. * It is used by the {@link module:remove-format/removeformat~RemoveFormat remove format feature}
  14. * to clear the formatting in the selection.
  15. *
  16. * editor.execute( 'removeFormat' );
  17. *
  18. * @extends module:core/command~Command
  19. */
  20. export default class RemoveFormatCommand extends Command {
  21. /**
  22. * @inheritDoc
  23. */
  24. refresh() {
  25. const model = this.editor.model;
  26. this.isEnabled = !!first( this._getFormattingItems( model.document.selection, model.schema ) );
  27. }
  28. /**
  29. * @inheritDoc
  30. */
  31. execute() {
  32. const model = this.editor.model;
  33. const schema = model.schema;
  34. model.change( writer => {
  35. for ( const item of this._getFormattingItems( model.document.selection, schema ) ) {
  36. if ( item.is( 'selection' ) ) {
  37. for ( const attributeName of this._getFormattingAttributes( item, schema ) ) {
  38. writer.removeSelectionAttribute( attributeName );
  39. }
  40. } else {
  41. // Workaround for items with multiple removable attributes. See
  42. // https://github.com/ckeditor/ckeditor5-remove-format/pull/1#pullrequestreview-220515609
  43. const itemRange = writer.createRangeOn( item );
  44. for ( const attributeName of this._getFormattingAttributes( item, schema ) ) {
  45. writer.removeAttribute( attributeName, itemRange );
  46. }
  47. }
  48. }
  49. } );
  50. }
  51. /**
  52. * Returns an iterable of items in a selection (including the selection itself) that have formatting model
  53. * attributes to be removed by the feature.
  54. *
  55. * @protected
  56. * @param {module:engine/model/documentselection~DocumentSelection} selection
  57. * @param {module:engine/model/schema~Schema} schema The schema describing the item.
  58. * @returns {Iterable.<module:engine/model/item~Item>|Iterable.<module:engine/model/documentselection~DocumentSelection>}
  59. */
  60. * _getFormattingItems( selection, schema ) {
  61. const itemHasRemovableFormatting = item => {
  62. return !!first( this._getFormattingAttributes( item, schema ) );
  63. };
  64. // Check formatting on selected items that are not blocks.
  65. for ( const curRange of selection.getRanges() ) {
  66. for ( const item of curRange.getItems() ) {
  67. if ( !schema.isBlock( item ) && itemHasRemovableFormatting( item ) ) {
  68. yield item;
  69. }
  70. }
  71. }
  72. // Check formatting from selected blocks.
  73. for ( const block of selection.getSelectedBlocks() ) {
  74. if ( itemHasRemovableFormatting( block ) ) {
  75. yield block;
  76. }
  77. }
  78. // Finally the selection might be formatted as well, so make sure to check it.
  79. if ( itemHasRemovableFormatting( selection ) ) {
  80. yield selection;
  81. }
  82. }
  83. /**
  84. * Returns an iterable of formatting attributes of a given model item.
  85. *
  86. * **Note:** Formatting items have the `isFormatting` property set to `true`.
  87. *
  88. * @protected
  89. * @param {module:engine/model/item~Item|module:engine/model/documentselection~DocumentSelection} item
  90. * @param {module:engine/model/schema~Schema} schema The schema describing the item.
  91. * @returns {Iterable.<String>} The names of formatting attributes found in a given item.
  92. */
  93. * _getFormattingAttributes( item, schema ) {
  94. for ( const [ attributeName ] of item.getAttributes() ) {
  95. const attributeProperties = schema.getAttributeProperties( attributeName );
  96. if ( attributeProperties && attributeProperties.isFormatting ) {
  97. yield attributeName;
  98. }
  99. }
  100. }
  101. }