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 |
|
10 | import { Command } from 'ckeditor5/src/core';
|
11 |
|
12 | const 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 | */
|
22 | export 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 | }
|