Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit d8ee5fa

Browse files
authored
Merge pull request #896 from ckeditor/t/887
Fix: Renderer should not change the native selection if the one it's about to render is visually similar to the current one. Closes #887. Closes #880.
2 parents 8b859fb + b7f8491 commit d8ee5fa

File tree

8 files changed

+417
-0
lines changed

8 files changed

+417
-0
lines changed

src/view/renderer.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99

1010
import ViewText from './text';
1111
import ViewPosition from './position';
12+
import Selection from './selection';
1213
import { INLINE_FILLER, INLINE_FILLER_LENGTH, startsWithFiller, isInlineFiller, isBlockFiller } from './filler';
1314

1415
import mix from '@ckeditor/ckeditor5-utils/src/mix';
1516
import diff from '@ckeditor/ckeditor5-utils/src/diff';
1617
import insertAt from '@ckeditor/ckeditor5-utils/src/dom/insertat';
1718
import remove from '@ckeditor/ckeditor5-utils/src/dom/remove';
19+
import log from '@ckeditor/ckeditor5-utils/src/log';
1820
import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
1921
import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
2022

@@ -580,6 +582,17 @@ export default class Renderer {
580582
return;
581583
}
582584

585+
if ( oldViewSelection && areSimilarSelections( oldViewSelection, this.selection ) ) {
586+
const data = {
587+
oldSelection: oldViewSelection,
588+
currentSelection: this.selection
589+
};
590+
591+
log.warn( 'renderer-skipped-selection-rendering: The selection was not rendered due to its similarity to the current one.', data );
592+
593+
return;
594+
}
595+
583596
// Multi-range selection is not available in most browsers, and, at least in Chrome, trying to
584597
// set such selection, that is not continuous, throws an error. Because of that, we will just use anchor
585598
// and focus of view selection.
@@ -642,3 +655,35 @@ export default class Renderer {
642655
}
643656

644657
mix( Renderer, ObservableMixin );
658+
659+
// Checks if two given selections are similar. Selections are considered similar if they are non-collapsed
660+
// and their trimmed (see {@link #_trimSelection}) representations are equal.
661+
//
662+
// @private
663+
// @param {module:engine/view/selection~Selection} selection1
664+
// @param {module:engine/view/selection~Selection} selection2
665+
// @returns {Boolean}
666+
function areSimilarSelections( selection1, selection2 ) {
667+
return !selection1.isCollapsed && trimSelection( selection1 ).isEqual( trimSelection( selection2 ) );
668+
}
669+
670+
// Creates a copy of a given selection with all of its ranges
671+
// trimmed (see {@link module:engine/view/range~Range#getTrimmed getTrimmed}).
672+
//
673+
// @private
674+
// @param {module:engine/view/selection~Selection} selection
675+
// @returns {module:engine/view/selection~Selection} Selection copy with all ranges trimmed.
676+
function trimSelection( selection ) {
677+
const newSelection = Selection.createFromSelection( selection );
678+
const ranges = newSelection.getRanges();
679+
680+
let trimmedRanges = [];
681+
682+
for ( let range of ranges ) {
683+
trimmedRanges.push( range.getTrimmed() );
684+
}
685+
686+
newSelection.setRanges( trimmedRanges, newSelection.isBackward );
687+
688+
return newSelection;
689+
}

tests/manual/tickets/880/1.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div id="editor">
2+
<p>This is an <strong>editor</strong> instance.</p>
3+
</div>

tests/manual/tickets/880/1.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3+
* For licensing, see LICENSE.md.
4+
*/
5+
6+
/* globals console, window, document */
7+
8+
import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classic';
9+
import EssentialsPreset from '@ckeditor/ckeditor5-presets/src/essentials';
10+
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
11+
import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
12+
13+
ClassicEditor.create( document.querySelector( '#editor' ), {
14+
plugins: [ EssentialsPreset, Paragraph, Bold ],
15+
toolbar: [ 'undo', 'redo' ]
16+
} )
17+
.then( editor => {
18+
window.editor = editor;
19+
20+
editor.editing.view.on( 'selectionChange', () => {
21+
editor.document.enqueueChanges( () => {} );
22+
console.log( 'selectionChange', ( new Date() ).getTime() );
23+
} );
24+
} )
25+
.catch( err => {
26+
console.error( err.stack );
27+
} );

tests/manual/tickets/880/1.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
## Renderer - infinite `selectionChange` event
2+
3+
Place the selection like this:
4+
5+
```
6+
This is {an <strong>editor}</strong> instance.
7+
```
8+
9+
(it must end at the end of the inline style)
10+
11+
**Expected**:
12+
13+
* Every time selection is changed, console log with `selectionChange` is printed once.
14+
* While creating selection from **2.**, there might be `renderer-selection-similar` warning visible in the console.

tests/manual/tickets/887/1.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div id="editor">
2+
<p>This is an <strong>editor</strong> instance.</p>
3+
</div>

tests/manual/tickets/887/1.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3+
* For licensing, see LICENSE.md.
4+
*/
5+
6+
/* globals console, window, document */
7+
8+
import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classic';
9+
import EssentialsPreset from '@ckeditor/ckeditor5-presets/src/essentials';
10+
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
11+
import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
12+
13+
ClassicEditor.create( document.querySelector( '#editor' ), {
14+
plugins: [ EssentialsPreset, Paragraph, Bold ],
15+
toolbar: [ 'undo', 'redo' ]
16+
} )
17+
.then( editor => {
18+
window.editor = editor;
19+
} )
20+
.catch( err => {
21+
console.error( err.stack );
22+
} );

tests/manual/tickets/887/1.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
## Renderer - MacOS accent balloon on inline element boundary
2+
3+
1. Place the selection like this:
4+
5+
`This is an <strong>editor{}</strong> instance.`
6+
2. Open MacOS accent balloon (e.g. long `a` press).
7+
3. Navigate through the balloon panel using arrow keys.
8+
9+
**Expected**: It is possible to navigate with arrow keys inside the MacOS balloon panel. While navigating, there
10+
might be `renderer-selection-similar` warning visible in the console.

0 commit comments

Comments
 (0)