UNPKG

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