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

Commit 0e2f02e

Browse files
authored
Merge pull request #1826 from ckeditor/i/6091
Other: `StylesProcessor` rules will not be stored in a singleton, which made them shared between editor instances. In order to allow binding a styles processor instance to a specific view document, we had to replace a dynamic `#document` property in view nodes with a static one, set upon node creation. Closes ckeditor/ckeditor5#6091. MAJOR BREAKING CHANGES: `EditingController` requires an instance of StylesProcessor in its constructor. MAJOR BREAKING CHANGES: `DataController` requires an instance of StylesProcessor in its constructor. MAJOR BREAKING CHANGES: `DomConverter`, `HtmlDataProcessor` and `XmlDataProcessor` require an instance of the view document in their constructors. MAJOR BREAKING CHANGES: The `View` class requires an instance of `StylesProcessor` as its first argument. MAJOR BREAKING CHANGES: The `createViewElementFromHighlightDescriptor()` function that is exported by `src/conversion/downcasthelpers.js` file requires an instance of the view document as its first argument. MAJOR BREAKING CHANGES: Method `view.Document#addStyleProcessorRules()` has been moved to DataController class. MINOR BREAKING CHANGES: `DataController` does not accept the data processor instance any more. MAJOR BREAKING CHANGES: The `#document` getter was removed from model nodes. Only the root element holds the reference to the model document. For attached nodes, use `node.root.document` to access it.
2 parents 5fdb765 + fb8e77a commit 0e2f02e

File tree

122 files changed

+1873
-1661
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+1873
-1661
lines changed

