@@ -92,20 +92,7 @@ function selectionPostFixer( writer, model ) {
92
92
93
93
// If any of ranges were corrected update the selection.
94
94
if ( wasFixed ) {
95
- // The above algorithm might create ranges that intersects each other when selection contains more then one range.
96
- // This is case happens mostly on Firefox which creates multiple ranges for selected table.
97
- let fixedRanges = ranges ;
98
-
99
- // Fixing selection with many ranges usually breaks the selection in Firefox. As only Firefox supports multiple selection ranges
100
- // we simply create one continuous range from fixed selection ranges (even if they are not adjacent).
101
- if ( ranges . length > 1 ) {
102
- const selectionStart = ranges [ 0 ] . start ;
103
- const selectionEnd = ranges [ ranges . length - 1 ] . end ;
104
-
105
- fixedRanges = [ new Range ( selectionStart , selectionEnd ) ] ;
106
- }
107
-
108
- writer . setSelection ( fixedRanges , { backward : selection . isBackward } ) ;
95
+ writer . setSelection ( mergeIntersectingRanges ( ranges ) , { backward : selection . isBackward } ) ;
109
96
}
110
97
}
111
98
@@ -140,18 +127,17 @@ function tryFixingCollapsedRange( range, schema ) {
140
127
return null ;
141
128
}
142
129
130
+ if ( ! nearestSelectionRange . isCollapsed ) {
131
+ return nearestSelectionRange ;
132
+ }
133
+
143
134
const fixedPosition = nearestSelectionRange . start ;
144
135
145
136
// Fixed position is the same as original - no need to return corrected range.
146
137
if ( originalPosition . isEqual ( fixedPosition ) ) {
147
138
return null ;
148
139
}
149
140
150
- // Check single node selection (happens in tables).
151
- if ( fixedPosition . nodeAfter && schema . isLimit ( fixedPosition . nodeAfter ) ) {
152
- return new Range ( fixedPosition , Position . _createAfter ( fixedPosition . nodeAfter ) ) ;
153
- }
154
-
155
141
return new Range ( fixedPosition ) ;
156
142
}
157
143
@@ -263,6 +249,35 @@ function checkSelectionOnNonLimitElements( start, end, schema ) {
263
249
return startIsOnBlock || endIsOnBlock ;
264
250
}
265
251
252
+ // Returns a minimal non-intersecting array of ranges.
253
+ //
254
+ // @param {Array.<module:engine/model/range~Range> } ranges
255
+ // @returns {Array.<module:engine/model/range~Range> }
256
+ function mergeIntersectingRanges ( ranges ) {
257
+ const nonIntersectingRanges = [ ] ;
258
+
259
+ // First range will always be fine.
260
+ nonIntersectingRanges . push ( ranges . shift ( ) ) ;
261
+
262
+ for ( const range of ranges ) {
263
+ const previousRange = nonIntersectingRanges . pop ( ) ;
264
+
265
+ if ( range . isIntersecting ( previousRange ) ) {
266
+ // Get the sum of two ranges.
267
+ const start = previousRange . start . isAfter ( range . start ) ? range . start : previousRange . start ;
268
+ const end = previousRange . end . isAfter ( range . end ) ? previousRange . end : range . end ;
269
+
270
+ const merged = new Range ( start , end ) ;
271
+ nonIntersectingRanges . push ( merged ) ;
272
+ } else {
273
+ nonIntersectingRanges . push ( previousRange ) ;
274
+ nonIntersectingRanges . push ( range ) ;
275
+ }
276
+ }
277
+
278
+ return nonIntersectingRanges ;
279
+ }
280
+
266
281
// Checks if node exists and if it's an object.
267
282
//
268
283
// @param {module:engine/model/node~Node } node
@@ -271,4 +286,3 @@ function checkSelectionOnNonLimitElements( start, end, schema ) {
271
286
function isInObject ( node , schema ) {
272
287
return node && schema . isObject ( node ) ;
273
288
}
274
-
0 commit comments