7
7
* @module autoformat/inlineautoformatediting
8
8
*/
9
9
10
- import LiveRange from '@ckeditor/ckeditor5-engine/src/model/liverange ' ;
10
+ import ModelRange from '@ckeditor/ckeditor5-engine/src/model/range ' ;
11
11
12
12
/**
13
13
* The inline autoformatting engine. It allows to format various inline patterns. For example,
@@ -141,74 +141,43 @@ export default class InlineAutoformatEditing {
141
141
} ) ;
142
142
143
143
editor . model . document . on ( 'change' , ( ) => {
144
- const changes = editor . model . document . differ . getChanges ( ) ;
144
+ const selection = editor . model . document . selection ;
145
145
146
- for ( const entry of changes ) {
147
- if ( entry . type != 'insert' || entry . name != '$text' ) {
148
- continue ;
149
- }
150
-
151
- const selection = editor . model . document . selection ;
146
+ // Do nothing if selection is not collapsed.
147
+ if ( ! selection . isCollapsed ) {
148
+ return ;
149
+ }
152
150
153
- if ( ! selection . isCollapsed || ! selection . focus || ! selection . focus . parent ) {
154
- continue ;
155
- }
151
+ const changes = Array . from ( editor . model . document . differ . getChanges ( ) ) ;
152
+ const entry = changes [ 0 ] ;
156
153
157
- const block = selection . focus . parent ;
158
- const text = getText ( block ) . slice ( 0 , selection . focus . offset ) ;
159
- const ranges = testCallback ( text ) ;
160
- const rangesToFormat = [ ] ;
161
-
162
- // Apply format before deleting text.
163
- ranges . format . forEach ( range => {
164
- if ( range [ 0 ] === undefined || range [ 1 ] === undefined ) {
165
- return ;
166
- }
167
-
168
- rangesToFormat . push ( LiveRange . createFromParentsAndOffsets (
169
- block , range [ 0 ] ,
170
- block , range [ 1 ]
171
- ) ) ;
172
- } ) ;
173
-
174
- const rangesToRemove = [ ] ;
175
-
176
- // Reverse order to not mix the offsets while removing.
177
- ranges . remove . slice ( ) . reverse ( ) . forEach ( range => {
178
- if ( range [ 0 ] === undefined || range [ 1 ] === undefined ) {
179
- return ;
180
- }
181
-
182
- rangesToRemove . push ( LiveRange . createFromParentsAndOffsets (
183
- block , range [ 0 ] ,
184
- block , range [ 1 ]
185
- ) ) ;
186
- } ) ;
187
-
188
- if ( ! ( rangesToFormat . length && rangesToRemove . length ) ) {
189
- continue ;
190
- }
154
+ // Typing is represented by only a single change.
155
+ if ( changes . length != 1 || entry . type !== 'insert' || entry . name != '$text' || entry . length != 1 ) {
156
+ return ;
157
+ }
191
158
192
- // Use enqueueChange to create new batch to separate typing batch from the auto-format changes.
193
- editor . model . enqueueChange ( writer => {
194
- const validRanges = editor . model . schema . getValidRanges ( rangesToFormat , attributeKey ) ;
159
+ const block = selection . focus . parent ;
160
+ const text = getText ( block ) . slice ( 0 , selection . focus . offset ) ;
161
+ const testOutput = testCallback ( text ) ;
162
+ const rangesToFormat = testOutputToRanges ( block , testOutput . format ) ;
163
+ const rangesToRemove = testOutputToRanges ( block , testOutput . remove ) ;
195
164
196
- // Apply format.
197
- formatCallback ( writer , validRanges ) ;
165
+ if ( ! ( rangesToFormat . length && rangesToRemove . length ) ) {
166
+ return ;
167
+ }
198
168
199
- // Detach ranges used to apply Autoformat. Prevents memory leaks. #39
200
- rangesToFormat . forEach ( range => range . detach ( ) ) ;
169
+ // Use enqueueChange to create new batch to separate typing batch from the auto-format changes.
170
+ editor . model . enqueueChange ( writer => {
171
+ const validRanges = editor . model . schema . getValidRanges ( rangesToFormat , attributeKey ) ;
201
172
202
- // Remove delimiters.
203
- for ( const range of rangesToRemove ) {
204
- writer . remove ( range ) ;
173
+ // Apply format.
174
+ formatCallback ( writer , validRanges ) ;
205
175
206
- // Prevents memory leaks.
207
- // https://github.com/ckeditor/ckeditor5-autoformat/issues/39
208
- range . detach ( ) ;
209
- }
210
- } ) ;
211
- }
176
+ // Remove delimiters - use reversed order to not mix the offsets while removing.
177
+ for ( const range of rangesToRemove . reverse ( ) ) {
178
+ writer . remove ( range ) ;
179
+ }
180
+ } ) ;
212
181
} ) ;
213
182
}
214
183
}
@@ -221,3 +190,15 @@ export default class InlineAutoformatEditing {
221
190
function getText ( element ) {
222
191
return Array . from ( element . getChildren ( ) ) . reduce ( ( a , b ) => a + b . data , '' ) ;
223
192
}
193
+
194
+ // Converts output of the test function provided to the InlineAutoformatEditing and converts it to the model ranges
195
+ // inside provided block.
196
+ //
197
+ // @private
198
+ // @param {module:engine/model/element~Element } block
199
+ // @param {Array.<Array> } arrays
200
+ function testOutputToRanges ( block , arrays ) {
201
+ return arrays
202
+ . filter ( array => ( array [ 0 ] !== undefined && array [ 1 ] !== undefined ) )
203
+ . map ( array => ModelRange . createFromParentsAndOffsets ( block , array [ 0 ] , block , array [ 1 ] ) ) ;
204
+ }
0 commit comments