@ckeditor/ckeditor5-block-quote 38.0.1 → 38.1.1
Sign up to get free protection for your applications and to get access to all the features.
- package/build/block-quote.js +1 -1
- package/build/block-quote.js.map +1 -0
- package/package.json +2 -25
- package/src/augmentation.d.ts +15 -15
- package/src/augmentation.js +5 -5
- package/src/blockquote.d.ts +30 -30
- package/src/blockquote.js +34 -34
- package/src/blockquotecommand.d.ts +61 -61
- package/src/blockquotecommand.js +172 -172
- package/src/blockquoteediting.d.ts +31 -31
- package/src/blockquoteediting.js +118 -118
- package/src/blockquoteui.d.ts +26 -26
- package/src/blockquoteui.js +50 -50
- package/src/index.d.ts +12 -12
- package/src/index.js +11 -11
package/src/blockquotecommand.js
CHANGED
@@ -1,172 +1,172 @@
|
|
1
|
-
/**
|
2
|
-
* @license Copyright (c) 2003-2023, 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
|
-
* @module block-quote/blockquotecommand
|
7
|
-
*/
|
8
|
-
import { Command } from 'ckeditor5/src/core';
|
9
|
-
import { first } from 'ckeditor5/src/utils';
|
10
|
-
/**
|
11
|
-
* The block quote command plugin.
|
12
|
-
*
|
13
|
-
* @extends module:core/command~Command
|
14
|
-
*/
|
15
|
-
export default class BlockQuoteCommand extends Command {
|
16
|
-
/**
|
17
|
-
* @inheritDoc
|
18
|
-
*/
|
19
|
-
refresh() {
|
20
|
-
this.value = this._getValue();
|
21
|
-
this.isEnabled = this._checkEnabled();
|
22
|
-
}
|
23
|
-
/**
|
24
|
-
* Executes the command. When the command {@link #value is on}, all top-most block quotes within
|
25
|
-
* the selection will be removed. If it is off, all selected blocks will be wrapped with
|
26
|
-
* a block quote.
|
27
|
-
*
|
28
|
-
* @fires execute
|
29
|
-
* @param options Command options.
|
30
|
-
* @param options.forceValue If set, it will force the command behavior. If `true`, the command will apply a block quote,
|
31
|
-
* otherwise the command will remove the block quote. If not set, the command will act basing on its current value.
|
32
|
-
*/
|
33
|
-
execute(options = {}) {
|
34
|
-
const model = this.editor.model;
|
35
|
-
const schema = model.schema;
|
36
|
-
const selection = model.document.selection;
|
37
|
-
const blocks = Array.from(selection.getSelectedBlocks());
|
38
|
-
const value = (options.forceValue === undefined) ? !this.value : options.forceValue;
|
39
|
-
model.change(writer => {
|
40
|
-
if (!value) {
|
41
|
-
this._removeQuote(writer, blocks.filter(findQuote));
|
42
|
-
}
|
43
|
-
else {
|
44
|
-
const blocksToQuote = blocks.filter(block => {
|
45
|
-
// Already quoted blocks needs to be considered while quoting too
|
46
|
-
// in order to reuse their <bQ> elements.
|
47
|
-
return findQuote(block) || checkCanBeQuoted(schema, block);
|
48
|
-
});
|
49
|
-
this._applyQuote(writer, blocksToQuote);
|
50
|
-
}
|
51
|
-
});
|
52
|
-
}
|
53
|
-
/**
|
54
|
-
* Checks the command's {@link #value}.
|
55
|
-
*/
|
56
|
-
_getValue() {
|
57
|
-
const selection = this.editor.model.document.selection;
|
58
|
-
const firstBlock = first(selection.getSelectedBlocks());
|
59
|
-
// In the current implementation, the block quote must be an immediate parent of a block element.
|
60
|
-
return !!(firstBlock && findQuote(firstBlock));
|
61
|
-
}
|
62
|
-
/**
|
63
|
-
* Checks whether the command can be enabled in the current context.
|
64
|
-
*
|
65
|
-
* @returns Whether the command should be enabled.
|
66
|
-
*/
|
67
|
-
_checkEnabled() {
|
68
|
-
if (this.value) {
|
69
|
-
return true;
|
70
|
-
}
|
71
|
-
const selection = this.editor.model.document.selection;
|
72
|
-
const schema = this.editor.model.schema;
|
73
|
-
const firstBlock = first(selection.getSelectedBlocks());
|
74
|
-
if (!firstBlock) {
|
75
|
-
return false;
|
76
|
-
}
|
77
|
-
return checkCanBeQuoted(schema, firstBlock);
|
78
|
-
}
|
79
|
-
/**
|
80
|
-
* Removes the quote from given blocks.
|
81
|
-
*
|
82
|
-
* If blocks which are supposed to be "unquoted" are in the middle of a quote,
|
83
|
-
* start it or end it, then the quote will be split (if needed) and the blocks
|
84
|
-
* will be moved out of it, so other quoted blocks remained quoted.
|
85
|
-
*/
|
86
|
-
_removeQuote(writer, blocks) {
|
87
|
-
// Unquote all groups of block. Iterate in the reverse order to not break following ranges.
|
88
|
-
getRangesOfBlockGroups(writer, blocks).reverse().forEach(groupRange => {
|
89
|
-
if (groupRange.start.isAtStart && groupRange.end.isAtEnd) {
|
90
|
-
writer.unwrap(groupRange.start.parent);
|
91
|
-
return;
|
92
|
-
}
|
93
|
-
// The group of blocks are at the beginning of an <bQ> so let's move them left (out of the <bQ>).
|
94
|
-
if (groupRange.start.isAtStart) {
|
95
|
-
const positionBefore = writer.createPositionBefore(groupRange.start.parent);
|
96
|
-
writer.move(groupRange, positionBefore);
|
97
|
-
return;
|
98
|
-
}
|
99
|
-
// The blocks are in the middle of an <bQ> so we need to split the <bQ> after the last block
|
100
|
-
// so we move the items there.
|
101
|
-
if (!groupRange.end.isAtEnd) {
|
102
|
-
writer.split(groupRange.end);
|
103
|
-
}
|
104
|
-
// Now we are sure that groupRange.end.isAtEnd is true, so let's move the blocks right.
|
105
|
-
const positionAfter = writer.createPositionAfter(groupRange.end.parent);
|
106
|
-
writer.move(groupRange, positionAfter);
|
107
|
-
});
|
108
|
-
}
|
109
|
-
/**
|
110
|
-
* Applies the quote to given blocks.
|
111
|
-
*/
|
112
|
-
_applyQuote(writer, blocks) {
|
113
|
-
const quotesToMerge = [];
|
114
|
-
// Quote all groups of block. Iterate in the reverse order to not break following ranges.
|
115
|
-
getRangesOfBlockGroups(writer, blocks).reverse().forEach(groupRange => {
|
116
|
-
let quote = findQuote(groupRange.start);
|
117
|
-
if (!quote) {
|
118
|
-
quote = writer.createElement('blockQuote');
|
119
|
-
writer.wrap(groupRange, quote);
|
120
|
-
}
|
121
|
-
quotesToMerge.push(quote);
|
122
|
-
});
|
123
|
-
// Merge subsequent <bQ> elements. Reverse the order again because this time we want to go through
|
124
|
-
// the <bQ> elements in the source order (due to how merge works – it moves the right element's content
|
125
|
-
// to the first element and removes the right one. Since we may need to merge a couple of subsequent `<bQ>` elements
|
126
|
-
// we want to keep the reference to the first (furthest left) one.
|
127
|
-
quotesToMerge.reverse().reduce((currentQuote, nextQuote) => {
|
128
|
-
if (currentQuote.nextSibling == nextQuote) {
|
129
|
-
writer.merge(writer.createPositionAfter(currentQuote));
|
130
|
-
return currentQuote;
|
131
|
-
}
|
132
|
-
return nextQuote;
|
133
|
-
});
|
134
|
-
}
|
135
|
-
}
|
136
|
-
function findQuote(elementOrPosition) {
|
137
|
-
return elementOrPosition.parent.name == 'blockQuote' ? elementOrPosition.parent : null;
|
138
|
-
}
|
139
|
-
/**
|
140
|
-
* Returns a minimal array of ranges containing groups of subsequent blocks.
|
141
|
-
*
|
142
|
-
* content: abcdefgh
|
143
|
-
* blocks: [ a, b, d, f, g, h ]
|
144
|
-
* output ranges: [ab]c[d]e[fgh]
|
145
|
-
*/
|
146
|
-
function getRangesOfBlockGroups(writer, blocks) {
|
147
|
-
let startPosition;
|
148
|
-
let i = 0;
|
149
|
-
const ranges = [];
|
150
|
-
while (i < blocks.length) {
|
151
|
-
const block = blocks[i];
|
152
|
-
const nextBlock = blocks[i + 1];
|
153
|
-
if (!startPosition) {
|
154
|
-
startPosition = writer.createPositionBefore(block);
|
155
|
-
}
|
156
|
-
if (!nextBlock || block.nextSibling != nextBlock) {
|
157
|
-
ranges.push(writer.createRange(startPosition, writer.createPositionAfter(block)));
|
158
|
-
startPosition = null;
|
159
|
-
}
|
160
|
-
i++;
|
161
|
-
}
|
162
|
-
return ranges;
|
163
|
-
}
|
164
|
-
/**
|
165
|
-
* Checks whether <bQ> can wrap the block.
|
166
|
-
*/
|
167
|
-
function checkCanBeQuoted(schema, block) {
|
168
|
-
// TMP will be replaced with schema.checkWrap().
|
169
|
-
const isBQAllowed = schema.checkChild(block.parent, 'blockQuote');
|
170
|
-
const isBlockAllowedInBQ = schema.checkChild(['$root', 'blockQuote'], block);
|
171
|
-
return isBQAllowed && isBlockAllowedInBQ;
|
172
|
-
}
|
1
|
+
/**
|
2
|
+
* @license Copyright (c) 2003-2023, 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
|
+
* @module block-quote/blockquotecommand
|
7
|
+
*/
|
8
|
+
import { Command } from 'ckeditor5/src/core';
|
9
|
+
import { first } from 'ckeditor5/src/utils';
|
10
|
+
/**
|
11
|
+
* The block quote command plugin.
|
12
|
+
*
|
13
|
+
* @extends module:core/command~Command
|
14
|
+
*/
|
15
|
+
export default class BlockQuoteCommand extends Command {
|
16
|
+
/**
|
17
|
+
* @inheritDoc
|
18
|
+
*/
|
19
|
+
refresh() {
|
20
|
+
this.value = this._getValue();
|
21
|
+
this.isEnabled = this._checkEnabled();
|
22
|
+
}
|
23
|
+
/**
|
24
|
+
* Executes the command. When the command {@link #value is on}, all top-most block quotes within
|
25
|
+
* the selection will be removed. If it is off, all selected blocks will be wrapped with
|
26
|
+
* a block quote.
|
27
|
+
*
|
28
|
+
* @fires execute
|
29
|
+
* @param options Command options.
|
30
|
+
* @param options.forceValue If set, it will force the command behavior. If `true`, the command will apply a block quote,
|
31
|
+
* otherwise the command will remove the block quote. If not set, the command will act basing on its current value.
|
32
|
+
*/
|
33
|
+
execute(options = {}) {
|
34
|
+
const model = this.editor.model;
|
35
|
+
const schema = model.schema;
|
36
|
+
const selection = model.document.selection;
|
37
|
+
const blocks = Array.from(selection.getSelectedBlocks());
|
38
|
+
const value = (options.forceValue === undefined) ? !this.value : options.forceValue;
|
39
|
+
model.change(writer => {
|
40
|
+
if (!value) {
|
41
|
+
this._removeQuote(writer, blocks.filter(findQuote));
|
42
|
+
}
|
43
|
+
else {
|
44
|
+
const blocksToQuote = blocks.filter(block => {
|
45
|
+
// Already quoted blocks needs to be considered while quoting too
|
46
|
+
// in order to reuse their <bQ> elements.
|
47
|
+
return findQuote(block) || checkCanBeQuoted(schema, block);
|
48
|
+
});
|
49
|
+
this._applyQuote(writer, blocksToQuote);
|
50
|
+
}
|
51
|
+
});
|
52
|
+
}
|
53
|
+
/**
|
54
|
+
* Checks the command's {@link #value}.
|
55
|
+
*/
|
56
|
+
_getValue() {
|
57
|
+
const selection = this.editor.model.document.selection;
|
58
|
+
const firstBlock = first(selection.getSelectedBlocks());
|
59
|
+
// In the current implementation, the block quote must be an immediate parent of a block element.
|
60
|
+
return !!(firstBlock && findQuote(firstBlock));
|
61
|
+
}
|
62
|
+
/**
|
63
|
+
* Checks whether the command can be enabled in the current context.
|
64
|
+
*
|
65
|
+
* @returns Whether the command should be enabled.
|
66
|
+
*/
|
67
|
+
_checkEnabled() {
|
68
|
+
if (this.value) {
|
69
|
+
return true;
|
70
|
+
}
|
71
|
+
const selection = this.editor.model.document.selection;
|
72
|
+
const schema = this.editor.model.schema;
|
73
|
+
const firstBlock = first(selection.getSelectedBlocks());
|
74
|
+
if (!firstBlock) {
|
75
|
+
return false;
|
76
|
+
}
|
77
|
+
return checkCanBeQuoted(schema, firstBlock);
|
78
|
+
}
|
79
|
+
/**
|
80
|
+
* Removes the quote from given blocks.
|
81
|
+
*
|
82
|
+
* If blocks which are supposed to be "unquoted" are in the middle of a quote,
|
83
|
+
* start it or end it, then the quote will be split (if needed) and the blocks
|
84
|
+
* will be moved out of it, so other quoted blocks remained quoted.
|
85
|
+
*/
|
86
|
+
_removeQuote(writer, blocks) {
|
87
|
+
// Unquote all groups of block. Iterate in the reverse order to not break following ranges.
|
88
|
+
getRangesOfBlockGroups(writer, blocks).reverse().forEach(groupRange => {
|
89
|
+
if (groupRange.start.isAtStart && groupRange.end.isAtEnd) {
|
90
|
+
writer.unwrap(groupRange.start.parent);
|
91
|
+
return;
|
92
|
+
}
|
93
|
+
// The group of blocks are at the beginning of an <bQ> so let's move them left (out of the <bQ>).
|
94
|
+
if (groupRange.start.isAtStart) {
|
95
|
+
const positionBefore = writer.createPositionBefore(groupRange.start.parent);
|
96
|
+
writer.move(groupRange, positionBefore);
|
97
|
+
return;
|
98
|
+
}
|
99
|
+
// The blocks are in the middle of an <bQ> so we need to split the <bQ> after the last block
|
100
|
+
// so we move the items there.
|
101
|
+
if (!groupRange.end.isAtEnd) {
|
102
|
+
writer.split(groupRange.end);
|
103
|
+
}
|
104
|
+
// Now we are sure that groupRange.end.isAtEnd is true, so let's move the blocks right.
|
105
|
+
const positionAfter = writer.createPositionAfter(groupRange.end.parent);
|
106
|
+
writer.move(groupRange, positionAfter);
|
107
|
+
});
|
108
|
+
}
|
109
|
+
/**
|
110
|
+
* Applies the quote to given blocks.
|
111
|
+
*/
|
112
|
+
_applyQuote(writer, blocks) {
|
113
|
+
const quotesToMerge = [];
|
114
|
+
// Quote all groups of block. Iterate in the reverse order to not break following ranges.
|
115
|
+
getRangesOfBlockGroups(writer, blocks).reverse().forEach(groupRange => {
|
116
|
+
let quote = findQuote(groupRange.start);
|
117
|
+
if (!quote) {
|
118
|
+
quote = writer.createElement('blockQuote');
|
119
|
+
writer.wrap(groupRange, quote);
|
120
|
+
}
|
121
|
+
quotesToMerge.push(quote);
|
122
|
+
});
|
123
|
+
// Merge subsequent <bQ> elements. Reverse the order again because this time we want to go through
|
124
|
+
// the <bQ> elements in the source order (due to how merge works – it moves the right element's content
|
125
|
+
// to the first element and removes the right one. Since we may need to merge a couple of subsequent `<bQ>` elements
|
126
|
+
// we want to keep the reference to the first (furthest left) one.
|
127
|
+
quotesToMerge.reverse().reduce((currentQuote, nextQuote) => {
|
128
|
+
if (currentQuote.nextSibling == nextQuote) {
|
129
|
+
writer.merge(writer.createPositionAfter(currentQuote));
|
130
|
+
return currentQuote;
|
131
|
+
}
|
132
|
+
return nextQuote;
|
133
|
+
});
|
134
|
+
}
|
135
|
+
}
|
136
|
+
function findQuote(elementOrPosition) {
|
137
|
+
return elementOrPosition.parent.name == 'blockQuote' ? elementOrPosition.parent : null;
|
138
|
+
}
|
139
|
+
/**
|
140
|
+
* Returns a minimal array of ranges containing groups of subsequent blocks.
|
141
|
+
*
|
142
|
+
* content: abcdefgh
|
143
|
+
* blocks: [ a, b, d, f, g, h ]
|
144
|
+
* output ranges: [ab]c[d]e[fgh]
|
145
|
+
*/
|
146
|
+
function getRangesOfBlockGroups(writer, blocks) {
|
147
|
+
let startPosition;
|
148
|
+
let i = 0;
|
149
|
+
const ranges = [];
|
150
|
+
while (i < blocks.length) {
|
151
|
+
const block = blocks[i];
|
152
|
+
const nextBlock = blocks[i + 1];
|
153
|
+
if (!startPosition) {
|
154
|
+
startPosition = writer.createPositionBefore(block);
|
155
|
+
}
|
156
|
+
if (!nextBlock || block.nextSibling != nextBlock) {
|
157
|
+
ranges.push(writer.createRange(startPosition, writer.createPositionAfter(block)));
|
158
|
+
startPosition = null;
|
159
|
+
}
|
160
|
+
i++;
|
161
|
+
}
|
162
|
+
return ranges;
|
163
|
+
}
|
164
|
+
/**
|
165
|
+
* Checks whether <bQ> can wrap the block.
|
166
|
+
*/
|
167
|
+
function checkCanBeQuoted(schema, block) {
|
168
|
+
// TMP will be replaced with schema.checkWrap().
|
169
|
+
const isBQAllowed = schema.checkChild(block.parent, 'blockQuote');
|
170
|
+
const isBlockAllowedInBQ = schema.checkChild(['$root', 'blockQuote'], block);
|
171
|
+
return isBQAllowed && isBlockAllowedInBQ;
|
172
|
+
}
|
@@ -1,31 +1,31 @@
|
|
1
|
-
/**
|
2
|
-
* @license Copyright (c) 2003-2023, 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
|
-
* @module block-quote/blockquoteediting
|
7
|
-
*/
|
8
|
-
import { Plugin } from 'ckeditor5/src/core';
|
9
|
-
import { Enter } from 'ckeditor5/src/enter';
|
10
|
-
import { Delete } from 'ckeditor5/src/typing';
|
11
|
-
/**
|
12
|
-
* The block quote editing.
|
13
|
-
*
|
14
|
-
* Introduces the `'blockQuote'` command and the `'blockQuote'` model element.
|
15
|
-
*
|
16
|
-
* @extends module:core/plugin~Plugin
|
17
|
-
*/
|
18
|
-
export default class BlockQuoteEditing extends Plugin {
|
19
|
-
/**
|
20
|
-
* @inheritDoc
|
21
|
-
*/
|
22
|
-
static get pluginName():
|
23
|
-
/**
|
24
|
-
* @inheritDoc
|
25
|
-
*/
|
26
|
-
static get requires(): readonly [typeof Enter, typeof Delete];
|
27
|
-
/**
|
28
|
-
* @inheritDoc
|
29
|
-
*/
|
30
|
-
init(): void;
|
31
|
-
}
|
1
|
+
/**
|
2
|
+
* @license Copyright (c) 2003-2023, 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
|
+
* @module block-quote/blockquoteediting
|
7
|
+
*/
|
8
|
+
import { Plugin } from 'ckeditor5/src/core';
|
9
|
+
import { Enter } from 'ckeditor5/src/enter';
|
10
|
+
import { Delete } from 'ckeditor5/src/typing';
|
11
|
+
/**
|
12
|
+
* The block quote editing.
|
13
|
+
*
|
14
|
+
* Introduces the `'blockQuote'` command and the `'blockQuote'` model element.
|
15
|
+
*
|
16
|
+
* @extends module:core/plugin~Plugin
|
17
|
+
*/
|
18
|
+
export default class BlockQuoteEditing extends Plugin {
|
19
|
+
/**
|
20
|
+
* @inheritDoc
|
21
|
+
*/
|
22
|
+
static get pluginName(): "BlockQuoteEditing";
|
23
|
+
/**
|
24
|
+
* @inheritDoc
|
25
|
+
*/
|
26
|
+
static get requires(): readonly [typeof Enter, typeof Delete];
|
27
|
+
/**
|
28
|
+
* @inheritDoc
|
29
|
+
*/
|
30
|
+
init(): void;
|
31
|
+
}
|
package/src/blockquoteediting.js
CHANGED
@@ -1,118 +1,118 @@
|
|
1
|
-
/**
|
2
|
-
* @license Copyright (c) 2003-2023, 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
|
-
* @module block-quote/blockquoteediting
|
7
|
-
*/
|
8
|
-
import { Plugin } from 'ckeditor5/src/core';
|
9
|
-
import { Enter } from 'ckeditor5/src/enter';
|
10
|
-
import { Delete } from 'ckeditor5/src/typing';
|
11
|
-
import BlockQuoteCommand from './blockquotecommand';
|
12
|
-
/**
|
13
|
-
* The block quote editing.
|
14
|
-
*
|
15
|
-
* Introduces the `'blockQuote'` command and the `'blockQuote'` model element.
|
16
|
-
*
|
17
|
-
* @extends module:core/plugin~Plugin
|
18
|
-
*/
|
19
|
-
export default class BlockQuoteEditing extends Plugin {
|
20
|
-
/**
|
21
|
-
* @inheritDoc
|
22
|
-
*/
|
23
|
-
static get pluginName() {
|
24
|
-
return 'BlockQuoteEditing';
|
25
|
-
}
|
26
|
-
/**
|
27
|
-
* @inheritDoc
|
28
|
-
*/
|
29
|
-
static get requires() {
|
30
|
-
return [Enter, Delete];
|
31
|
-
}
|
32
|
-
/**
|
33
|
-
* @inheritDoc
|
34
|
-
*/
|
35
|
-
init() {
|
36
|
-
const editor = this.editor;
|
37
|
-
const schema = editor.model.schema;
|
38
|
-
editor.commands.add('blockQuote', new BlockQuoteCommand(editor));
|
39
|
-
schema.register('blockQuote', {
|
40
|
-
inheritAllFrom: '$container'
|
41
|
-
});
|
42
|
-
editor.conversion.elementToElement({ model: 'blockQuote', view: 'blockquote' });
|
43
|
-
// Postfixer which cleans incorrect model states connected with block quotes.
|
44
|
-
editor.model.document.registerPostFixer(writer => {
|
45
|
-
const changes = editor.model.document.differ.getChanges();
|
46
|
-
for (const entry of changes) {
|
47
|
-
if (entry.type == 'insert') {
|
48
|
-
const element = entry.position.nodeAfter;
|
49
|
-
if (!element) {
|
50
|
-
// We are inside a text node.
|
51
|
-
continue;
|
52
|
-
}
|
53
|
-
if (element.is('element', 'blockQuote') && element.isEmpty) {
|
54
|
-
// Added an empty blockQuote - remove it.
|
55
|
-
writer.remove(element);
|
56
|
-
return true;
|
57
|
-
}
|
58
|
-
else if (element.is('element', 'blockQuote') && !schema.checkChild(entry.position, element)) {
|
59
|
-
// Added a blockQuote in incorrect place. Unwrap it so the content inside is not lost.
|
60
|
-
writer.unwrap(element);
|
61
|
-
return true;
|
62
|
-
}
|
63
|
-
else if (element.is('element')) {
|
64
|
-
// Just added an element. Check that all children meet the scheme rules.
|
65
|
-
const range = writer.createRangeIn(element);
|
66
|
-
for (const child of range.getItems()) {
|
67
|
-
if (child.is('element', 'blockQuote') &&
|
68
|
-
!schema.checkChild(writer.createPositionBefore(child), child)) {
|
69
|
-
writer.unwrap(child);
|
70
|
-
return true;
|
71
|
-
}
|
72
|
-
}
|
73
|
-
}
|
74
|
-
}
|
75
|
-
else if (entry.type == 'remove') {
|
76
|
-
const parent = entry.position.parent;
|
77
|
-
if (parent.is('element', 'blockQuote') && parent.isEmpty) {
|
78
|
-
// Something got removed and now blockQuote is empty. Remove the blockQuote as well.
|
79
|
-
writer.remove(parent);
|
80
|
-
return true;
|
81
|
-
}
|
82
|
-
}
|
83
|
-
}
|
84
|
-
return false;
|
85
|
-
});
|
86
|
-
const viewDocument = this.editor.editing.view.document;
|
87
|
-
const selection = editor.model.document.selection;
|
88
|
-
const blockQuoteCommand = editor.commands.get('blockQuote');
|
89
|
-
// Overwrite default Enter key behavior.
|
90
|
-
// If Enter key is pressed with selection collapsed in empty block inside a quote, break the quote.
|
91
|
-
this.listenTo(viewDocument, 'enter', (evt, data) => {
|
92
|
-
if (!selection.isCollapsed || !blockQuoteCommand.value) {
|
93
|
-
return;
|
94
|
-
}
|
95
|
-
const positionParent = selection.getLastPosition().parent;
|
96
|
-
if (positionParent.isEmpty) {
|
97
|
-
editor.execute('blockQuote');
|
98
|
-
editor.editing.view.scrollToTheSelection();
|
99
|
-
data.preventDefault();
|
100
|
-
evt.stop();
|
101
|
-
}
|
102
|
-
}, { context: 'blockquote' });
|
103
|
-
// Overwrite default Backspace key behavior.
|
104
|
-
// If Backspace key is pressed with selection collapsed in first empty block inside a quote, break the quote.
|
105
|
-
this.listenTo(viewDocument, 'delete', (evt, data) => {
|
106
|
-
if (data.direction != 'backward' || !selection.isCollapsed || !blockQuoteCommand.value) {
|
107
|
-
return;
|
108
|
-
}
|
109
|
-
const positionParent = selection.getLastPosition().parent;
|
110
|
-
if (positionParent.isEmpty && !positionParent.previousSibling) {
|
111
|
-
editor.execute('blockQuote');
|
112
|
-
editor.editing.view.scrollToTheSelection();
|
113
|
-
data.preventDefault();
|
114
|
-
evt.stop();
|
115
|
-
}
|
116
|
-
}, { context: 'blockquote' });
|
117
|
-
}
|
118
|
-
}
|
1
|
+
/**
|
2
|
+
* @license Copyright (c) 2003-2023, 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
|
+
* @module block-quote/blockquoteediting
|
7
|
+
*/
|
8
|
+
import { Plugin } from 'ckeditor5/src/core';
|
9
|
+
import { Enter } from 'ckeditor5/src/enter';
|
10
|
+
import { Delete } from 'ckeditor5/src/typing';
|
11
|
+
import BlockQuoteCommand from './blockquotecommand';
|
12
|
+
/**
|
13
|
+
* The block quote editing.
|
14
|
+
*
|
15
|
+
* Introduces the `'blockQuote'` command and the `'blockQuote'` model element.
|
16
|
+
*
|
17
|
+
* @extends module:core/plugin~Plugin
|
18
|
+
*/
|
19
|
+
export default class BlockQuoteEditing extends Plugin {
|
20
|
+
/**
|
21
|
+
* @inheritDoc
|
22
|
+
*/
|
23
|
+
static get pluginName() {
|
24
|
+
return 'BlockQuoteEditing';
|
25
|
+
}
|
26
|
+
/**
|
27
|
+
* @inheritDoc
|
28
|
+
*/
|
29
|
+
static get requires() {
|
30
|
+
return [Enter, Delete];
|
31
|
+
}
|
32
|
+
/**
|
33
|
+
* @inheritDoc
|
34
|
+
*/
|
35
|
+
init() {
|
36
|
+
const editor = this.editor;
|
37
|
+
const schema = editor.model.schema;
|
38
|
+
editor.commands.add('blockQuote', new BlockQuoteCommand(editor));
|
39
|
+
schema.register('blockQuote', {
|
40
|
+
inheritAllFrom: '$container'
|
41
|
+
});
|
42
|
+
editor.conversion.elementToElement({ model: 'blockQuote', view: 'blockquote' });
|
43
|
+
// Postfixer which cleans incorrect model states connected with block quotes.
|
44
|
+
editor.model.document.registerPostFixer(writer => {
|
45
|
+
const changes = editor.model.document.differ.getChanges();
|
46
|
+
for (const entry of changes) {
|
47
|
+
if (entry.type == 'insert') {
|
48
|
+
const element = entry.position.nodeAfter;
|
49
|
+
if (!element) {
|
50
|
+
// We are inside a text node.
|
51
|
+
continue;
|
52
|
+
}
|
53
|
+
if (element.is('element', 'blockQuote') && element.isEmpty) {
|
54
|
+
// Added an empty blockQuote - remove it.
|
55
|
+
writer.remove(element);
|
56
|
+
return true;
|
57
|
+
}
|
58
|
+
else if (element.is('element', 'blockQuote') && !schema.checkChild(entry.position, element)) {
|
59
|
+
// Added a blockQuote in incorrect place. Unwrap it so the content inside is not lost.
|
60
|
+
writer.unwrap(element);
|
61
|
+
return true;
|
62
|
+
}
|
63
|
+
else if (element.is('element')) {
|
64
|
+
// Just added an element. Check that all children meet the scheme rules.
|
65
|
+
const range = writer.createRangeIn(element);
|
66
|
+
for (const child of range.getItems()) {
|
67
|
+
if (child.is('element', 'blockQuote') &&
|
68
|
+
!schema.checkChild(writer.createPositionBefore(child), child)) {
|
69
|
+
writer.unwrap(child);
|
70
|
+
return true;
|
71
|
+
}
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
else if (entry.type == 'remove') {
|
76
|
+
const parent = entry.position.parent;
|
77
|
+
if (parent.is('element', 'blockQuote') && parent.isEmpty) {
|
78
|
+
// Something got removed and now blockQuote is empty. Remove the blockQuote as well.
|
79
|
+
writer.remove(parent);
|
80
|
+
return true;
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
return false;
|
85
|
+
});
|
86
|
+
const viewDocument = this.editor.editing.view.document;
|
87
|
+
const selection = editor.model.document.selection;
|
88
|
+
const blockQuoteCommand = editor.commands.get('blockQuote');
|
89
|
+
// Overwrite default Enter key behavior.
|
90
|
+
// If Enter key is pressed with selection collapsed in empty block inside a quote, break the quote.
|
91
|
+
this.listenTo(viewDocument, 'enter', (evt, data) => {
|
92
|
+
if (!selection.isCollapsed || !blockQuoteCommand.value) {
|
93
|
+
return;
|
94
|
+
}
|
95
|
+
const positionParent = selection.getLastPosition().parent;
|
96
|
+
if (positionParent.isEmpty) {
|
97
|
+
editor.execute('blockQuote');
|
98
|
+
editor.editing.view.scrollToTheSelection();
|
99
|
+
data.preventDefault();
|
100
|
+
evt.stop();
|
101
|
+
}
|
102
|
+
}, { context: 'blockquote' });
|
103
|
+
// Overwrite default Backspace key behavior.
|
104
|
+
// If Backspace key is pressed with selection collapsed in first empty block inside a quote, break the quote.
|
105
|
+
this.listenTo(viewDocument, 'delete', (evt, data) => {
|
106
|
+
if (data.direction != 'backward' || !selection.isCollapsed || !blockQuoteCommand.value) {
|
107
|
+
return;
|
108
|
+
}
|
109
|
+
const positionParent = selection.getLastPosition().parent;
|
110
|
+
if (positionParent.isEmpty && !positionParent.previousSibling) {
|
111
|
+
editor.execute('blockQuote');
|
112
|
+
editor.editing.view.scrollToTheSelection();
|
113
|
+
data.preventDefault();
|
114
|
+
evt.stop();
|
115
|
+
}
|
116
|
+
}, { context: 'blockquote' });
|
117
|
+
}
|
118
|
+
}
|