Skip to content

Commit

Permalink
Merge pull request #8484 from ckeditor/cf/3644
Browse files Browse the repository at this point in the history
Other (engine): The `DocumentSelection#markers` collection will now be updated only for observed markers groups. See `DocumentSelection#observeMarkers()`.

BREAKING CHANGE (engine): The `DocumentSelection#markers` collection will not include all markers by default. Use `DocumentSelection#observeMarkers()` to register that the given marker should be put in the `#markers` collection when the document selection is placed inside it.
  • Loading branch information
scofalik authored Nov 19, 2020
2 parents 0c9a2e1 + ae64861 commit 814b363
Show file tree
Hide file tree
Showing 2 changed files with 303 additions and 48 deletions.
86 changes: 83 additions & 3 deletions packages/ckeditor5-engine/src/model/documentselection.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,13 @@ export default class DocumentSelection {
}

/**
* A collection of selection markers.
* A collection of selection {@link module:engine/model/markercollection~Marker markers}.
* Marker is a selection marker when selection range is inside the marker range.
*
* **Note**: Only markers from {@link ~DocumentSelection#observeMarkersGroup observed markers groups} are collected.
*
* @readonly
* @type {module:utils/collection~Collection.<module:engine/model/markercollection~Marker>}
* @type {module:utils/collection~Collection}
*/
get markers() {
return this._selection.markers;
Expand Down Expand Up @@ -364,6 +366,17 @@ export default class DocumentSelection {
this._selection._updateAttributes( false );
}

/**
* Registers marker group prefix or marker name to be collected in {@link ~DocumentSelection#markers selection markers collection}.
*
* See also {@link module:engine/model/markercollection~MarkerCollection#getMarkersGroup `MarkerCollection#getMarkersGroup()`}.
*
* @param {String} prefixOrName Marker group prefix or marker name.
*/
observeMarkers( prefixOrName ) {
this._selection.observeMarkers( prefixOrName );
}

/**
* Checks whether this object is of the given type.
*
Expand Down Expand Up @@ -619,6 +632,11 @@ class LiveSelection extends Selection {
// @type {Set}
this._overriddenGravityRegister = new Set();

// Prefixes of marker names that should affect `LiveSelection#markers` collection.
// @private
// @type {Set}
this._observedMarkers = new Set();

// Ensure selection is correct after each operation.
this.listenTo( this._model, 'applyOperation', ( evt, args ) => {
const operation = args[ 0 ];
Expand Down Expand Up @@ -662,7 +680,10 @@ class LiveSelection extends Selection {
} );

// Update markers data stored by the selection after each marker change.
this.listenTo( this._model.markers, 'update', () => this._updateMarkers() );
// This handles only marker changes done through marker operations (not model tree changes).
this.listenTo( this._model.markers, 'update', ( evt, marker, oldRange, newRange ) => {
this._updateMarker( marker, newRange );
} );

// Ensure selection is up to date after each change block.
this.listenTo( this._document, 'change', ( evt, batch ) => {
Expand Down Expand Up @@ -798,6 +819,11 @@ class LiveSelection extends Selection {
}
}

observeMarkers( prefixOrName ) {
this._observedMarkers.add( prefixOrName );
this._updateMarkers();
}

_popRange() {
this._ranges.pop().detach();
}
Expand Down Expand Up @@ -846,10 +872,20 @@ class LiveSelection extends Selection {
}

_updateMarkers() {
if ( !this._observedMarkers.size ) {
return;
}

const markers = [];
let changed = false;

for ( const marker of this._model.markers ) {
const markerGroup = marker.name.split( ':', 1 )[ 0 ];

if ( !this._observedMarkers.has( markerGroup ) ) {
continue;
}

const markerRange = marker.getRange();

for ( const selectionRange of this.getRanges() ) {
Expand Down Expand Up @@ -882,6 +918,50 @@ class LiveSelection extends Selection {
}
}

_updateMarker( marker, markerRange ) {
const markerGroup = marker.name.split( ':', 1 )[ 0 ];

if ( !this._observedMarkers.has( markerGroup ) ) {
return;
}

let changed = false;

const oldMarkers = Array.from( this.markers );
const hasMarker = this.markers.has( marker );

if ( !markerRange ) {
if ( hasMarker ) {
this.markers.remove( marker );
changed = true;
}
} else {
let contained = false;

for ( const selectionRange of this.getRanges() ) {
if ( markerRange.containsRange( selectionRange, !selectionRange.isCollapsed ) ) {
contained = true;

break;
}
}

if ( contained && !hasMarker ) {
this.markers.add( marker );

changed = true;
} else if ( !contained && hasMarker ) {
this.markers.remove( marker );

changed = true;
}
}

if ( changed ) {
this.fire( 'change:marker', { oldMarkers, directChange: false } );
}
}

// Updates this selection attributes according to its ranges and the {@link module:engine/model/document~Document model document}.
//
// @protected
Expand Down
Loading

0 comments on commit 814b363

Please sign in to comment.