@ckeditor/ckeditor5-typing 35.2.1 → 35.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,15 +2,11 @@
2
2
  * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  /**
7
6
  * @module typing/twostepcaretmovement
8
7
  */
9
-
10
8
  import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
11
-
12
9
  import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
13
-
14
10
  /**
15
11
  * This plugin enables the two-step caret (phantom) movement behavior for
16
12
  * {@link module:typing/twostepcaretmovement~TwoStepCaretMovement#registerAttribute registered attributes}
@@ -103,321 +99,287 @@ import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
103
99
  *
104
100
  */
105
101
  export default class TwoStepCaretMovement extends Plugin {
106
- /**
107
- * @inheritDoc
108
- */
109
- static get pluginName() {
110
- return 'TwoStepCaretMovement';
111
- }
112
-
113
- /**
114
- * @inheritDoc
115
- */
116
- constructor( editor ) {
117
- super( editor );
118
-
119
- /**
120
- * A set of attributes to handle.
121
- *
122
- * @protected
123
- * @property {module:typing/twostepcaretmovement~TwoStepCaretMovement}
124
- */
125
- this.attributes = new Set();
126
-
127
- /**
128
- * The current UID of the overridden gravity, as returned by
129
- * {@link module:engine/model/writer~Writer#overrideSelectionGravity}.
130
- *
131
- * @private
132
- * @member {String}
133
- */
134
- this._overrideUid = null;
135
- }
136
-
137
- /**
138
- * @inheritDoc
139
- */
140
- init() {
141
- const editor = this.editor;
142
- const model = editor.model;
143
- const view = editor.editing.view;
144
- const locale = editor.locale;
145
-
146
- const modelSelection = model.document.selection;
147
-
148
- // Listen to keyboard events and handle the caret movement according to the 2-step caret logic.
149
- this.listenTo( view.document, 'arrowKey', ( evt, data ) => {
150
- // This implementation works only for collapsed selection.
151
- if ( !modelSelection.isCollapsed ) {
152
- return;
153
- }
154
-
155
- // When user tries to expand the selection or jump over the whole word or to the beginning/end then
156
- // two-steps movement is not necessary.
157
- if ( data.shiftKey || data.altKey || data.ctrlKey ) {
158
- return;
159
- }
160
-
161
- const arrowRightPressed = data.keyCode == keyCodes.arrowright;
162
- const arrowLeftPressed = data.keyCode == keyCodes.arrowleft;
163
-
164
- // When neither left or right arrow has been pressed then do noting.
165
- if ( !arrowRightPressed && !arrowLeftPressed ) {
166
- return;
167
- }
168
-
169
- const contentDirection = locale.contentLanguageDirection;
170
- let isMovementHandled = false;
171
-
172
- if ( ( contentDirection === 'ltr' && arrowRightPressed ) || ( contentDirection === 'rtl' && arrowLeftPressed ) ) {
173
- isMovementHandled = this._handleForwardMovement( data );
174
- } else {
175
- isMovementHandled = this._handleBackwardMovement( data );
176
- }
177
-
178
- // Stop the keydown event if the two-step caret movement handled it. Avoid collisions
179
- // with other features which may also take over the caret movement (e.g. Widget).
180
- if ( isMovementHandled === true ) {
181
- evt.stop();
182
- }
183
- }, { context: '$text', priority: 'highest' } );
184
-
185
- /**
186
- * A flag indicating that the automatic gravity restoration should not happen upon the next
187
- * gravity restoration.
188
- * {@link module:engine/model/selection~Selection#event:change:range} event.
189
- *
190
- * @private
191
- * @member {String}
192
- */
193
- this._isNextGravityRestorationSkipped = false;
194
-
195
- // The automatic gravity restoration logic.
196
- this.listenTo( modelSelection, 'change:range', ( evt, data ) => {
197
- // Skipping the automatic restoration is needed if the selection should change
198
- // but the gravity must remain overridden afterwards. See the #handleBackwardMovement
199
- // to learn more.
200
- if ( this._isNextGravityRestorationSkipped ) {
201
- this._isNextGravityRestorationSkipped = false;
202
-
203
- return;
204
- }
205
-
206
- // Skip automatic restore when the gravity is not overridden — simply, there's nothing to restore
207
- // at this moment.
208
- if ( !this._isGravityOverridden ) {
209
- return;
210
- }
211
-
212
- // Skip automatic restore when the change is indirect AND the selection is at the attribute boundary.
213
- // It means that e.g. if the change was external (collaboration) and the user had their
214
- // selection around the link, its gravity should remain intact in this change:range event.
215
- if ( !data.directChange && isBetweenDifferentAttributes( modelSelection.getFirstPosition(), this.attributes ) ) {
216
- return;
217
- }
218
-
219
- this._restoreGravity();
220
- } );
221
- }
222
-
223
- /**
224
- * Registers a given attribute for the two-step caret movement.
225
- *
226
- * @param {String} attribute Name of the attribute to handle.
227
- */
228
- registerAttribute( attribute ) {
229
- this.attributes.add( attribute );
230
- }
231
-
232
- /**
233
- * Updates the document selection and the view according to the two–step caret movement state
234
- * when moving **forwards**. Executed upon `keypress` in the {@link module:engine/view/view~View}.
235
- *
236
- * @private
237
- * @param {module:engine/view/observer/domeventdata~DomEventData} data Data of the key press.
238
- * @returns {Boolean} `true` when the handler prevented caret movement
239
- */
240
- _handleForwardMovement( data ) {
241
- const attributes = this.attributes;
242
- const model = this.editor.model;
243
- const selection = model.document.selection;
244
- const position = selection.getFirstPosition();
245
- // DON'T ENGAGE 2-SCM if gravity is already overridden. It means that we just entered
246
- //
247
- // <paragraph>foo<$text attribute>{}bar</$text>baz</paragraph>
248
- //
249
- // or left the attribute
250
- //
251
- // <paragraph>foo<$text attribute>bar</$text>{}baz</paragraph>
252
- //
253
- // and the gravity will be restored automatically.
254
- if ( this._isGravityOverridden ) {
255
- return false;
256
- }
257
-
258
- // DON'T ENGAGE 2-SCM when the selection is at the beginning of the block AND already has the
259
- // attribute:
260
- // * when the selection was initially set there using the mouse,
261
- // * when the editor has just started
262
- //
263
- // <paragraph><$text attribute>{}bar</$text>baz</paragraph>
264
- //
265
- if ( position.isAtStart && hasAnyAttribute( selection, attributes ) ) {
266
- return false;
267
- }
268
-
269
- // ENGAGE 2-SCM When at least one of the observed attributes changes its value (incl. starts, ends).
270
- //
271
- // <paragraph>foo<$text attribute>bar{}</$text>baz</paragraph>
272
- // <paragraph>foo<$text attribute>bar{}</$text><$text otherAttribute>baz</$text></paragraph>
273
- // <paragraph>foo<$text attribute=1>bar{}</$text><$text attribute=2>baz</$text></paragraph>
274
- // <paragraph>foo{}<$text attribute>bar</$text>baz</paragraph>
275
- //
276
- if ( isBetweenDifferentAttributes( position, attributes ) ) {
277
- preventCaretMovement( data );
278
- this._overrideGravity();
279
- return true;
280
- }
281
- }
282
-
283
- /**
284
- * Updates the document selection and the view according to the two–step caret movement state
285
- * when moving **backwards**. Executed upon `keypress` in the {@link module:engine/view/view~View}.
286
- *
287
- * @private
288
- * @param {module:engine/view/observer/domeventdata~DomEventData} data Data of the key press.
289
- * @returns {Boolean} `true` when the handler prevented caret movement
290
- */
291
- _handleBackwardMovement( data ) {
292
- const attributes = this.attributes;
293
- const model = this.editor.model;
294
- const selection = model.document.selection;
295
- const position = selection.getFirstPosition();
296
-
297
- // When the gravity is already overridden (by this plugin), it means we are on the two-step position.
298
- // Prevent the movement, restore the gravity and update selection attributes.
299
- //
300
- // <paragraph>foo<$text attribute=1>bar</$text><$text attribute=2>{}baz</$text></paragraph>
301
- // <paragraph>foo<$text attribute>bar</$text><$text otherAttribute>{}baz</$text></paragraph>
302
- // <paragraph>foo<$text attribute>{}bar</$text>baz</paragraph>
303
- // <paragraph>foo<$text attribute>bar</$text>{}baz</paragraph>
304
- //
305
- if ( this._isGravityOverridden ) {
306
- preventCaretMovement( data );
307
- this._restoreGravity();
308
- setSelectionAttributesFromTheNodeBefore( model, attributes, position );
309
-
310
- return true;
311
- } else {
312
- // REMOVE SELECTION ATTRIBUTE when restoring gravity towards a non-existent content at the
313
- // beginning of the block.
314
- //
315
- // <paragraph>{}<$text attribute>bar</$text></paragraph>
316
- //
317
- if ( position.isAtStart ) {
318
- if ( hasAnyAttribute( selection, attributes ) ) {
319
- preventCaretMovement( data );
320
- setSelectionAttributesFromTheNodeBefore( model, attributes, position );
321
-
322
- return true;
323
- }
324
-
325
- return false;
326
- }
327
-
328
- // When we are moving from natural gravity, to the position of the 2SCM, we need to override the gravity,
329
- // and make sure it won't be restored. Unless it's at the end of the block and an observed attribute.
330
- // We need to check if the caret is a one position before the attribute boundary:
331
- //
332
- // <paragraph>foo<$text attribute=1>bar</$text><$text attribute=2>b{}az</$text></paragraph>
333
- // <paragraph>foo<$text attribute>bar</$text><$text otherAttribute>b{}az</$text></paragraph>
334
- // <paragraph>foo<$text attribute>b{}ar</$text>baz</paragraph>
335
- // <paragraph>foo<$text attribute>bar</$text>b{}az</paragraph>
336
- //
337
- if ( isStepAfterAnyAttributeBoundary( position, attributes ) ) {
338
- // ENGAGE 2-SCM if the selection has no attribute. This may happen when the user
339
- // left the attribute using a FORWARD 2-SCM.
340
- //
341
- // <paragraph><$text attribute>bar</$text>{}</paragraph>
342
- //
343
- if (
344
- position.isAtEnd &&
345
- !hasAnyAttribute( selection, attributes ) &&
346
- isBetweenDifferentAttributes( position, attributes )
347
- ) {
348
- preventCaretMovement( data );
349
- setSelectionAttributesFromTheNodeBefore( model, attributes, position );
350
-
351
- return true;
352
- }
353
- // Skip the automatic gravity restore upon the next selection#change:range event.
354
- // If not skipped, it would automatically restore the gravity, which should remain
355
- // overridden.
356
- this._isNextGravityRestorationSkipped = true;
357
- this._overrideGravity();
358
-
359
- // Don't return "true" here because we didn't call _preventCaretMovement.
360
- // Returning here will destabilize the filler logic, which also listens to
361
- // keydown (and the event would be stopped).
362
- return false;
363
- }
364
- }
365
- }
366
-
367
- /**
368
- * `true` when the gravity is overridden for the plugin.
369
- *
370
- * @readonly
371
- * @private
372
- * @type {Boolean}
373
- */
374
- get _isGravityOverridden() {
375
- return !!this._overrideUid;
376
- }
377
-
378
- /**
379
- * Overrides the gravity using the {@link module:engine/model/writer~Writer model writer}
380
- * and stores the information about this fact in the {@link #_overrideUid}.
381
- *
382
- * A shorthand for {@link module:engine/model/writer~Writer#overrideSelectionGravity}.
383
- *
384
- * @private
385
- */
386
- _overrideGravity() {
387
- this._overrideUid = this.editor.model.change( writer => {
388
- return writer.overrideSelectionGravity();
389
- } );
390
- }
391
-
392
- /**
393
- * Restores the gravity using the {@link module:engine/model/writer~Writer model writer}.
394
- *
395
- * A shorthand for {@link module:engine/model/writer~Writer#restoreSelectionGravity}.
396
- *
397
- * @private
398
- */
399
- _restoreGravity() {
400
- this.editor.model.change( writer => {
401
- writer.restoreSelectionGravity( this._overrideUid );
402
- this._overrideUid = null;
403
- } );
404
- }
102
+ /**
103
+ * @inheritDoc
104
+ */
105
+ constructor(editor) {
106
+ super(editor);
107
+ /**
108
+ * A set of attributes to handle.
109
+ *
110
+ * @protected
111
+ * @property {module:typing/twostepcaretmovement~TwoStepCaretMovement}
112
+ */
113
+ this.attributes = new Set();
114
+ /**
115
+ * The current UID of the overridden gravity, as returned by
116
+ * {@link module:engine/model/writer~Writer#overrideSelectionGravity}.
117
+ *
118
+ * @private
119
+ * @member {String}
120
+ */
121
+ this._overrideUid = null;
122
+ }
123
+ /**
124
+ * @inheritDoc
125
+ */
126
+ static get pluginName() {
127
+ return 'TwoStepCaretMovement';
128
+ }
129
+ /**
130
+ * @inheritDoc
131
+ */
132
+ init() {
133
+ const editor = this.editor;
134
+ const model = editor.model;
135
+ const view = editor.editing.view;
136
+ const locale = editor.locale;
137
+ const modelSelection = model.document.selection;
138
+ // Listen to keyboard events and handle the caret movement according to the 2-step caret logic.
139
+ this.listenTo(view.document, 'arrowKey', (evt, data) => {
140
+ // This implementation works only for collapsed selection.
141
+ if (!modelSelection.isCollapsed) {
142
+ return;
143
+ }
144
+ // When user tries to expand the selection or jump over the whole word or to the beginning/end then
145
+ // two-steps movement is not necessary.
146
+ if (data.shiftKey || data.altKey || data.ctrlKey) {
147
+ return;
148
+ }
149
+ const arrowRightPressed = data.keyCode == keyCodes.arrowright;
150
+ const arrowLeftPressed = data.keyCode == keyCodes.arrowleft;
151
+ // When neither left or right arrow has been pressed then do noting.
152
+ if (!arrowRightPressed && !arrowLeftPressed) {
153
+ return;
154
+ }
155
+ const contentDirection = locale.contentLanguageDirection;
156
+ let isMovementHandled = false;
157
+ if ((contentDirection === 'ltr' && arrowRightPressed) || (contentDirection === 'rtl' && arrowLeftPressed)) {
158
+ isMovementHandled = this._handleForwardMovement(data);
159
+ }
160
+ else {
161
+ isMovementHandled = this._handleBackwardMovement(data);
162
+ }
163
+ // Stop the keydown event if the two-step caret movement handled it. Avoid collisions
164
+ // with other features which may also take over the caret movement (e.g. Widget).
165
+ if (isMovementHandled === true) {
166
+ evt.stop();
167
+ }
168
+ }, { context: '$text', priority: 'highest' });
169
+ /**
170
+ * A flag indicating that the automatic gravity restoration should not happen upon the next
171
+ * gravity restoration.
172
+ * {@link module:engine/model/selection~Selection#event:change:range} event.
173
+ *
174
+ * @private
175
+ * @member {String}
176
+ */
177
+ this._isNextGravityRestorationSkipped = false;
178
+ // The automatic gravity restoration logic.
179
+ this.listenTo(modelSelection, 'change:range', (evt, data) => {
180
+ // Skipping the automatic restoration is needed if the selection should change
181
+ // but the gravity must remain overridden afterwards. See the #handleBackwardMovement
182
+ // to learn more.
183
+ if (this._isNextGravityRestorationSkipped) {
184
+ this._isNextGravityRestorationSkipped = false;
185
+ return;
186
+ }
187
+ // Skip automatic restore when the gravity is not overridden — simply, there's nothing to restore
188
+ // at this moment.
189
+ if (!this._isGravityOverridden) {
190
+ return;
191
+ }
192
+ // Skip automatic restore when the change is indirect AND the selection is at the attribute boundary.
193
+ // It means that e.g. if the change was external (collaboration) and the user had their
194
+ // selection around the link, its gravity should remain intact in this change:range event.
195
+ if (!data.directChange && isBetweenDifferentAttributes(modelSelection.getFirstPosition(), this.attributes)) {
196
+ return;
197
+ }
198
+ this._restoreGravity();
199
+ });
200
+ }
201
+ /**
202
+ * Registers a given attribute for the two-step caret movement.
203
+ *
204
+ * @param {String} attribute Name of the attribute to handle.
205
+ */
206
+ registerAttribute(attribute) {
207
+ this.attributes.add(attribute);
208
+ }
209
+ /**
210
+ * Updates the document selection and the view according to the two–step caret movement state
211
+ * when moving **forwards**. Executed upon `keypress` in the {@link module:engine/view/view~View}.
212
+ *
213
+ * @private
214
+ * @param {module:engine/view/observer/domeventdata~DomEventData} data Data of the key press.
215
+ * @returns {Boolean} `true` when the handler prevented caret movement
216
+ */
217
+ _handleForwardMovement(data) {
218
+ const attributes = this.attributes;
219
+ const model = this.editor.model;
220
+ const selection = model.document.selection;
221
+ const position = selection.getFirstPosition();
222
+ // DON'T ENGAGE 2-SCM if gravity is already overridden. It means that we just entered
223
+ //
224
+ // <paragraph>foo<$text attribute>{}bar</$text>baz</paragraph>
225
+ //
226
+ // or left the attribute
227
+ //
228
+ // <paragraph>foo<$text attribute>bar</$text>{}baz</paragraph>
229
+ //
230
+ // and the gravity will be restored automatically.
231
+ if (this._isGravityOverridden) {
232
+ return false;
233
+ }
234
+ // DON'T ENGAGE 2-SCM when the selection is at the beginning of the block AND already has the
235
+ // attribute:
236
+ // * when the selection was initially set there using the mouse,
237
+ // * when the editor has just started
238
+ //
239
+ // <paragraph><$text attribute>{}bar</$text>baz</paragraph>
240
+ //
241
+ if (position.isAtStart && hasAnyAttribute(selection, attributes)) {
242
+ return false;
243
+ }
244
+ // ENGAGE 2-SCM When at least one of the observed attributes changes its value (incl. starts, ends).
245
+ //
246
+ // <paragraph>foo<$text attribute>bar{}</$text>baz</paragraph>
247
+ // <paragraph>foo<$text attribute>bar{}</$text><$text otherAttribute>baz</$text></paragraph>
248
+ // <paragraph>foo<$text attribute=1>bar{}</$text><$text attribute=2>baz</$text></paragraph>
249
+ // <paragraph>foo{}<$text attribute>bar</$text>baz</paragraph>
250
+ //
251
+ if (isBetweenDifferentAttributes(position, attributes)) {
252
+ preventCaretMovement(data);
253
+ this._overrideGravity();
254
+ return true;
255
+ }
256
+ return false;
257
+ }
258
+ /**
259
+ * Updates the document selection and the view according to the two–step caret movement state
260
+ * when moving **backwards**. Executed upon `keypress` in the {@link module:engine/view/view~View}.
261
+ *
262
+ * @private
263
+ * @param {module:engine/view/observer/domeventdata~DomEventData} data Data of the key press.
264
+ * @returns {Boolean} `true` when the handler prevented caret movement
265
+ */
266
+ _handleBackwardMovement(data) {
267
+ const attributes = this.attributes;
268
+ const model = this.editor.model;
269
+ const selection = model.document.selection;
270
+ const position = selection.getFirstPosition();
271
+ // When the gravity is already overridden (by this plugin), it means we are on the two-step position.
272
+ // Prevent the movement, restore the gravity and update selection attributes.
273
+ //
274
+ // <paragraph>foo<$text attribute=1>bar</$text><$text attribute=2>{}baz</$text></paragraph>
275
+ // <paragraph>foo<$text attribute>bar</$text><$text otherAttribute>{}baz</$text></paragraph>
276
+ // <paragraph>foo<$text attribute>{}bar</$text>baz</paragraph>
277
+ // <paragraph>foo<$text attribute>bar</$text>{}baz</paragraph>
278
+ //
279
+ if (this._isGravityOverridden) {
280
+ preventCaretMovement(data);
281
+ this._restoreGravity();
282
+ setSelectionAttributesFromTheNodeBefore(model, attributes, position);
283
+ return true;
284
+ }
285
+ else {
286
+ // REMOVE SELECTION ATTRIBUTE when restoring gravity towards a non-existent content at the
287
+ // beginning of the block.
288
+ //
289
+ // <paragraph>{}<$text attribute>bar</$text></paragraph>
290
+ //
291
+ if (position.isAtStart) {
292
+ if (hasAnyAttribute(selection, attributes)) {
293
+ preventCaretMovement(data);
294
+ setSelectionAttributesFromTheNodeBefore(model, attributes, position);
295
+ return true;
296
+ }
297
+ return false;
298
+ }
299
+ // When we are moving from natural gravity, to the position of the 2SCM, we need to override the gravity,
300
+ // and make sure it won't be restored. Unless it's at the end of the block and an observed attribute.
301
+ // We need to check if the caret is a one position before the attribute boundary:
302
+ //
303
+ // <paragraph>foo<$text attribute=1>bar</$text><$text attribute=2>b{}az</$text></paragraph>
304
+ // <paragraph>foo<$text attribute>bar</$text><$text otherAttribute>b{}az</$text></paragraph>
305
+ // <paragraph>foo<$text attribute>b{}ar</$text>baz</paragraph>
306
+ // <paragraph>foo<$text attribute>bar</$text>b{}az</paragraph>
307
+ //
308
+ if (isStepAfterAnyAttributeBoundary(position, attributes)) {
309
+ // ENGAGE 2-SCM if the selection has no attribute. This may happen when the user
310
+ // left the attribute using a FORWARD 2-SCM.
311
+ //
312
+ // <paragraph><$text attribute>bar</$text>{}</paragraph>
313
+ //
314
+ if (position.isAtEnd &&
315
+ !hasAnyAttribute(selection, attributes) &&
316
+ isBetweenDifferentAttributes(position, attributes)) {
317
+ preventCaretMovement(data);
318
+ setSelectionAttributesFromTheNodeBefore(model, attributes, position);
319
+ return true;
320
+ }
321
+ // Skip the automatic gravity restore upon the next selection#change:range event.
322
+ // If not skipped, it would automatically restore the gravity, which should remain
323
+ // overridden.
324
+ this._isNextGravityRestorationSkipped = true;
325
+ this._overrideGravity();
326
+ // Don't return "true" here because we didn't call _preventCaretMovement.
327
+ // Returning here will destabilize the filler logic, which also listens to
328
+ // keydown (and the event would be stopped).
329
+ return false;
330
+ }
331
+ }
332
+ return false;
333
+ }
334
+ /**
335
+ * `true` when the gravity is overridden for the plugin.
336
+ *
337
+ * @readonly
338
+ * @private
339
+ * @type {Boolean}
340
+ */
341
+ get _isGravityOverridden() {
342
+ return !!this._overrideUid;
343
+ }
344
+ /**
345
+ * Overrides the gravity using the {@link module:engine/model/writer~Writer model writer}
346
+ * and stores the information about this fact in the {@link #_overrideUid}.
347
+ *
348
+ * A shorthand for {@link module:engine/model/writer~Writer#overrideSelectionGravity}.
349
+ *
350
+ * @private
351
+ */
352
+ _overrideGravity() {
353
+ this._overrideUid = this.editor.model.change(writer => {
354
+ return writer.overrideSelectionGravity();
355
+ });
356
+ }
357
+ /**
358
+ * Restores the gravity using the {@link module:engine/model/writer~Writer model writer}.
359
+ *
360
+ * A shorthand for {@link module:engine/model/writer~Writer#restoreSelectionGravity}.
361
+ *
362
+ * @private
363
+ */
364
+ _restoreGravity() {
365
+ this.editor.model.change(writer => {
366
+ writer.restoreSelectionGravity(this._overrideUid);
367
+ this._overrideUid = null;
368
+ });
369
+ }
405
370
  }
