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

Commit bfe23c9

Browse files
author
Piotr Jasiun
authored
Merge pull request #1268 from ckeditor/t/1086
Other: Provided one API for two types of markers, improved docs. Closes #1086. BREAKING CHANGE: Writer should be now used to set or remove markers, instead of MarkerCollection.
2 parents c2d4cec + c182c17 commit bfe23c9

16 files changed

+522
-272
lines changed

src/model/document.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ export default class Document {
161161
// Buffer marker changes.
162162
// This is not covered in buffering operations because markers may change outside of them (when they
163163
// are modified using `model.markers` collection, not through `MarkerOperation`).
164-
this.listenTo( model.markers, 'add', ( evt, marker ) => {
164+
this.listenTo( model.markers, 'set', ( evt, marker ) => {
165165
// TODO: Should filter out changes of markers that are not in document.
166166
// Whenever a new marker is added, buffer that change.
167167
this.differ.bufferMarkerChange( marker.name, null, marker.getRange() );

src/model/markercollection.js

Lines changed: 81 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,19 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
1515
import mix from '@ckeditor/ckeditor5-utils/src/mix';
1616

1717
/**
18-
* Creates, stores and manages {@link ~Marker markers}.
18+
* The collection of all {@link module:engine/model/markercollection~Marker markers} attached to the document.
19+
* It lets you {@link module:engine/model/markercollection~MarkerCollection#get get} markers or track them using
20+
* {@link module:engine/model/markercollection~MarkerCollection#event:set} and
21+
* {@link module:engine/model/markercollection~MarkerCollection#event:remove} events.
1922
*
20-
* Markers are created by {@link ~MarkerCollection#set setting} a name for a {@link module:engine/model/liverange~LiveRange live range}
21-
* in `MarkerCollection`. Name is used to group and identify markers. Names have to be unique, but markers can be grouped by
22-
* using common prefixes, separated with `:`, for example: `user:john` or `search:3`.
23+
* To create, change or remove makers use {@link module:engine/model/writer~Writer model writers'} methods:
24+
* {@link module:engine/model/writer~Writer#setMarker} or {@link module:engine/model/writer~Writer#removeMarker}. Since
25+
* the writer is the only proper way to change the data model it is not possible to change markers directly using this
26+
* collection. All markers created by the writer will be automatically added to this collection.
2327
*
24-
* Since markers are based on {@link module:engine/model/liverange~LiveRange live ranges}, for efficiency reasons, it's
25-
* best to create and keep at least markers as possible.
28+
* By default there is one marker collection available as {@link module:engine/model/model~Model#markers model property}.
29+
*
30+
* @see module:engine/model/markercollection~Marker
2631
*/
2732
export default class MarkerCollection {
2833
/**
@@ -78,42 +83,45 @@ export default class MarkerCollection {
7883
* set is different, the marker in collection is removed and then new marker is added. If the range was same, nothing
7984
* happens and `false` is returned.
8085
*
81-
* @fires module:engine/model/markercollection~MarkerCollection#event:add
86+
* @protected
87+
* @fires module:engine/model/markercollection~MarkerCollection#event:set
8288
* @fires module:engine/model/markercollection~MarkerCollection#event:remove
83-
* @param {String|module:engine/model/markercollection~Marker} markerOrName Name of marker to add or Marker instance to update.
89+
* @param {String|module:engine/model/markercollection~Marker} markerOrName Name of marker to set or marker instance to update.
8490
* @param {module:engine/model/range~Range} range Marker range.
91+
* @param {Boolean} managedUsingOperations Specifies whether the marker is managed using operations.
8592
* @returns {module:engine/model/markercollection~Marker} `Marker` instance added to the collection.
8693
*/
87-
set( markerOrName, range ) {
94+
_set( markerOrName, range, managedUsingOperations ) {
8895
const markerName = markerOrName instanceof Marker ? markerOrName.name : markerOrName;
8996
const oldMarker = this._markers.get( markerName );
9097

9198
if ( oldMarker ) {
9299
const oldRange = oldMarker.getRange();
93100

94-
if ( oldRange.isEqual( range ) ) {
101+
if ( oldRange.isEqual( range ) && managedUsingOperations === oldMarker.managedUsingOperations ) {
95102
return oldMarker;
96103
}
97104

98-
this.remove( markerName );
105+
this._remove( markerName );
99106
}
100107

101108
const liveRange = LiveRange.createFromRange( range );
102-
const marker = new Marker( markerName, liveRange );
109+
const marker = new Marker( markerName, liveRange, managedUsingOperations );
103110

104111
this._markers.set( markerName, marker );
105-
this.fire( 'add:' + markerName, marker );
112+
this.fire( 'set:' + markerName, marker );
106113

107114
return marker;
108115
}
109116

110117
/**
111118
* Removes given {@link ~Marker marker} or a marker with given name from the `MarkerCollection`.
112119
*
120+
* @protected
113121
* @param {String} markerOrName Marker or name of a marker to remove.
114122
* @returns {Boolean} `true` if marker was found and removed, `false` otherwise.
115123
*/
116-
remove( markerOrName ) {
124+
_remove( markerOrName ) {
117125
const markerName = markerOrName instanceof Marker ? markerOrName.name : markerOrName;
118126
const oldMarker = this._markers.get( markerName );
119127

@@ -190,10 +198,10 @@ export default class MarkerCollection {
190198
}
191199

192200
/**
193-
* Fired whenever marker is added to `MarkerCollection`.
201+
* Fired whenever marker is added or updated in `MarkerCollection`.
194202
*
195-
* @event add
196-
* @param {module:engine/model/markercollection~Marker} The added marker.
203+
* @event set
204+
* @param {module:engine/model/markercollection~Marker} The set marker.
197205
*/
198206

199207
/**
@@ -209,30 +217,64 @@ mix( MarkerCollection, EmitterMixin );
209217
/**
210218
* `Marker` is a continuous parts of model (like a range), is named and represent some kind of information about marked
211219
* part of model document. In contrary to {@link module:engine/model/node~Node nodes}, which are building blocks of
212-
* model document tree, markers are not stored directly in document tree. Still, they are document data, by giving
220+
* model document tree, markers are not stored directly in document tree but in
221+
* {@link module:engine/model/model~Model#markers model markers' collection}. Still, they are document data, by giving
213222
* additional meaning to the part of a model document between marker start and marker end.
214223
*
215224
* In this sense, markers are similar to adding and converting attributes on nodes. The difference is that attribute is
216225
* connected with a given node (e.g. a character is bold no matter if it gets moved or content around it changes).
217-
* Markers on the other hand are continuous ranges and are characterised by their start and end position. This means that
226+
* Markers on the other hand are continuous ranges and are characterized by their start and end position. This means that
218227
* any character in the marker is marked by the marker. For example, if a character is moved outside of marker it stops being
219228
* "special" and the marker is shrunk. Similarly, when a character is moved into the marker from other place in document
220229
* model, it starts being "special" and the marker is enlarged.
221230
*
222-
* Since markers are based on {@link module:engine/model/liverange~LiveRange live ranges}, for efficiency reasons, it's
223-
* best to create and keep at least markers as possible.
231+
* Another upside of markers is that finding marked part of document is fast and easy. Using attributes to mark some nodes
232+
* and then trying to find that part of document would require traversing whole document tree. Marker gives instant access
233+
* to the range which it is marking at the moment.
234+
*
235+
* Markers are built from a name and a range.
236+
*
237+
* Range of the marker is updated automatically when document changes, using
238+
* {@link module:engine/model/liverange~LiveRange live range} mechanism.
239+
*
240+
* Name is used to group and identify markers. Names have to be unique, but markers can be grouped by
241+
* using common prefixes, separated with `:`, for example: `user:john` or `search:3`. That's useful in term of creating
242+
* namespaces for custom elements (e.g. comments, highlights). You can use this prefixes in
243+
* {@link module:engine/model/markercollection~MarkerCollection#event:set} listeners to listen on changes in a group of markers.
244+
* For instance: `model.markers.on( 'set:user', callback );` will be called whenever any `user:*` markers changes.
245+
*
246+
* There are two types of markers.
247+
*
248+
* 1. Markers managed directly, without using operations. They are added directly by {@link module:engine/model/writer~Writer}
249+
* to the {@link module:engine/model/markercollection~MarkerCollection} without any additional mechanism. They can be used
250+
* as bookmarks or visual markers. They are great for showing results of the find, or select link when the focus is in the input.
251+
*
252+
* 1. Markers managed using operations. These markers are also stored in {@link module:engine/model/markercollection~MarkerCollection}
253+
* but changes in these markers is managed the same way all other changes in the model structure - using operations.
254+
* Therefore, they are handled in the undo stack and synchronized between clients if the collaboration plugin is enabled.
255+
* This type of markers is useful for solutions like spell checking or comments.
256+
*
257+
* Both type of them should be added / updated by {@link module:engine/model/writer~Writer#setMarker}
258+
* and removed by {@link module:engine/model/writer~Writer#removeMarker} methods.
259+
*
260+
* model.change( ( writer ) => {
261+
* const marker = writer.setMarker( name, range, { usingOperation: true } );
262+
*
263+
* // ...
264+
*
265+
* writer.removeMarker( marker );
266+
* } );
267+
*
268+
* See {@link module:engine/model/writer~Writer} to find more examples.
269+
*
270+
* Since markers need to track change in the document, for efficiency reasons, it is best to create and keep as little
271+
* markers as possible and remove them as soon as they are not needed anymore.
224272
*
225273
* Markers can be converted to view by adding appropriate converters for
226274
* {@link module:engine/conversion/modelconversiondispatcher~ModelConversionDispatcher#event:addMarker} and
227275
* {@link module:engine/conversion/modelconversiondispatcher~ModelConversionDispatcher#event:removeMarker}
228276
* events, or by building converters for {@link module:engine/conversion/modelconversiondispatcher~ModelConversionDispatcher}
229277
* using {@link module:engine/conversion/buildmodelconverter~buildModelConverter model converter builder}.
230-
*
231-
* Another upside of markers is that finding marked part of document is fast and easy. Using attributes to mark some nodes
232-
* and then trying to find that part of document would require traversing whole document tree. Marker gives instant access
233-
* to the range which it is marking at the moment.
234-
*
235-
* `Marker` instances are created and destroyed only by {@link ~MarkerCollection MarkerCollection}.
236278
*/
237279
class Marker {
238280
/**
@@ -241,20 +283,29 @@ class Marker {
241283
* @param {String} name Marker name.
242284
* @param {module:engine/model/liverange~LiveRange} liveRange Range marked by the marker.
243285
*/
244-
constructor( name, liveRange ) {
286+
constructor( name, liveRange, managedUsingOperations ) {
245287
/**
246288
* Marker's name.
247289
*
248290
* @readonly
249-
* @member {String} #name
291+
* @type {String}
250292
*/
251293
this.name = name;
252294

295+
/**
296+
* Flag indicates if the marker is managed using operations or not. See {@link ~Marker marker class description}
297+
* to learn more about marker types. See {@link module:engine/model/writer~Writer#setMarker}.
298+
*
299+
* @readonly
300+
* @type {Boolean}
301+
*/
302+
this.managedUsingOperations = managedUsingOperations;
303+
253304
/**
254305
* Range marked by the marker.
255306
*
256307
* @protected
257-
* @member {module:engine/model/liverange~LiveRange} #_liveRange
308+
* @type {module:engine/model/liverange~LiveRange}
258309
*/
259310
this._liveRange = liveRange;
260311

src/model/operation/markeroperation.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ export default class MarkerOperation extends Operation {
8787
* @inheritDoc
8888
*/
8989
_execute() {
90-
const type = this.newRange ? 'set' : 'remove';
90+
const type = this.newRange ? '_set' : '_remove';
9191

92-
this._markers[ type ]( this.name, this.newRange );
92+
this._markers[ type ]( this.name, this.newRange, true );
9393
}
9494

9595
/**

0 commit comments

Comments
 (0)