@@ -15,14 +15,19 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
1515import 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 */
2732export 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 */
237279class 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
0 commit comments