406
-
407
371
  // Checks whether the selection has any of given attributes.
408
372
  //
409
373
  // @param {module:engine/model/documentselection~DocumentSelection} selection
410
374
  // @param {Iterable.<String>} attributes
411
- function hasAnyAttribute( selection, attributes ) {
412
- for ( const observedAttribute of attributes ) {
413
- if ( selection.hasAttribute( observedAttribute ) ) {
414
- return true;
415
- }
416
- }
417
-
418
- return false;
375
+ function hasAnyAttribute(selection, attributes) {
376
+ for (const observedAttribute of attributes) {
377
+ if (selection.hasAttribute(observedAttribute)) {
378
+ return true;
379
+ }
380
+ }
381
+ return false;
419
382
  }
420
-
421
383
  // Applies the given attributes to the current selection using using the
422
384
  // values from the node before the current position. Uses
423
385
  // the {@link module:engine/model/writer~Writer model writer}.
@@ -425,46 +387,43 @@ function hasAnyAttribute( selection, attributes ) {
425
387
  // @param {module:engine/model/model~Model}
426
388
  // @param {Iterable.<String>} attributess
427
389
  // @param {module:engine/model/position~Position} position
428
- function setSelectionAttributesFromTheNodeBefore( model, attributes, position ) {
429
- const nodeBefore = position.nodeBefore;
430
- model.change( writer => {
431
- if ( nodeBefore ) {
432
- writer.setSelectionAttribute( nodeBefore.getAttributes() );
433
- } else {
434
- writer.removeSelectionAttribute( attributes );
435
- }
436
- } );
390
+ function setSelectionAttributesFromTheNodeBefore(model, attributes, position) {
391
+ const nodeBefore = position.nodeBefore;
392
+ model.change(writer => {
393
+ if (nodeBefore) {
394
+ writer.setSelectionAttribute(nodeBefore.getAttributes());
395
+ }
396
+ else {
397
+ writer.removeSelectionAttribute(attributes);
398
+ }
399
+ });
437
400
  }
438
-
439
401
  // Prevents the caret movement in the view by calling `preventDefault` on the event data.
440
402
  //
441
403
  // @alias data.preventDefault
442
- function preventCaretMovement( data ) {
443
- data.preventDefault();
404
+ function preventCaretMovement(data) {
405
+ data.preventDefault();
444
406
  }
445
-
446
407
  // Checks whether the step before `isBetweenDifferentAttributes()`.
447
408
  //
448
409
  // @param {module:engine/model/position~Position} position
449
410
  // @param {String} attribute
450
- function isStepAfterAnyAttributeBoundary( position, attributes ) {
451
- const positionBefore = position.getShiftedBy( -1 );
452
- return isBetweenDifferentAttributes( positionBefore, attributes );
411
+ function isStepAfterAnyAttributeBoundary(position, attributes) {
412
+ const positionBefore = position.getShiftedBy(-1);
413
+ return isBetweenDifferentAttributes(positionBefore, attributes);
453
414
  }
454
-
455
415
  // Checks whether the given position is between different values of given attributes.
456
416
  //
457
417
  // @param {module:engine/model/position~Position} position
458
418
  // @param {Iterable.<String>} attributes
459
- function isBetweenDifferentAttributes( position, attributes ) {
460
- const { nodeBefore, nodeAfter } = position;
461
- for ( const observedAttribute of attributes ) {
462
- const attrBefore = nodeBefore ? nodeBefore.getAttribute( observedAttribute ) : undefined;
463
- const attrAfter = nodeAfter ? nodeAfter.getAttribute( observedAttribute ) : undefined;
464
-
465
- if ( attrAfter !== attrBefore ) {
466
- return true;
467
- }
468
- }
469
- return false;
419
+ function isBetweenDifferentAttributes(position, attributes) {
420
+ const { nodeBefore, nodeAfter } = position;
421
+ for (const observedAttribute of attributes) {
422
+ const attrBefore = nodeBefore ? nodeBefore.getAttribute(observedAttribute) : undefined;
423
+ const attrAfter = nodeAfter ? nodeAfter.getAttribute(observedAttribute) : undefined;
424
+ if (attrAfter !== attrBefore) {
425
+ return true;
426
+ }
427
+ }
428
+ return false;
470
429
  }