src/controller/datacontroller.js

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,9 @@ export default class DataController {
4747
* Creates a data controller instance.
4848
*
4949
* @param {module:engine/model/model~Model} model Data model.
50-
* @param {module:engine/dataprocessor/dataprocessor~DataProcessor} [dataProcessor] Data processor that should be used
51-
* by the controller.
50+
* @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance.
5251
*/
53-
constructor( model, dataProcessor ) {
52+
constructor( model, stylesProcessor ) {
5453
/**
5554
* Data model.
5655
*
@@ -60,12 +59,19 @@ export default class DataController {
6059
this.model = model;
6160

6261
/**
63-
* Data processor used during the conversion.
62+
* Styles processor used during the conversion.
6463
*
6564
* @readonly
66-
* @member {module:engine/dataprocessor/dataprocessor~DataProcessor}
65+
* @member {module:engine/view/stylesmap~StylesProcessor}
6766
*/
68-
this.processor = dataProcessor;
67+
this.stylesProcessor = stylesProcessor;
68+
69+
/**
70+
* Data processor used during the conversion.
71+
*
72+
* @member {module:engine/dataprocessor/dataprocessor~DataProcessor} #processor
73+
*/
74+
this.processor;
6975

7076
/**
7177
* Mapper used for the conversion. It has no permanent bindings, because they are created when getting data and
@@ -187,12 +193,13 @@ export default class DataController {
187193

188194
// First, convert elements.
189195
const modelRange = ModelRange._createIn( modelElementOrFragment );
196+
const viewDocument = new ViewDocument( this.stylesProcessor );
190197

191-
const viewDocumentFragment = new ViewDocumentFragment();
198+
const viewDocumentFragment = new ViewDocumentFragment( viewDocument );
192199

193200
// Create separate ViewDowncastWriter just for data conversion purposes.
194201
// We have no view controller and rendering do DOM in DataController so view.change() block is not used here.
195-
const viewWriter = new ViewDowncastWriter( new ViewDocument() );
202+
const viewWriter = new ViewDowncastWriter( viewDocument );
196203
this.mapper.bindElements( modelElementOrFragment, viewDocumentFragment );
197204

198205
this.downcastDispatcher.convertInsert( modelRange, viewWriter );
@@ -371,6 +378,22 @@ export default class DataController {
371378
} );
372379
}
373380

381+
/**
382+
* Adds a style processor normalization rules.
383+
*
384+
* You can implement your own rules as well as use one of the available processor rules:
385+
*
386+
* * background: {@link module:engine/view/styles/background~addBackgroundRules}
387+
* * border: {@link module:engine/view/styles/border~addBorderRules}
388+
* * margin: {@link module:engine/view/styles/margin~addMarginRules}
389+
* * padding: {@link module:engine/view/styles/padding~addPaddingRules}
390+
*
391+
* @param {Function} callback
392+
*/
393+
addStyleProcessorRules( callback ) {
394+
callback( this.stylesProcessor );
395+
}
396+
374397
/**
375398
* Removes all event listeners set by the DataController.
376399
*/

src/controller/editingcontroller.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ export default class EditingController {
3131
* Creates an editing controller instance.
3232
*
3333
* @param {module:engine/model/model~Model} model Editing model.
34+
* @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance.
3435
*/
35-
constructor( model ) {
36+
constructor( model, stylesProcessor ) {
3637
/**
3738
* Editor model.
3839
*
@@ -47,7 +48,7 @@ export default class EditingController {
4748
* @readonly
4849
* @member {module:engine/view/view~View}
4950
*/
50-
this.view = new View();
51+
this.view = new View( stylesProcessor );
5152

5253
/**
5354
* Mapper which describes the model-view binding.
@@ -115,10 +116,9 @@ export default class EditingController {
115116
return null;
116117
}
117118

118-
const viewRoot = new RootEditableElement( root.name );
119+
const viewRoot = new RootEditableElement( this.view.document, root.name );
119120

120121
viewRoot.rootName = root.rootName;
121-
viewRoot._document = this.view.document;
122122
this.mapper.bindElements( root, viewRoot );
123123

124124
return viewRoot;

src/conversion/downcasthelpers.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -416,11 +416,12 @@ export function remove() {
416416
* provided by the {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor} object. If a priority
417417
* is not provided in the descriptor, the default priority will be used.
418418
*
419+
* @param {module:engine/view/downcastwriter~DowncastWriter} writer
419420
* @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor
420421
* @returns {module:engine/view/attributeelement~AttributeElement}
421422
*/
422-
export function createViewElementFromHighlightDescriptor( descriptor ) {
423-
const viewElement = new ViewAttributeElement( 'span', descriptor.attributes );
423+
export function createViewElementFromHighlightDescriptor( writer, descriptor ) {
424+
const viewElement = writer.createAttributeElement( 'span', descriptor.attributes );
424425

425426
if ( descriptor.classes ) {
426427
viewElement._addClass( descriptor.classes );
@@ -543,7 +544,7 @@ export function clearAttributes() {
543544
// Not collapsed selection should not have artifacts.
544545
if ( range.isCollapsed ) {
545546
// Position might be in the node removed by the view writer.
546-
if ( range.end.parent.document ) {
547+
if ( range.end.parent.isAttached() ) {
547548
conversionApi.writer.mergeAttributes( range.start );
548549
}
549550
}
@@ -919,8 +920,8 @@ function highlightText( highlightDescriptor ) {
919920
return;
920921
}
921922

922-
const viewElement = createViewElementFromHighlightDescriptor( descriptor );
923923
const viewWriter = conversionApi.writer;
924+
const viewElement = createViewElementFromHighlightDescriptor( viewWriter, descriptor );
924925
const viewSelection = viewWriter.document.selection;
925926

926927
if ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) {
@@ -1034,7 +1035,7 @@ function removeHighlight( highlightDescriptor ) {
10341035
}
10351036

10361037
// View element that will be used to unwrap `AttributeElement`s.
1037-
const viewHighlightElement = createViewElementFromHighlightDescriptor( descriptor );
1038+
const viewHighlightElement = createViewElementFromHighlightDescriptor( conversionApi.writer, descriptor );
10381039

10391040
// Get all elements bound with given marker name.
10401041
const elements = conversionApi.mapper.markerNameToElements( data.markerName );

src/conversion/viewconsumable.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
import { isArray } from 'lodash-es';
1111
import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
12-
import StylesMap from '../view/stylesmap';
1312

1413
/**
1514
* Class used for handling consumption of view {@link module:engine/view/element~Element elements},
@@ -89,7 +88,7 @@ export default class ViewConsumable {
8988

9089
// For elements create new ViewElementConsumables or update already existing one.
9190
if ( !this._consumables.has( element ) ) {
92-
elementConsumables = new ViewElementConsumables();
91+
elementConsumables = new ViewElementConsumables( element );
9392
this._consumables.set( element, elementConsumables );
9493
} else {
9594
elementConsumables = this._consumables.get( element );
@@ -239,6 +238,7 @@ export default class ViewConsumable {
239238
*/
240239
static consumablesFromElement( element ) {
241240
const consumables = {
241+
element,
242242
name: true,
243243
attributes: [],
244244
classes: [],
@@ -284,7 +284,7 @@ export default class ViewConsumable {
284284
*/
285285
static createFrom( from, instance ) {
286286
if ( !instance ) {
287-
instance = new ViewConsumable();
287+
instance = new ViewConsumable( from );
288288
}
289289

290290
if ( from.is( 'text' ) ) {
@@ -319,8 +319,17 @@ export default class ViewConsumable {
319319
class ViewElementConsumables {
320320
/**
321321
* Creates ViewElementConsumables instance.
322+
*
323+
* @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} from View node or document fragment
324+
* from which `ViewElementConsumables` is being created.
322325
*/
323-
constructor() {
326+
constructor( from ) {
327+
/**
328+
* @readonly
329+
* @member {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}
330+
*/
331+
this.element = from;
332+
324333
/**
325334
* Flag indicating if name of the element can be consumed.
326335
*
@@ -510,7 +519,7 @@ class ViewElementConsumables {
510519
consumables.set( name, true );
511520

512521
if ( type === 'styles' ) {
513-
for ( const alsoName of StylesMap.getRelatedStyles( name ) ) {
522+
for ( const alsoName of this.element.document.stylesProcessor.getRelatedStyles( name ) ) {
514523
consumables.set( alsoName, true );
515524
}
516525
}
@@ -577,7 +586,7 @@ class ViewElementConsumables {
577586
consumables.set( name, false );
578587

579588
if ( type == 'styles' ) {
580-
for ( const toConsume of StylesMap.getRelatedStyles( name ) ) {
589+
for ( const toConsume of this.element.document.stylesProcessor.getRelatedStyles( name ) ) {
581590
consumables.set( toConsume, false );
582591
}
583592
}

src/dataprocessor/htmldataprocessor.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ import DomConverter from '../view/domconverter';
2121
export default class HtmlDataProcessor {
2222
/**
2323
* Creates a new instance of the HTML data processor class.
24+
*
25+
* @param {module:engine/view/document~Document} document The view document instance.
2426
*/
25-
constructor() {
27+
constructor( document ) {
2628
/**
2729
* A DOM parser instance used to parse an HTML string to an HTML document.
2830
*
@@ -37,7 +39,7 @@ export default class HtmlDataProcessor {
3739
* @private
3840
* @member {module:engine/view/domconverter~DomConverter}
3941
*/
40-
this._domConverter = new DomConverter( { blockFillerMode: 'nbsp' } );
42+
this._domConverter = new DomConverter( document, { blockFillerMode: 'nbsp' } );
4143

4244
/**
4345
* A basic HTML writer instance used to convert DOM elements to an HTML string.

src/dataprocessor/xmldataprocessor.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ export default class XmlDataProcessor {
2424
/**
2525
* Creates a new instance of the XML data processor class.
2626
*
27+
* @param {module:engine/view/document~Document} document The view document instance.
2728
* @param {Object} options Configuration options.
2829
* @param {Array<String>} [options.namespaces=[]] A list of namespaces allowed to use in the XML input.
2930
*/
30-
constructor( options = {} ) {
31+
constructor( document, options = {} ) {
3132
/**
3233
* A list of namespaces allowed to use in the XML input.
3334
*
@@ -53,7 +54,7 @@ export default class XmlDataProcessor {
5354
* @private
5455
* @member {module:engine/view/domconverter~DomConverter}
5556
*/
56-
this._domConverter = new DomConverter( { blockFillerMode: 'nbsp' } );
57+
this._domConverter = new DomConverter( document, { blockFillerMode: 'nbsp' } );
5758

5859
/**
5960
* A basic HTML writer instance used to convert DOM elements to an XML string.

src/dev-utils/model.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939

4040
import { isPlainObject } from 'lodash-es';
4141
import toMap from '@ckeditor/ckeditor5-utils/src/tomap';
42+
import { StylesProcessor } from '../view/stylesmap';
4243

4344
/**
4445
* Writes the content of a model {@link module:engine/model/document~Document document} to an HTML-like string.
@@ -210,12 +211,12 @@ export function stringify( node, selectionOrPositionOrRange = null, markers = nu
210211

211212
// Set up conversion.
212213
// Create a temporary view controller.
213-
const view = new View();
214+
const stylesProcessor = new StylesProcessor();
215+
const view = new View( stylesProcessor );
214216
const viewDocument = view.document;
215-
const viewRoot = new ViewRootEditableElement( 'div' );
217+
const viewRoot = new ViewRootEditableElement( viewDocument, 'div' );
216218

217219
// Create a temporary root element in view document.
218-
viewRoot._document = view.document;
219220
viewRoot.rootName = 'main';
220221
viewDocument.roots.add( viewRoot );
221222

@@ -242,7 +243,7 @@ export function stringify( node, selectionOrPositionOrRange = null, markers = nu
242243
// Stringify object types values for properly display as an output string.
243244
const attributes = convertAttributes( modelItem.getAttributes(), stringifyAttributeValue );
244245

245-
return new ViewContainerElement( modelItem.name, attributes );
246+
return new ViewContainerElement( viewDocument, modelItem.name, attributes );
246247
} ) );
247248

248249
downcastDispatcher.on( 'selection', convertRangeSelection() );

src/dev-utils/view.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515

1616
import View from '../view/view';
17+
import ViewDocument from '../view/document';
1718
import ViewDocumentFragment from '../view/documentfragment';
1819
import XmlDataProcessor from '../dataprocessor/xmldataprocessor';
1920
import ViewElement from '../view/element';
@@ -24,6 +25,7 @@ import AttributeElement from '../view/attributeelement';
2425
import ContainerElement from '../view/containerelement';
2526
import EmptyElement from '../view/emptyelement';
2627
import UIElement from '../view/uielement';
28+
import { StylesProcessor } from '../view/stylesmap';
2729

2830
const ELEMENT_RANGE_START_TOKEN = '[';
2931
const ELEMENT_RANGE_END_TOKEN = ']';
@@ -321,16 +323,19 @@ export function stringify( node, selectionOrPositionOrRange = null, options = {}
321323
* this node will be used as the root for all parsed nodes.
322324
* @param {Boolean} [options.sameSelectionCharacters=false] When set to `false`, the selection inside the text should be marked using
323325
* `{` and `}` and the selection outside the ext using `[` and `]`. When set to `true`, both should be marked with `[` and `]` only.
326+
* @param {module:engine/view/stylesmap~StylesProcessor} [options.stylesProcessor] Styles processor.
324327
* @returns {module:engine/view/text~Text|module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|Object}
325328
* Returns the parsed view node or an object with two fields: `view` and `selection` when selection ranges were included in the data
326329
* to parse.
327330
*/
328331
export function parse( data, options = {} ) {
332+
const viewDocument = new ViewDocument( new StylesProcessor() );
333+
329334
options.order = options.order || [];
330335
const rangeParser = new RangeParser( {
331336
sameSelectionCharacters: options.sameSelectionCharacters
332337
} );
333-
const processor = new XmlDataProcessor( {
338+
const processor = new XmlDataProcessor( viewDocument, {
334339
namespaces: Object.keys( allowedTypes )
335340
} );
336341

@@ -927,7 +932,10 @@ class ViewStringify {
927932
function _convertViewElements( rootNode ) {
928933
if ( rootNode.is( 'element' ) || rootNode.is( 'documentFragment' ) ) {
929934
// Convert element or leave document fragment.
930-
const convertedElement = rootNode.is( 'documentFragment' ) ? new ViewDocumentFragment() : _convertElement( rootNode );
935+
936+
const convertedElement = rootNode.is( 'documentFragment' ) ?
937+
new ViewDocumentFragment( rootNode.document ) :
938+
_convertElement( rootNode.document, rootNode );
931939

932940
// Convert all child nodes.
933941
// Cache the nodes in array. Otherwise, we would skip some nodes because during iteration we move nodes
@@ -973,10 +981,10 @@ function _convertViewElements( rootNode ) {
973981
// module:engine/view/emptyelement~EmptyElement|module:engine/view/uielement~UIElement|
974982
// module:engine/view/containerelement~ContainerElement} A tree view
975983
// element converted according to its name.
976-
function _convertElement( viewElement ) {
984+
function _convertElement( viewDocument, viewElement ) {
977985
const info = _convertElementNameAndInfo( viewElement );
978986
const ElementConstructor = allowedTypes[ info.type ];
979-
const newElement = ElementConstructor ? new ElementConstructor( info.name ) : new ViewElement( info.name );
987+
const newElement = ElementConstructor ? new ElementConstructor( viewDocument, info.name ) : new ViewElement( viewDocument, info.name );
980988

981989
if ( newElement.is( 'attributeElement' ) ) {
982990
if ( info.priority !== null ) {

src/model/model.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ export default class Model {
334334
*
335335
* // You can create your own HtmlDataProcessor instance or use editor.data.processor
336336
* // if you have not overridden the default one (which is the HtmlDataProcessor instance).
337-
* const htmlDP = new HtmlDataProcessor();
337+
* const htmlDP = new HtmlDataProcessor( viewDocument );
338338
*
339339
* // Convert an HTML string to a view document fragment:
340340
* const viewFragment = htmlDP.toView( htmlString );

src/model/node.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -189,20 +189,12 @@ export default class Node {
189189
}
190190

191191
/**
192-
* {@link module:engine/model/document~Document Document} that owns this node or `null` if the node has no parent or is inside
193-
* a {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment}.
192+
* Returns true if the node is in a tree rooted in the document (is a descendant of one of its roots).
194193
*
195-
* @readonly
196-
* @type {module:engine/model/document~Document|null}
194+
* @returns {Boolean}
197195
*/
198-
get document() {
199-
// This is a top element of a sub-tree.
200-
if ( this.root == this ) {
201-
return null;
202-
}
203-
204-
// Root may be `DocumentFragment` which does not have document property.
205-
return this.root.document || null;
196+
isAttached() {
197+
return this.root.is( 'rootElement' );
206198
}
207199

208200
/**

0 commit comments

Comments
 (0)