todolistcheckcommand.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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 list/todolistcheckedcommand
  7. */
  8. import Command from '@ckeditor/ckeditor5-core/src/command';
  9. const attributeKey = 'todoListChecked';
  10. /**
  11. * The to-do check command.
  12. *
  13. * The command is registered by the {@link module:list/todolistediting~TodoListEditing} as
  14. * the `'todoListCheck'` editor command.
  15. *
  16. * @extends module:core/command~Command
  17. */
  18. export default class TodoListCheckCommand extends Command {
  19. /**
  20. * @inheritDoc
  21. */
  22. constructor( editor ) {
  23. super( editor );
  24. /**
  25. * A flag indicating whether the command is active. The command is active when at least one of
  26. * {@link module:engine/model/selection~Selection selected} elements is a to-do list item.
  27. *
  28. * @observable
  29. * @readonly
  30. * @member {Boolean} #isEnabled
  31. */
  32. /**
  33. * A list of to-do list items selected by the {@link module:engine/model/selection~Selection}.
  34. *
  35. * @observable
  36. * @readonly
  37. * @member {Array.<module:engine/model/element~Element>} #value
  38. */
  39. /**
  40. * A list of to-do list items selected by the {@link module:engine/model/selection~Selection}.
  41. *
  42. * @protected
  43. * @type {Array.<module:engine/model/element~Element>}
  44. */
  45. this._selectedElements = [];
  46. // Refresh command before executing to be sure all values are up to date.
  47. // It is needed when selection has changed before command execution, in the same change block.
  48. this.on( 'execute', () => {
  49. this.refresh();
  50. }, { priority: 'highest' } );
  51. }
  52. /**
  53. * Updates the command's {@link #value} and {@link #isEnabled} properties based on the current selection.
  54. */
  55. refresh() {
  56. this._selectedElements = this._getSelectedItems();
  57. this.value = this._selectedElements.every( element => !!element.getAttribute( 'todoListChecked' ) );
  58. this.isEnabled = !!this._selectedElements.length;
  59. }
  60. /**
  61. * Gets all to-do list items selected by the {@link module:engine/model/selection~Selection}.
  62. *
  63. * @private
  64. * @returns {Array.<module:engine/model/element~Element>}
  65. */
  66. _getSelectedItems() {
  67. const model = this.editor.model;
  68. const schema = model.schema;
  69. const selectionRange = model.document.selection.getFirstRange();
  70. const startElement = selectionRange.start.parent;
  71. const elements = [];
  72. if ( schema.checkAttribute( startElement, attributeKey ) ) {
  73. elements.push( startElement );
  74. }
  75. for ( const item of selectionRange.getItems() ) {
  76. if ( schema.checkAttribute( item, attributeKey ) && !elements.includes( item ) ) {
  77. elements.push( item );
  78. }
  79. }
  80. return elements;
  81. }
  82. /**
  83. * Executes the command.
  84. *
  85. * @param {Object} [options]
  86. * @param {Boolean} [options.forceValue] If set, it will force the command behavior. If `true`, the command will apply
  87. * the attribute. Otherwise, the command will remove the attribute. If not set, the command will look for its current
  88. * value to decide what it should do.
  89. */
  90. execute( options = {} ) {
  91. this.editor.model.change( writer => {
  92. for ( const element of this._selectedElements ) {
  93. const value = ( options.forceValue === undefined ) ? !this.value : options.forceValue;
  94. if ( value ) {
  95. writer.setAttribute( attributeKey, true, element );
  96. } else {
  97. writer.removeAttribute( attributeKey, element );
  98. }
  99. }
  100. } );
  101. }
  102. }