diff --git a/src/controller/datacontroller.js b/src/controller/datacontroller.js index 963bd3c39..848444769 100644 --- a/src/controller/datacontroller.js +++ b/src/controller/datacontroller.js @@ -47,10 +47,9 @@ export default class DataController { * Creates a data controller instance. * * @param {module:engine/model/model~Model} model Data model. - * @param {module:engine/dataprocessor/dataprocessor~DataProcessor} [dataProcessor] Data processor that should be used - * by the controller. + * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance. */ - constructor( model, dataProcessor ) { + constructor( model, stylesProcessor ) { /** * Data model. * @@ -60,12 +59,19 @@ export default class DataController { this.model = model; /** - * Data processor used during the conversion. + * Styles processor used during the conversion. * * @readonly - * @member {module:engine/dataprocessor/dataprocessor~DataProcessor} + * @member {module:engine/view/stylesmap~StylesProcessor} */ - this.processor = dataProcessor; + this.stylesProcessor = stylesProcessor; + + /** + * Data processor used during the conversion. + * + * @member {module:engine/dataprocessor/dataprocessor~DataProcessor} #processor + */ + this.processor; /** * 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 { // First, convert elements. const modelRange = ModelRange._createIn( modelElementOrFragment ); + const viewDocument = new ViewDocument( this.stylesProcessor ); - const viewDocumentFragment = new ViewDocumentFragment(); + const viewDocumentFragment = new ViewDocumentFragment( viewDocument ); // Create separate ViewDowncastWriter just for data conversion purposes. // We have no view controller and rendering do DOM in DataController so view.change() block is not used here. - const viewWriter = new ViewDowncastWriter( new ViewDocument() ); + const viewWriter = new ViewDowncastWriter( viewDocument ); this.mapper.bindElements( modelElementOrFragment, viewDocumentFragment ); this.downcastDispatcher.convertInsert( modelRange, viewWriter ); @@ -371,6 +378,22 @@ export default class DataController { } ); } + /** + * Adds a style processor normalization rules. + * + * You can implement your own rules as well as use one of the available processor rules: + * + * * background: {@link module:engine/view/styles/background~addBackgroundRules} + * * border: {@link module:engine/view/styles/border~addBorderRules} + * * margin: {@link module:engine/view/styles/margin~addMarginRules} + * * padding: {@link module:engine/view/styles/padding~addPaddingRules} + * + * @param {Function} callback + */ + addStyleProcessorRules( callback ) { + callback( this.stylesProcessor ); + } + /** * Removes all event listeners set by the DataController. */ diff --git a/src/controller/editingcontroller.js b/src/controller/editingcontroller.js index 37c4d45c7..145ce7795 100644 --- a/src/controller/editingcontroller.js +++ b/src/controller/editingcontroller.js @@ -31,8 +31,9 @@ export default class EditingController { * Creates an editing controller instance. * * @param {module:engine/model/model~Model} model Editing model. + * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance. */ - constructor( model ) { + constructor( model, stylesProcessor ) { /** * Editor model. * @@ -47,7 +48,7 @@ export default class EditingController { * @readonly * @member {module:engine/view/view~View} */ - this.view = new View(); + this.view = new View( stylesProcessor ); /** * Mapper which describes the model-view binding. @@ -115,10 +116,9 @@ export default class EditingController { return null; } - const viewRoot = new RootEditableElement( root.name ); + const viewRoot = new RootEditableElement( this.view.document, root.name ); viewRoot.rootName = root.rootName; - viewRoot._document = this.view.document; this.mapper.bindElements( root, viewRoot ); return viewRoot; diff --git a/src/conversion/downcasthelpers.js b/src/conversion/downcasthelpers.js index 1f14f3e62..9ed599f93 100644 --- a/src/conversion/downcasthelpers.js +++ b/src/conversion/downcasthelpers.js @@ -416,11 +416,12 @@ export function remove() { * provided by the {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor} object. If a priority * is not provided in the descriptor, the default priority will be used. * + * @param {module:engine/view/downcastwriter~DowncastWriter} writer * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor * @returns {module:engine/view/attributeelement~AttributeElement} */ -export function createViewElementFromHighlightDescriptor( descriptor ) { - const viewElement = new ViewAttributeElement( 'span', descriptor.attributes ); +export function createViewElementFromHighlightDescriptor( writer, descriptor ) { + const viewElement = writer.createAttributeElement( 'span', descriptor.attributes ); if ( descriptor.classes ) { viewElement._addClass( descriptor.classes ); @@ -543,7 +544,7 @@ export function clearAttributes() { // Not collapsed selection should not have artifacts. if ( range.isCollapsed ) { // Position might be in the node removed by the view writer. - if ( range.end.parent.document ) { + if ( range.end.parent.isAttached() ) { conversionApi.writer.mergeAttributes( range.start ); } } @@ -919,8 +920,8 @@ function highlightText( highlightDescriptor ) { return; } - const viewElement = createViewElementFromHighlightDescriptor( descriptor ); const viewWriter = conversionApi.writer; + const viewElement = createViewElementFromHighlightDescriptor( viewWriter, descriptor ); const viewSelection = viewWriter.document.selection; if ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) { @@ -1034,7 +1035,7 @@ function removeHighlight( highlightDescriptor ) { } // View element that will be used to unwrap `AttributeElement`s. - const viewHighlightElement = createViewElementFromHighlightDescriptor( descriptor ); + const viewHighlightElement = createViewElementFromHighlightDescriptor( conversionApi.writer, descriptor ); // Get all elements bound with given marker name. const elements = conversionApi.mapper.markerNameToElements( data.markerName ); diff --git a/src/conversion/viewconsumable.js b/src/conversion/viewconsumable.js index 8b693e64b..3f7d45cb4 100644 --- a/src/conversion/viewconsumable.js +++ b/src/conversion/viewconsumable.js @@ -9,7 +9,6 @@ import { isArray } from 'lodash-es'; import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; -import StylesMap from '../view/stylesmap'; /** * Class used for handling consumption of view {@link module:engine/view/element~Element elements}, @@ -89,7 +88,7 @@ export default class ViewConsumable { // For elements create new ViewElementConsumables or update already existing one. if ( !this._consumables.has( element ) ) { - elementConsumables = new ViewElementConsumables(); + elementConsumables = new ViewElementConsumables( element ); this._consumables.set( element, elementConsumables ); } else { elementConsumables = this._consumables.get( element ); @@ -239,6 +238,7 @@ export default class ViewConsumable { */ static consumablesFromElement( element ) { const consumables = { + element, name: true, attributes: [], classes: [], @@ -284,7 +284,7 @@ export default class ViewConsumable { */ static createFrom( from, instance ) { if ( !instance ) { - instance = new ViewConsumable(); + instance = new ViewConsumable( from ); } if ( from.is( 'text' ) ) { @@ -319,8 +319,17 @@ export default class ViewConsumable { class ViewElementConsumables { /** * Creates ViewElementConsumables instance. + * + * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} from View node or document fragment + * from which `ViewElementConsumables` is being created. */ - constructor() { + constructor( from ) { + /** + * @readonly + * @member {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} + */ + this.element = from; + /** * Flag indicating if name of the element can be consumed. * @@ -510,7 +519,7 @@ class ViewElementConsumables { consumables.set( name, true ); if ( type === 'styles' ) { - for ( const alsoName of StylesMap.getRelatedStyles( name ) ) { + for ( const alsoName of this.element.document.stylesProcessor.getRelatedStyles( name ) ) { consumables.set( alsoName, true ); } } @@ -577,7 +586,7 @@ class ViewElementConsumables { consumables.set( name, false ); if ( type == 'styles' ) { - for ( const toConsume of StylesMap.getRelatedStyles( name ) ) { + for ( const toConsume of this.element.document.stylesProcessor.getRelatedStyles( name ) ) { consumables.set( toConsume, false ); } } diff --git a/src/dataprocessor/htmldataprocessor.js b/src/dataprocessor/htmldataprocessor.js index 72e008c27..1b8efa6de 100644 --- a/src/dataprocessor/htmldataprocessor.js +++ b/src/dataprocessor/htmldataprocessor.js @@ -21,8 +21,10 @@ import DomConverter from '../view/domconverter'; export default class HtmlDataProcessor { /** * Creates a new instance of the HTML data processor class. + * + * @param {module:engine/view/document~Document} document The view document instance. */ - constructor() { + constructor( document ) { /** * A DOM parser instance used to parse an HTML string to an HTML document. * @@ -37,7 +39,7 @@ export default class HtmlDataProcessor { * @private * @member {module:engine/view/domconverter~DomConverter} */ - this._domConverter = new DomConverter( { blockFillerMode: 'nbsp' } ); + this._domConverter = new DomConverter( document, { blockFillerMode: 'nbsp' } ); /** * A basic HTML writer instance used to convert DOM elements to an HTML string. diff --git a/src/dataprocessor/xmldataprocessor.js b/src/dataprocessor/xmldataprocessor.js index 50f797caa..8f0c03cd4 100644 --- a/src/dataprocessor/xmldataprocessor.js +++ b/src/dataprocessor/xmldataprocessor.js @@ -24,10 +24,11 @@ export default class XmlDataProcessor { /** * Creates a new instance of the XML data processor class. * + * @param {module:engine/view/document~Document} document The view document instance. * @param {Object} options Configuration options. * @param {Array} [options.namespaces=[]] A list of namespaces allowed to use in the XML input. */ - constructor( options = {} ) { + constructor( document, options = {} ) { /** * A list of namespaces allowed to use in the XML input. * @@ -53,7 +54,7 @@ export default class XmlDataProcessor { * @private * @member {module:engine/view/domconverter~DomConverter} */ - this._domConverter = new DomConverter( { blockFillerMode: 'nbsp' } ); + this._domConverter = new DomConverter( document, { blockFillerMode: 'nbsp' } ); /** * A basic HTML writer instance used to convert DOM elements to an XML string. diff --git a/src/dev-utils/model.js b/src/dev-utils/model.js index 35e9b1b97..2c3d2c9a2 100644 --- a/src/dev-utils/model.js +++ b/src/dev-utils/model.js @@ -39,6 +39,7 @@ import { import { isPlainObject } from 'lodash-es'; import toMap from '@ckeditor/ckeditor5-utils/src/tomap'; +import { StylesProcessor } from '../view/stylesmap'; /** * 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 // Set up conversion. // Create a temporary view controller. - const view = new View(); + const stylesProcessor = new StylesProcessor(); + const view = new View( stylesProcessor ); const viewDocument = view.document; - const viewRoot = new ViewRootEditableElement( 'div' ); + const viewRoot = new ViewRootEditableElement( viewDocument, 'div' ); // Create a temporary root element in view document. - viewRoot._document = view.document; viewRoot.rootName = 'main'; viewDocument.roots.add( viewRoot ); @@ -242,7 +243,7 @@ export function stringify( node, selectionOrPositionOrRange = null, markers = nu // Stringify object types values for properly display as an output string. const attributes = convertAttributes( modelItem.getAttributes(), stringifyAttributeValue ); - return new ViewContainerElement( modelItem.name, attributes ); + return new ViewContainerElement( viewDocument, modelItem.name, attributes ); } ) ); downcastDispatcher.on( 'selection', convertRangeSelection() ); diff --git a/src/dev-utils/view.js b/src/dev-utils/view.js index 89a6c40c6..38629c7a0 100644 --- a/src/dev-utils/view.js +++ b/src/dev-utils/view.js @@ -14,6 +14,7 @@ */ import View from '../view/view'; +import ViewDocument from '../view/document'; import ViewDocumentFragment from '../view/documentfragment'; import XmlDataProcessor from '../dataprocessor/xmldataprocessor'; import ViewElement from '../view/element'; @@ -24,6 +25,7 @@ import AttributeElement from '../view/attributeelement'; import ContainerElement from '../view/containerelement'; import EmptyElement from '../view/emptyelement'; import UIElement from '../view/uielement'; +import { StylesProcessor } from '../view/stylesmap'; const ELEMENT_RANGE_START_TOKEN = '['; const ELEMENT_RANGE_END_TOKEN = ']'; @@ -321,16 +323,19 @@ export function stringify( node, selectionOrPositionOrRange = null, options = {} * this node will be used as the root for all parsed nodes. * @param {Boolean} [options.sameSelectionCharacters=false] When set to `false`, the selection inside the text should be marked using * `{` and `}` and the selection outside the ext using `[` and `]`. When set to `true`, both should be marked with `[` and `]` only. + * @param {module:engine/view/stylesmap~StylesProcessor} [options.stylesProcessor] Styles processor. * @returns {module:engine/view/text~Text|module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|Object} * Returns the parsed view node or an object with two fields: `view` and `selection` when selection ranges were included in the data * to parse. */ export function parse( data, options = {} ) { + const viewDocument = new ViewDocument( new StylesProcessor() ); + options.order = options.order || []; const rangeParser = new RangeParser( { sameSelectionCharacters: options.sameSelectionCharacters } ); - const processor = new XmlDataProcessor( { + const processor = new XmlDataProcessor( viewDocument, { namespaces: Object.keys( allowedTypes ) } ); @@ -927,7 +932,10 @@ class ViewStringify { function _convertViewElements( rootNode ) { if ( rootNode.is( 'element' ) || rootNode.is( 'documentFragment' ) ) { // Convert element or leave document fragment. - const convertedElement = rootNode.is( 'documentFragment' ) ? new ViewDocumentFragment() : _convertElement( rootNode ); + + const convertedElement = rootNode.is( 'documentFragment' ) ? + new ViewDocumentFragment( rootNode.document ) : + _convertElement( rootNode.document, rootNode ); // Convert all child nodes. // Cache the nodes in array. Otherwise, we would skip some nodes because during iteration we move nodes @@ -973,10 +981,10 @@ function _convertViewElements( rootNode ) { // module:engine/view/emptyelement~EmptyElement|module:engine/view/uielement~UIElement| // module:engine/view/containerelement~ContainerElement} A tree view // element converted according to its name. -function _convertElement( viewElement ) { +function _convertElement( viewDocument, viewElement ) { const info = _convertElementNameAndInfo( viewElement ); const ElementConstructor = allowedTypes[ info.type ]; - const newElement = ElementConstructor ? new ElementConstructor( info.name ) : new ViewElement( info.name ); + const newElement = ElementConstructor ? new ElementConstructor( viewDocument, info.name ) : new ViewElement( viewDocument, info.name ); if ( newElement.is( 'attributeElement' ) ) { if ( info.priority !== null ) { diff --git a/src/model/model.js b/src/model/model.js index d428e57f8..79c8d7761 100644 --- a/src/model/model.js +++ b/src/model/model.js @@ -334,7 +334,7 @@ export default class Model { * * // You can create your own HtmlDataProcessor instance or use editor.data.processor * // if you have not overridden the default one (which is the HtmlDataProcessor instance). - * const htmlDP = new HtmlDataProcessor(); + * const htmlDP = new HtmlDataProcessor( viewDocument ); * * // Convert an HTML string to a view document fragment: * const viewFragment = htmlDP.toView( htmlString ); diff --git a/src/model/node.js b/src/model/node.js index 3795350b1..d85bb8055 100644 --- a/src/model/node.js +++ b/src/model/node.js @@ -189,20 +189,12 @@ export default class Node { } /** - * {@link module:engine/model/document~Document Document} that owns this node or `null` if the node has no parent or is inside - * a {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment}. + * Returns true if the node is in a tree rooted in the document (is a descendant of one of its roots). * - * @readonly - * @type {module:engine/model/document~Document|null} + * @returns {Boolean} */ - get document() { - // This is a top element of a sub-tree. - if ( this.root == this ) { - return null; - } - - // Root may be `DocumentFragment` which does not have document property. - return this.root.document || null; + isAttached() { + return this.root.is( 'rootElement' ); } /** diff --git a/src/model/rootelement.js b/src/model/rootelement.js index 77fe0f2c8..2d29cac2d 100644 --- a/src/model/rootelement.js +++ b/src/model/rootelement.js @@ -17,12 +17,12 @@ export default class RootElement extends Element { /** * Creates root element. * - * @param {module:engine/model/document~Document} doc Document that is an owner of this root. + * @param {module:engine/model/document~Document} document Document that is an owner of this root. * @param {String} name Node name. * @param {String} [rootName='main'] Unique root name used to identify this root * element by {@link module:engine/model/document~Document}. */ - constructor( doc, name, rootName = 'main' ) { + constructor( document, name, rootName = 'main' ) { super( name ); /** @@ -31,7 +31,7 @@ export default class RootElement extends Element { * @private * @member {module:engine/model/document~Document} */ - this._doc = doc; + this._document = document; /** * Unique root name used to identify this root element by {@link module:engine/model/document~Document}. @@ -45,13 +45,11 @@ export default class RootElement extends Element { /** * {@link module:engine/model/document~Document Document} that owns this root element. * - * In contrary, to {@link module:engine/model/node~Node node}, root element always have a `document`. - * * @readonly * @type {module:engine/model/document~Document|null} */ get document() { - return this._doc; + return this._document; } /** diff --git a/src/model/selection.js b/src/model/selection.js index be1fe8682..aad3538c3 100644 --- a/src/model/selection.js +++ b/src/model/selection.js @@ -829,7 +829,7 @@ function isUnvisitedBlock( element, visited ) { visited.add( element ); - return element.document.model.schema.isBlock( element ) && element.parent; + return element.root.document.model.schema.isBlock( element ) && element.parent; } // Checks if the given element is a $block was not previously visited and is a top block in a range. @@ -841,7 +841,8 @@ function isUnvisitedTopBlock( element, visited, range ) { // It will search until first ancestor that is a limit element. // Marks all ancestors as already visited to not include any of them later on. function getParentBlock( position, visited ) { - const schema = position.parent.document.model.schema; + const element = position.parent; + const schema = element.root.document.model.schema; const ancestors = position.parent.getAncestors( { parentFirst: true, includeSelf: true } ); @@ -887,7 +888,7 @@ function isTopBlockInRange( block, range ) { // @param {module:engine/model/node~Node} node // @returns {module:engine/model/node~Node|undefined} function findAncestorBlock( node ) { - const schema = node.document.model.schema; + const schema = node.root.document.model.schema; let parent = node.parent; diff --git a/src/model/textproxy.js b/src/model/textproxy.js index 1d4a0a9cf..f3946f8c4 100644 --- a/src/model/textproxy.js +++ b/src/model/textproxy.js @@ -163,17 +163,6 @@ export default class TextProxy { return this.textNode.root; } - /** - * {@link module:engine/model/document~Document Document} that owns text node represented by this text proxy or `null` if the text node - * has no parent or is inside a {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment}. - * - * @readonly - * @type {module:engine/model/document~Document|null} - */ - get document() { - return this.textNode.document; - } - /** * Checks whether this object is of the given. * diff --git a/src/view/attributeelement.js b/src/view/attributeelement.js index a63c3e56c..626e470d1 100644 --- a/src/view/attributeelement.js +++ b/src/view/attributeelement.js @@ -33,9 +33,14 @@ export default class AttributeElement extends Element { * @see module:engine/view/downcastwriter~DowncastWriter#createAttributeElement * @see module:engine/view/element~Element * @protected + * @param {module:engine/view/document~Document} document The document instance to which this element belongs. + * @param {String} name Node name. + * @param {Object|Iterable} [attrs] Collection of attributes. + * @param {module:engine/view/node~Node|Iterable.} [children] + * A list of nodes to be inserted into created element. */ - constructor( name, attrs, children ) { - super( name, attrs, children ); + constructor( document, name, attrs, children ) { + super( document, name, attrs, children ); /** * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed. diff --git a/src/view/containerelement.js b/src/view/containerelement.js index d06a4e0c2..753b71867 100644 --- a/src/view/containerelement.js +++ b/src/view/containerelement.js @@ -37,9 +37,14 @@ export default class ContainerElement extends Element { * @see module:engine/view/downcastwriter~DowncastWriter#createContainerElement * @see module:engine/view/element~Element * @protected + * @param {module:engine/view/document~Document} document The document instance to which this element belongs. + * @param {String} name Node name. + * @param {Object|Iterable} [attrs] Collection of attributes. + * @param {module:engine/view/node~Node|Iterable.} [children] + * A list of nodes to be inserted into created element. */ - constructor( name, attrs, children ) { - super( name, attrs, children ); + constructor( document, name, attrs, children ) { + super( document, name, attrs, children ); /** * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed. diff --git a/src/view/document.js b/src/view/document.js index 0cc471375..2d1738541 100644 --- a/src/view/document.js +++ b/src/view/document.js @@ -11,7 +11,6 @@ import DocumentSelection from './documentselection'; import Collection from '@ckeditor/ckeditor5-utils/src/collection'; import mix from '@ckeditor/ckeditor5-utils/src/mix'; import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin'; -import StylesMap from './stylesmap'; // @if CK_DEBUG_ENGINE // const { logDocument } = require( '../dev-utils/utils' ); @@ -24,8 +23,10 @@ import StylesMap from './stylesmap'; export default class Document { /** * Creates a Document instance. + * + * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance. */ - constructor() { + constructor( stylesProcessor ) { /** * Selection done on this document. * @@ -47,6 +48,14 @@ export default class Document { */ this.roots = new Collection( { idProperty: 'rootName' } ); + /** + * The styles processor instance used by this document when normalizing styles. + * + * @readonly + * @member {module:engine/view/stylesmap~StylesProcessor} + */ + this.stylesProcessor = stylesProcessor; + /** * Defines whether document is in read-only mode. * @@ -161,22 +170,6 @@ export default class Document { this.stopListening(); } - /** - * Adds a style processor normalization rules. - * - * The available style processors: - * - * * background: {@link module:engine/view/styles/background~addBackgroundRules} - * * border: {@link module:engine/view/styles/border~addBorderRules} - * * margin: {@link module:engine/view/styles/margin~addMarginRules} - * * padding: {@link module:engine/view/styles/padding~addPaddingRules} - * - * @param {Function} callback - */ - addStyleProcessorRules( callback ) { - callback( StylesMap._styleProcessor ); - } - /** * Performs post-fixer loops. Executes post-fixer callbacks as long as none of them has done any changes to the model. * diff --git a/src/view/documentfragment.js b/src/view/documentfragment.js index ae55450d6..1bda12313 100644 --- a/src/view/documentfragment.js +++ b/src/view/documentfragment.js @@ -25,10 +25,19 @@ export default class DocumentFragment { * Creates new DocumentFragment instance. * * @protected + * @param {module:engine/view/document~Document} document The document to which this document fragment belongs. * @param {module:engine/view/node~Node|Iterable.} [children] * A list of nodes to be inserted into the created document fragment. */ - constructor( children ) { + constructor( document, children ) { + /** + * The document to which this document fragment belongs. + * + * @readonly + * @member {module:engine/view/document~Document} + */ + this.document = document; + /** * Array of child nodes. * @@ -164,7 +173,7 @@ export default class DocumentFragment { this._fireChange( 'children', this ); let count = 0; - const nodes = normalize( items ); + const nodes = normalize( this.document, items ); for ( const node of nodes ) { // If node that is being added to this element is already inside another element, first remove it from the old parent. @@ -238,10 +247,10 @@ mix( DocumentFragment, EmitterMixin ); // // @param {String|module:engine/view/item~Item|Iterable.} // @returns {Iterable.} -function normalize( nodes ) { +function normalize( document, nodes ) { // Separate condition because string is iterable. if ( typeof nodes == 'string' ) { - return [ new Text( nodes ) ]; + return [ new Text( document, nodes ) ]; } if ( !isIterable( nodes ) ) { @@ -252,11 +261,11 @@ function normalize( nodes ) { return Array.from( nodes ) .map( node => { if ( typeof node == 'string' ) { - return new Text( node ); + return new Text( document, node ); } if ( node instanceof TextProxy ) { - return new Text( node.data ); + return new Text( document, node.data ); } return node; diff --git a/src/view/domconverter.js b/src/view/domconverter.js index d71d0ef78..c8564a552 100644 --- a/src/view/domconverter.js +++ b/src/view/domconverter.js @@ -44,10 +44,17 @@ export default class DomConverter { /** * Creates DOM converter. * + * @param {module:engine/view/document~Document} document The view document instance. * @param {Object} options Object with configuration options. * @param {module:engine/view/filler~BlockFillerMode} [options.blockFillerMode='br'] The type of the block filler to use. */ - constructor( options = {} ) { + constructor( document, options = {} ) { + /** + * @readonly + * @type {module:engine/view/document~Document} + */ + this.document = document; + /** * The mode of a block filler used by DOM converter. * @@ -399,7 +406,7 @@ export default class DomConverter { } else { const textData = this._processDataFromDomText( domNode ); - return textData === '' ? null : new ViewText( textData ); + return textData === '' ? null : new ViewText( this.document, textData ); } } else if ( this.isComment( domNode ) ) { return null; @@ -412,7 +419,7 @@ export default class DomConverter { if ( this.isDocumentFragment( domNode ) ) { // Create view document fragment. - viewElement = new ViewDocumentFragment(); + viewElement = new ViewDocumentFragment( this.document ); if ( options.bind ) { this.bindDocumentFragments( domNode, viewElement ); @@ -420,7 +427,7 @@ export default class DomConverter { } else { // Create view element. const viewName = options.keepOriginalCase ? domNode.tagName : domNode.tagName.toLowerCase(); - viewElement = new ViewElement( viewName ); + viewElement = new ViewElement( this.document, viewName ); if ( options.bind ) { this.bindElements( domNode, viewElement ); @@ -800,7 +807,7 @@ export default class DomConverter { /** * Checks if the node is an instance of the block filler for this DOM converter. * - * const converter = new DomConverter( { blockFillerMode: 'br' } ); + * const converter = new DomConverter( viewDocument, { blockFillerMode: 'br' } ); * * converter.isBlockFiller( BR_FILLER( document ) ); // true * converter.isBlockFiller( NBSP_FILLER( document ) ); // false diff --git a/src/view/downcastwriter.js b/src/view/downcastwriter.js index c6bd7916f..9f9d3e0b7 100644 --- a/src/view/downcastwriter.js +++ b/src/view/downcastwriter.js @@ -37,8 +37,13 @@ import { isPlainObject } from 'lodash-es'; * section of the {@glink framework/guides/architecture/editing-engine Editing engine architecture} guide. */ export default class DowncastWriter { + /** + * @param {module:engine/view/document~Document} document The view document instance. + */ constructor( document ) { /** + * The view document instance in which this writer operates. + * * @readonly * @type {module:engine/view/document~Document} */ @@ -145,7 +150,7 @@ export default class DowncastWriter { * @returns {module:engine/view/text~Text} The created text node. */ createText( data ) { - return new Text( data ); + return new Text( this.document, data ); } /** @@ -168,7 +173,7 @@ export default class DowncastWriter { * @returns {module:engine/view/attributeelement~AttributeElement} Created element. */ createAttributeElement( name, attributes, options = {} ) { - const attributeElement = new AttributeElement( name, attributes ); + const attributeElement = new AttributeElement( this.document, name, attributes ); if ( options.priority ) { attributeElement._priority = options.priority; @@ -200,7 +205,7 @@ export default class DowncastWriter { * @returns {module:engine/view/containerelement~ContainerElement} Created element. */ createContainerElement( name, attributes ) { - return new ContainerElement( name, attributes ); + return new ContainerElement( this.document, name, attributes ); } /** @@ -214,7 +219,7 @@ export default class DowncastWriter { * @returns {module:engine/view/editableelement~EditableElement} Created element. */ createEditableElement( name, attributes ) { - const editableElement = new EditableElement( name, attributes ); + const editableElement = new EditableElement( this.document, name, attributes ); editableElement._document = this.document; return editableElement; @@ -231,7 +236,7 @@ export default class DowncastWriter { * @returns {module:engine/view/emptyelement~EmptyElement} Created element. */ createEmptyElement( name, attributes ) { - return new EmptyElement( name, attributes ); + return new EmptyElement( this.document, name, attributes ); } /** @@ -255,7 +260,7 @@ export default class DowncastWriter { * @returns {module:engine/view/uielement~UIElement} Created element. */ createUIElement( name, attributes, renderFunction ) { - const uiElement = new UIElement( name, attributes ); + const uiElement = new UIElement( this.document, name, attributes ); if ( renderFunction ) { uiElement.render = renderFunction; @@ -325,7 +330,7 @@ export default class DowncastWriter { * }, element ); * * **Note**: The passed style can be normalized if - * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}. + * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}. * See {@link module:engine/view/stylesmap~StylesMap#set `StylesMap#set()`} for details. * * @param {String|Object} property Property name or object with key - value pairs. @@ -347,7 +352,7 @@ export default class DowncastWriter { * writer.removeStyle( [ 'color', 'border-top' ], element ); // Removes both 'color' and 'border-top' styles. * * **Note**: This method can work with normalized style names if - * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}. + * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}. * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details. * * @param {Array.|String} property @@ -686,7 +691,7 @@ export default class DowncastWriter { // If range is collapsed - nothing to remove. if ( range.isCollapsed ) { - return new DocumentFragment(); + return new DocumentFragment( this.document ); } // Break attributes at range start and end. @@ -708,7 +713,7 @@ export default class DowncastWriter { range.end = mergePosition.clone(); // Return removed nodes. - return new DocumentFragment( removed ); + return new DocumentFragment( this.document, removed ); } /** @@ -914,7 +919,7 @@ export default class DowncastWriter { * @param {module:engine/view/containerelement~ContainerElement} viewElement Element to be renamed. */ rename( newName, viewElement ) { - const newElement = new ContainerElement( newName, viewElement.getAttributes() ); + const newElement = new ContainerElement( this.document, newName, viewElement.getAttributes() ); this.insert( Position._createAfter( viewElement ), newElement ); this.move( Range._createIn( viewElement ), Position._createAt( newElement, 0 ) ); @@ -985,7 +990,7 @@ export default class DowncastWriter { /** * Creates a range spanning from `start` position to `end` position. * - * **Note:** This factory method creates it's own {@link module:engine/view/position~Position} instances basing on passed values. + * **Note:** This factory method creates its own {@link module:engine/view/position~Position} instances basing on passed values. * * @param {module:engine/view/position~Position} start Start position. * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position. @@ -1807,7 +1812,7 @@ function breakTextNode( position ) { position.parent._data = position.parent.data.slice( 0, position.offset ); // Insert new text node after position's parent text node. - position.parent.parent._insertChild( position.parent.index + 1, new Text( textToMove ) ); + position.parent.parent._insertChild( position.parent.index + 1, new Text( position.root.document, textToMove ) ); // Return new position between two newly created text nodes. return new Position( position.parent.parent, position.parent.index + 1 ); diff --git a/src/view/editableelement.js b/src/view/editableelement.js index 8a9b61641..b6ca91c6f 100644 --- a/src/view/editableelement.js +++ b/src/view/editableelement.js @@ -8,12 +8,9 @@ */ import ContainerElement from './containerelement'; -import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; import mix from '@ckeditor/ckeditor5-utils/src/mix'; import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin'; -const documentSymbol = Symbol( 'document' ); - /** * Editable element which can be a {@link module:engine/view/rooteditableelement~RootEditableElement root} * or nested editable area in the editor. @@ -33,8 +30,8 @@ export default class EditableElement extends ContainerElement { * @see module:engine/view/downcastwriter~DowncastWriter#createEditableElement * @protected */ - constructor( name, attrs, children ) { - super( name, attrs, children ); + constructor( document, name, attrs, children ) { + super( document, name, attrs, children ); /** * Whether the editable is in read-write or read-only mode. @@ -56,14 +53,18 @@ export default class EditableElement extends ContainerElement { */ this.set( 'isFocused', false ); - /** - * The {@link module:engine/view/document~Document} which is an owner of this root. - * Can only by set once. - * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-editableelement-document-already-set` - * when document is already set. - * - * @member {module:engine/view/document~Document} #document - */ + this.bind( 'isReadOnly' ).to( document ); + + this.bind( 'isFocused' ).to( + document, + 'isFocused', + isFocused => isFocused && document.selection.editableElement == this + ); + + // Update focus state based on selection changes. + this.listenTo( document.selection, 'change', () => { + this.isFocused = document.isFocused && document.selection.editableElement == this; + } ); } /** @@ -105,48 +106,6 @@ export default class EditableElement extends ContainerElement { destroy() { this.stopListening(); } - - /** - * Returns document associated with the editable. - * - * @readonly - * @returns {module:engine/view/document~Document} - */ - get document() { - return this.getCustomProperty( documentSymbol ); - } - - /** - * Sets document of this editable element. - * - * @protected - * @param {module:engine/view/document~Document} document - */ - set _document( document ) { - if ( this.getCustomProperty( documentSymbol ) ) { - /** - * View document is already set. It can only be set once. - * - * @error view-editableelement-document-already-set - */ - throw new CKEditorError( 'view-editableelement-document-already-set: View document is already set.', this ); - } - - this._setCustomProperty( documentSymbol, document ); - - this.bind( 'isReadOnly' ).to( document ); - - this.bind( 'isFocused' ).to( - document, - 'isFocused', - isFocused => isFocused && document.selection.editableElement == this - ); - - // Update focus state based on selection changes. - this.listenTo( document.selection, 'change', () => { - this.isFocused = document.isFocused && document.selection.editableElement == this; - } ); - } } mix( EditableElement, ObservableMixin ); diff --git a/src/view/element.js b/src/view/element.js index be74c983b..9bd3efebb 100644 --- a/src/view/element.js +++ b/src/view/element.js @@ -48,18 +48,19 @@ export default class Element extends Node { * * Attributes can be passed in various formats: * - * new Element( 'div', { class: 'editor', contentEditable: 'true' } ); // object - * new Element( 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator - * new Element( 'div', mapOfAttributes ); // map + * new Element( viewDocument, 'div', { class: 'editor', contentEditable: 'true' } ); // object + * new Element( viewDocument, 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator + * new Element( viewDocument, 'div', mapOfAttributes ); // map * * @protected + * @param {module:engine/view/document~Document} document The document instance to which this element belongs. * @param {String} name Node name. * @param {Object|Iterable} [attrs] Collection of attributes. * @param {module:engine/view/node~Node|Iterable.} [children] * A list of nodes to be inserted into created element. */ - constructor( name, attrs, children ) { - super(); + constructor( document, name, attrs, children ) { + super( document ); /** * Name of the element. @@ -110,7 +111,7 @@ export default class Element extends Node { * @protected * @member {module:engine/view/stylesmap~StylesMap} module:engine/view/element~Element#_styles */ - this._styles = new StylesMap(); + this._styles = new StylesMap( this.document.stylesProcessor ); if ( this._attrs.has( 'style' ) ) { // Remove style attribute and handle it by styles map. @@ -380,13 +381,13 @@ export default class Element extends Node { * If the style does not exist `undefined` is returned. * * **Note**: This method can work with normalized style names if - * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}. + * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}. * See {@link module:engine/view/stylesmap~StylesMap#getAsString `StylesMap#getAsString()`} for details. * * For an element with style set to `'margin:1px'`: * * // Enable 'margin' shorthand processing: - * editor.editing.view.document.addStyleProcessorRules( addMarginRules ); + * editor.data.addStyleProcessorRules( addMarginRules ); * * const element = view.change( writer => { * const element = writer.createElement(); @@ -428,7 +429,7 @@ export default class Element extends Node { * Will return a `2px` string. * * **Note**: This method will return normalized values only if - * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}. + * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}. * See {@link module:engine/view/stylesmap~StylesMap#getNormalized `StylesMap#getNormalized()`} for details. * * @@ -563,7 +564,7 @@ export default class Element extends Node { } // ContainerElement and AttributeElement should be also cloned properly. - const cloned = new this.constructor( this.name, this._attrs, childrenClone ); + const cloned = new this.constructor( this.document, this.name, this._attrs, childrenClone ); // Classes and styles are cloned separately - this solution is faster than adding them back to attributes and // parse once again in constructor. @@ -610,7 +611,7 @@ export default class Element extends Node { this._fireChange( 'children', this ); let count = 0; - const nodes = normalize( items ); + const nodes = normalize( this.document, items ); for ( const node of nodes ) { // If node that is being added to this element is already inside another element, first remove it from the old parent. @@ -619,6 +620,7 @@ export default class Element extends Node { } node.parent = this; + node.document = this.document; this._children.splice( index, 0, node ); index++; @@ -755,7 +757,7 @@ export default class Element extends Node { * } ); * * **Note**: This method can work with normalized style names if - * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}. + * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}. * See {@link module:engine/view/stylesmap~StylesMap#set `StylesMap#set()`} for details. * * @see module:engine/view/downcastwriter~DowncastWriter#setStyle @@ -777,7 +779,7 @@ export default class Element extends Node { * element._removeStyle( [ 'color', 'border-top' ] ); // Removes both 'color' and 'border-top' styles. * * **Note**: This method can work with normalized style names if - * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}. + * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}. * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details. * * @see module:engine/view/downcastwriter~DowncastWriter#removeStyle @@ -886,10 +888,10 @@ function parseClasses( classesSet, classesString ) { // // @param {String|module:engine/view/item~Item|Iterable.} // @returns {Iterable.} -function normalize( nodes ) { +function normalize( document, nodes ) { // Separate condition because string is iterable. if ( typeof nodes == 'string' ) { - return [ new Text( nodes ) ]; + return [ new Text( document, nodes ) ]; } if ( !isIterable( nodes ) ) { @@ -900,11 +902,11 @@ function normalize( nodes ) { return Array.from( nodes ) .map( node => { if ( typeof node == 'string' ) { - return new Text( node ); + return new Text( document, node ); } if ( node instanceof TextProxy ) { - return new Text( node.data ); + return new Text( document, node.data ); } return node; diff --git a/src/view/emptyelement.js b/src/view/emptyelement.js index 2d8d4ea9b..39182de91 100644 --- a/src/view/emptyelement.js +++ b/src/view/emptyelement.js @@ -28,11 +28,14 @@ export default class EmptyElement extends Element { * * @see module:engine/view/downcastwriter~DowncastWriter#createEmptyElement * @protected + * @param {module:engine/view/document~Document} document The document instance to which this element belongs. * @param {String} name Node name. - * @param {Object|Iterable} [attributes] Collection of attributes. + * @param {Object|Iterable} [attrs] Collection of attributes. + * @param {module:engine/view/node~Node|Iterable.} [children] + * A list of nodes to be inserted into created element. */ - constructor( name, attributes, children ) { - super( name, attributes, children ); + constructor( document, name, attrs, children ) { + super( document, name, attrs, children ); /** * Returns `null` because filler is not needed for EmptyElements. diff --git a/src/view/node.js b/src/view/node.js index 1e109df4c..719120930 100644 --- a/src/view/node.js +++ b/src/view/node.js @@ -17,19 +17,30 @@ import { clone } from 'lodash-es'; import '@ckeditor/ckeditor5-utils/src/version'; /** - * Abstract tree view node class. + * Abstract view node class. * * This is an abstract class. Its constructor should not be used directly. - * Use the {@link module:engine/view/element~Element} class to create view elements - * or {@link module:engine/view/text~Text} class to create view text nodes. + * Use the {@link module:engine/view/downcastwriter~DowncastWriter} or {@link module:engine/view/upcastwriter~UpcastWriter} + * to create new instances of view nodes. * * @abstract */ export default class Node { /** * Creates a tree view node. + * + * @protected + * @param {module:engine/view/document~Document} document The document instance to which this node belongs. */ - constructor() { + constructor( document ) { + /** + * The document instance to which this node belongs. + * + * @readonly + * @member {module:engine/view/document~Document} + */ + this.document = document; + /** * Parent element. Null by default. Set by {@link module:engine/view/element~Element#_insertChild}. * @@ -109,19 +120,12 @@ export default class Node { } /** - * {@link module:engine/view/document~Document View document} that owns this node, or `null` if the node is inside - * {@link module:engine/view/documentfragment~DocumentFragment document fragment}. + * Returns true if the node is in a tree rooted in the document (is a descendant of one of its roots). * - * @readonly - * @type {module:engine/view/document~Document|null} + * @returns {Boolean} */ - get document() { - // Parent might be Node, null or DocumentFragment. - if ( this.parent instanceof Node ) { - return this.parent.document; - } else { - return null; - } + isAttached() { + return this.root.is( 'rootElement' ); } /** diff --git a/src/view/placeholder.js b/src/view/placeholder.js index bdc0709da..b8fc3c9a4 100644 --- a/src/view/placeholder.js +++ b/src/view/placeholder.js @@ -144,10 +144,7 @@ export function hidePlaceholder( writer, element ) { * @returns {Boolean} */ export function needsPlaceholder( element ) { - const doc = element.document; - - // The element was removed from document. - if ( !doc ) { + if ( !element.isAttached() ) { return false; } @@ -155,6 +152,8 @@ export function needsPlaceholder( element ) { const isEmptyish = !Array.from( element.getChildren() ) .some( element => !element.is( 'uiElement' ) ); + const doc = element.document; + // If the element is empty and the document is blurred. if ( !doc.isFocused && isEmptyish ) { return true; @@ -201,6 +200,7 @@ function updateDocumentPlaceholders( doc, writer ) { // @returns {Boolean} True if any changes were made to the view document. function updatePlaceholder( writer, element, config ) { const { text, isDirectHost } = config; + const hostElement = isDirectHost ? element : getChildPlaceholderHostSubstitute( element ); let wasViewModified = false; diff --git a/src/view/rooteditableelement.js b/src/view/rooteditableelement.js index f298446fb..75337cb21 100644 --- a/src/view/rooteditableelement.js +++ b/src/view/rooteditableelement.js @@ -22,10 +22,11 @@ export default class RootEditableElement extends EditableElement { /** * Creates root editable element. * + * @param {module:engine/view/document~Document} document The document instance to which this element belongs. * @param {String} name Node name. */ - constructor( name ) { - super( name ); + constructor( document, name ) { + super( document, name ); /** * Name of this root inside {@link module:engine/view/document~Document} that is an owner of this root. If no diff --git a/src/view/styles/background.js b/src/view/styles/background.js index 3d5d49285..0974ef044 100644 --- a/src/view/styles/background.js +++ b/src/view/styles/background.js @@ -12,7 +12,7 @@ import { getShorthandValues, isAttachment, isColor, isPosition, isRepeat, isURL /** * Adds a background CSS styles processing rules. * - * editor.editing.view.document.addStyleProcessorRules( addBackgroundRules ); + * editor.data.addStyleProcessorRules( addBackgroundRules ); * * The normalized value is stored as: * diff --git a/src/view/styles/border.js b/src/view/styles/border.js index b044d9fbb..c8ecb87e8 100644 --- a/src/view/styles/border.js +++ b/src/view/styles/border.js @@ -12,7 +12,7 @@ import { getShorthandValues, getBoxSidesValueReducer, getBoxSidesValues, isLengt /** * Adds a border CSS styles processing rules. * - * editor.editing.view.document.addStyleProcessorRules( addBorderRules ); + * editor.data.addStyleProcessorRules( addBorderRules ); * * This rules merges all [border](https://developer.mozilla.org/en-US/docs/Web/CSS/border) styles notation shorthands: * diff --git a/src/view/styles/margin.js b/src/view/styles/margin.js index b308fbd64..740d2552f 100644 --- a/src/view/styles/margin.js +++ b/src/view/styles/margin.js @@ -12,7 +12,7 @@ import { getPositionShorthandNormalizer, getBoxSidesValueReducer } from './utils /** * Adds a margin CSS styles processing rules. * - * editor.editing.view.document.addStyleProcessorRules( addMarginRules ); + * editor.data.addStyleProcessorRules( addMarginRules ); * * The normalized value is stored as: * diff --git a/src/view/styles/padding.js b/src/view/styles/padding.js index 0a906e6d6..a5709e3a2 100644 --- a/src/view/styles/padding.js +++ b/src/view/styles/padding.js @@ -12,7 +12,7 @@ import { getPositionShorthandNormalizer, getBoxSidesValueReducer } from './utils /** * Adds a margin CSS styles processing rules. * - * editor.editing.view.document.addStyleProcessorRules( addPaddingRules ); + * editor.data.addStyleProcessorRules( addPaddingRules ); * * The normalized value is stored as: * diff --git a/src/view/stylesmap.js b/src/view/stylesmap.js index 8f54ff62e..b89a35a80 100644 --- a/src/view/stylesmap.js +++ b/src/view/stylesmap.js @@ -17,28 +17,28 @@ import { get, isObject, merge, set, unset } from 'lodash-es'; export default class StylesMap { /** * Creates Styles instance. + * + * @param {module:engine/view/stylesmap~StylesProcessor} styleProcessor */ - constructor() { + constructor( styleProcessor ) { /** * Keeps an internal representation of styles map. Normalized styles are kept as object tree to allow unified modification and * value access model using lodash's get, set, unset, etc methods. * * When no style processor rules are defined the it acts as simple key-value storage. * - * @type {Object} * @private + * @type {Object} */ this._styles = {}; - // Hide _styleProcessor from the watchdog by making this property non-enumarable. Watchdog checks errors for their editor origin - // by checking if two objects are connected through properties. Using singleton is against this check as it would detect - // that two editors are connected through single style processor instance. - Object.defineProperty( this, '_styleProcessor', { - get() { - return StylesMap._styleProcessor; - }, - enumerable: false - } ); + /** + * An instance of the {@link module:engine/view/stylesmap~StylesProcessor}. + * + * @private + * @member {module:engine/view/stylesmap~StylesProcessor} + */ + this._styleProcessor = styleProcessor; } /** @@ -94,7 +94,7 @@ export default class StylesMap { * **Note**: This check supports normalized style names. * * // Enable 'margin' shorthand processing: - * editor.editing.view.document.addStyleProcessorRules( addMarginRules ); + * editor.data.addStyleProcessorRules( addMarginRules ); * * styles.setTo( 'margin:2px;' ); * @@ -139,11 +139,11 @@ export default class StylesMap { * 'margin-right': '1em' * } ); * - * ***Note**:* This method uses {@link module:engine/view/document~Document#addStyleProcessorRules enabled style processor rules} - * to normalize passed values. + * ***Note**:* This method uses {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules + * enabled style processor rules} to normalize passed values. * * // Enable 'margin' shorthand processing: - * editor.editing.view.document.addStyleProcessorRules( addMarginRules ); + * editor.data.addStyleProcessorRules( addMarginRules ); * * styles.set( 'margin', '2px' ); * @@ -192,11 +192,11 @@ export default class StylesMap { * * styles.toString(); // -> 'margin-right:2px;' * - * ***Note**:* This method uses {@link module:engine/view/document~Document#addStyleProcessorRules enabled style processor rules} - * to normalize passed values. + * ***Note**:* This method uses {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules + * enabled style processor rules} to normalize passed values. * * // Enable 'margin' shorthand processing: - * editor.editing.view.document.addStyleProcessorRules( addMarginRules ); + * editor.data.addStyleProcessorRules( addMarginRules ); * * styles.setTo( 'margin:1px' ); * @@ -220,7 +220,7 @@ export default class StylesMap { * Returns a normalized style object or a single value. * * // Enable 'margin' shorthand processing: - * editor.editing.view.document.addStyleProcessorRules( addMarginRules ); + * editor.data.addStyleProcessorRules( addMarginRules ); * * const styles = new Styles(); * styles.setTo( 'margin:1px 2px 3em;' ); @@ -256,7 +256,7 @@ export default class StylesMap { * **Note**: This method supports normalized styles if defined. * * // Enable 'margin' shorthand processing: - * editor.editing.view.document.addStyleProcessorRules( addMarginRules ); + * editor.data.addStyleProcessorRules( addMarginRules ); * * styles.set( 'margin' , '1px' ); * styles.set( 'background', '#f00' ); @@ -282,7 +282,7 @@ export default class StylesMap { * Returns property as a value string or undefined if property is not set. * * // Enable 'margin' shorthand processing: - * editor.editing.view.document.addStyleProcessorRules( addMarginRules ); + * editor.data.addStyleProcessorRules( addMarginRules ); * * const styles = new Styles(); * styles.setTo( 'margin:1px;' ); @@ -371,28 +371,6 @@ export default class StylesMap { this._styles = {}; } - /** - * Returns related style names. - * - * // Enable 'margin' shorthand processing: - * editor.editing.view.document.addStyleProcessorRules( addMarginRules ); - * - * StylesMap.getRelatedStyles( 'margin' ); - * // will return: [ 'margin-top', 'margin-right', 'margin-bottom', 'margin-left' ]; - * - * StylesMap.getRelatedStyles( 'margin-top' ); - * // will return: [ 'margin' ]; - * - * **Note**: To define new style relations load an existing style processor (as shown above) or use - * {@link module:engine/view/stylesmap~StylesProcessor#setStyleRelation `StylesProcessor.setStyleRelation()`}. - * - * @param {String} name - * @returns {Array.} - */ - static getRelatedStyles( name ) { - return this._styleProcessor.getRelatedStyles( name ); - } - /** * Returns normalized styles entries for further processing. * @@ -439,32 +417,6 @@ export default class StylesMap { this.remove( parentPath ); } } - - /** - * Returns global StylesProcessor instance. - * - * @returns {module:engine/view/stylesmap~StylesProcessor} - * @private - */ - static get _styleProcessor() { - if ( !this._processor ) { - this._processor = new StylesProcessor(); - } - - return this._processor; - } - - /** - * Set new StylesProcessor instance. - * - * This is an internal method used mostly in tests. - * - * @param processor - * @protected - */ - static _setProcessor( processor ) { - this._processor = processor; - } } /** diff --git a/src/view/text.js b/src/view/text.js index f0c5a85e5..27636d59f 100644 --- a/src/view/text.js +++ b/src/view/text.js @@ -12,7 +12,7 @@ import Node from './node'; /** * Tree view text node. * - * The constructor of this class shouldn't be used directly. To create new Text instances + * The constructor of this class should not be used directly. To create a new text node instance * use the {@link module:engine/view/downcastwriter~DowncastWriter#createText `DowncastWriter#createText()`} * method when working on data downcasted from the model or the * {@link module:engine/view/upcastwriter~UpcastWriter#createText `UpcastWriter#createText()`} @@ -25,10 +25,11 @@ export default class Text extends Node { * Creates a tree view text node. * * @protected + * @param {module:engine/view/document~Document} document The document instance to which this text node belongs. * @param {String} data The text's data. */ - constructor( data ) { - super(); + constructor( document, data ) { + super( document ); /** * The text content. @@ -125,7 +126,7 @@ export default class Text extends Node { * @returns {module:engine/view/text~Text} Text node that is a clone of this node. */ _clone() { - return new Text( this.data ); + return new Text( this.document, this.data ); } // @if CK_DEBUG_ENGINE // toString() { diff --git a/src/view/uielement.js b/src/view/uielement.js index 3cae1c14d..c2f2a0718 100644 --- a/src/view/uielement.js +++ b/src/view/uielement.js @@ -41,11 +41,14 @@ export default class UIElement extends Element { * * @see module:engine/view/downcastwriter~DowncastWriter#createUIElement * @protected + * @param {module:engine/view/document~Document} document The document instance to which this element belongs. * @param {String} name Node name. * @param {Object|Iterable} [attributes] Collection of attributes. + * @param {module:engine/view/node~Node|Iterable.} [children] + * A list of nodes to be inserted into created element. */ - constructor( name, attributes, children ) { - super( name, attributes, children ); + constructor( document, name, attributes, children ) { + super( document, name, attributes, children ); /** * Returns `null` because filler is not needed for UIElements. diff --git a/src/view/upcastwriter.js b/src/view/upcastwriter.js index e5d90ccdb..973e81846 100644 --- a/src/view/upcastwriter.js +++ b/src/view/upcastwriter.js @@ -29,12 +29,25 @@ import Selection from './selection'; * Unlike `DowncastWriter`, which is available in the {@link module:engine/view/view~View#change `View#change()`} block, * `UpcastWriter` can be created wherever you need it: * - * const writer = new UpcastWriter(); + * const writer = new UpcastWriter( viewDocument ); * const text = writer.createText( 'foo!' ); * * writer.appendChild( text, someViewElement ); */ export default class UpcastWriter { + /** + * @param {module:engine/view/document~Document} document The view document instance in which this upcast writer operates. + */ + constructor( document ) { + /** + * The view document instance in which this upcast writer operates. + * + * @readonly + * @type {module:engine/view/document~Document} + */ + this.document = document; + } + /** * Creates a new {@link module:engine/view/documentfragment~DocumentFragment} instance. * @@ -43,7 +56,7 @@ export default class UpcastWriter { * @returns {module:engine/view/documentfragment~DocumentFragment} The created document fragment. */ createDocumentFragment( children ) { - return new DocumentFragment( children ); + return new DocumentFragment( this.document, children ); } /** @@ -62,7 +75,7 @@ export default class UpcastWriter { * @returns {module:engine/view/element~Element} Created element. */ createElement( name, attrs, children ) { - return new Element( name, attrs, children ); + return new Element( this.document, name, attrs, children ); } /** @@ -72,7 +85,7 @@ export default class UpcastWriter { * @returns {module:engine/view/text~Text} The created text node. */ createText( data ) { - return new Text( data ); + return new Text( this.document, data ); } /** @@ -201,7 +214,7 @@ export default class UpcastWriter { * was not replaced (happens for detached elements). */ rename( newName, element ) { - const newElement = new Element( newName, element.getAttributes(), element.getChildren() ); + const newElement = new Element( this.document, newName, element.getAttributes(), element.getChildren() ); return this.replace( element, newElement ) ? newElement : null; } @@ -271,7 +284,7 @@ export default class UpcastWriter { * } ); * * **Note**: This method can work with normalized style names if - * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}. + * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}. * See {@link module:engine/view/stylesmap~StylesMap#set `StylesMap#set()`} for details. * * @see module:engine/view/element~Element#_setStyle @@ -293,7 +306,7 @@ export default class UpcastWriter { * writer.removeStyle( element, [ 'color', 'border-top' ] ); // Removes both 'color' and 'border-top' styles. * * **Note**: This method can work with normalized style names if - * {@link module:engine/view/document~Document#addStyleProcessorRules a particular style processor rule is enabled}. + * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}. * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details. * * @see module:engine/view/element~Element#_removeStyle diff --git a/src/view/view.js b/src/view/view.js index c380ac5f2..379092a32 100644 --- a/src/view/view.js +++ b/src/view/view.js @@ -62,14 +62,17 @@ import env from '@ckeditor/ckeditor5-utils/src/env'; * @mixes module:utils/observablemixin~ObservableMixin */ export default class View { - constructor() { + /** + * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance. + */ + constructor( stylesProcessor ) { /** * Instance of the {@link module:engine/view/document~Document} associated with this view controller. * * @readonly * @type {module:engine/view/document~Document} */ - this.document = new Document(); + this.document = new Document( stylesProcessor ); /** * Instance of the {@link module:engine/view/domconverter~DomConverter domConverter} used by @@ -79,7 +82,7 @@ export default class View { * @readonly * @type {module:engine/view/domconverter~DomConverter} */ - this.domConverter = new DomConverter(); + this.domConverter = new DomConverter( this.document ); /** * Roots of the DOM tree. Map on the `HTMLElement`s with roots names as keys. diff --git a/tests/controller/datacontroller.js b/tests/controller/datacontroller.js index f358f051e..3fad2844d 100644 --- a/tests/controller/datacontroller.js +++ b/tests/controller/datacontroller.js @@ -11,6 +11,7 @@ import HtmlDataProcessor from '../../src/dataprocessor/htmldataprocessor'; import ModelDocumentFragment from '../../src/model/documentfragment'; import ViewDocumentFragment from '../../src/view/documentfragment'; +import ViewDocument from '../../src/view/document'; import { getData, setData, stringify, parse as parseModel } from '../../src/dev-utils/model'; import { parse as parseView, stringify as stringifyView } from '../../src/dev-utils/view'; @@ -20,11 +21,13 @@ import count from '@ckeditor/ckeditor5-utils/src/count'; import UpcastHelpers from '../../src/conversion/upcasthelpers'; import DowncastHelpers from '../../src/conversion/downcasthelpers'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'DataController', () => { - let model, modelDocument, htmlDataProcessor, data, schema, upcastHelpers, downcastHelpers; + let model, modelDocument, htmlDataProcessor, data, schema, upcastHelpers, downcastHelpers, viewDocument; beforeEach( () => { + const stylesProcessor = new StylesProcessor(); model = new Model(); schema = model.schema; @@ -35,19 +38,23 @@ describe( 'DataController', () => { schema.register( '$title', { inheritAllFrom: '$root' } ); - htmlDataProcessor = new HtmlDataProcessor(); + viewDocument = new ViewDocument( stylesProcessor ); + htmlDataProcessor = new HtmlDataProcessor( viewDocument ); - data = new DataController( model, htmlDataProcessor ); + data = new DataController( model, stylesProcessor ); + data.processor = htmlDataProcessor; upcastHelpers = new UpcastHelpers( [ data.upcastDispatcher ] ); downcastHelpers = new DowncastHelpers( [ data.downcastDispatcher ] ); } ); describe( 'constructor()', () => { - it( 'works without data processor', () => { - const data = new DataController( model ); + it( 'sets the model and styles processor properties', () => { + const stylesProcessor = new StylesProcessor(); + const data = new DataController( model, stylesProcessor ); - expect( data.processor ).to.be.undefined; + expect( data.model ).to.equal( model ); + expect( data.stylesProcessor ).to.equal( stylesProcessor ); } ); } ); @@ -139,7 +146,7 @@ describe( 'DataController', () => { schema.register( 'inlineRoot' ); schema.extend( '$text', { allowIn: 'inlineRoot' } ); - const viewFragment = new ViewDocumentFragment( [ parseView( 'foo' ) ] ); + const viewFragment = new ViewDocumentFragment( viewDocument, [ parseView( 'foo' ) ] ); // Model fragment in root. expect( stringify( data.toModel( viewFragment ) ) ).to.equal( '' ); @@ -569,4 +576,18 @@ describe( 'DataController', () => { expect( data ).to.respondTo( 'destroy' ); } ); } ); + + describe( 'addStyleProcessorRules()', () => { + it( 'should execute callback with an instance of StyleProcessor as the first argument', () => { + const stylesProcessor = new StylesProcessor(); + const data = new DataController( model, stylesProcessor ); + + const spy = sinon.spy(); + + data.addStyleProcessorRules( spy ); + + sinon.assert.calledOnce( spy ); + sinon.assert.calledWithExactly( spy, stylesProcessor ); + } ); + } ); } ); diff --git a/tests/controller/editingcontroller.js b/tests/controller/editingcontroller.js index b4c7bb638..467e05087 100644 --- a/tests/controller/editingcontroller.js +++ b/tests/controller/editingcontroller.js @@ -22,6 +22,7 @@ import ModelDocumentFragment from '../../src/model/documentfragment'; import { getData as getModelData, parse } from '../../src/dev-utils/model'; import { getData as getViewData } from '../../src/dev-utils/view'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'EditingController', () => { describe( 'constructor()', () => { @@ -29,7 +30,7 @@ describe( 'EditingController', () => { beforeEach( () => { model = new Model(); - editing = new EditingController( model ); + editing = new EditingController( model, new StylesProcessor() ); } ); afterEach( () => { @@ -77,7 +78,7 @@ describe( 'EditingController', () => { model = new Model(); modelRoot = model.document.createRoot(); - editing = new EditingController( model ); + editing = new EditingController( model, new StylesProcessor() ); domRoot = document.createElement( 'div' ); domRoot.contentEditable = true; @@ -477,7 +478,7 @@ describe( 'EditingController', () => { model.document.createRoot(); model.schema.register( 'paragraph', { inheritAllFrom: '$block' } ); - const editing = new EditingController( model ); + const editing = new EditingController( model, new StylesProcessor() ); const spy = sinon.spy(); @@ -501,7 +502,7 @@ describe( 'EditingController', () => { model.document.createRoot(); model.schema.register( 'paragraph', { inheritAllFrom: '$block' } ); - const editing = new EditingController( model ); + const editing = new EditingController( model, new StylesProcessor() ); const spy = sinon.spy( editing.view, 'destroy' ); diff --git a/tests/conversion/conversion.js b/tests/conversion/conversion.js index da81d2ac6..09fa4308c 100644 --- a/tests/conversion/conversion.js +++ b/tests/conversion/conversion.js @@ -18,6 +18,7 @@ import { parse as viewParse, stringify as viewStringify } from '../../src/dev-ut import { stringify as modelStringify } from '../../src/dev-utils/model'; import ConversionHelpers from '../../src/conversion/conversionhelpers'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'Conversion', () => { let conversion, downcastDispA, upcastDispaA, downcastDispB; @@ -121,7 +122,7 @@ describe( 'Conversion', () => { beforeEach( () => { model = new Model(); - const controller = new EditingController( model ); + const controller = new EditingController( model, new StylesProcessor() ); const modelDoc = model.document; modelRoot = modelDoc.createRoot(); diff --git a/tests/conversion/downcastdispatcher.js b/tests/conversion/downcastdispatcher.js index 68c1bfb75..23d98dd4f 100644 --- a/tests/conversion/downcastdispatcher.js +++ b/tests/conversion/downcastdispatcher.js @@ -13,13 +13,14 @@ import ModelRange from '../../src/model/range'; import View from '../../src/view/view'; import ViewContainerElement from '../../src/view/containerelement'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'DowncastDispatcher', () => { let dispatcher, doc, root, differStub, model, view, mapper; beforeEach( () => { model = new Model(); - view = new View(); + view = new View( new StylesProcessor() ); doc = model.document; mapper = new Mapper(); dispatcher = new DowncastDispatcher( { mapper } ); @@ -414,8 +415,8 @@ describe( 'DowncastDispatcher', () => { root._appendChild( [ image ] ); // Create view elements that will be "mapped" to model elements. - const viewCaption = new ViewContainerElement( 'caption' ); - const viewFigure = new ViewContainerElement( 'figure', null, viewCaption ); + const viewCaption = new ViewContainerElement( view.document, 'caption' ); + const viewFigure = new ViewContainerElement( view.document, 'figure', null, viewCaption ); // Create custom highlight handler mock. viewFigure._setCustomProperty( 'addHighlight', () => {} ); diff --git a/tests/conversion/downcasthelpers.js b/tests/conversion/downcasthelpers.js index 5c0201100..13f07e474 100644 --- a/tests/conversion/downcasthelpers.js +++ b/tests/conversion/downcasthelpers.js @@ -16,6 +16,7 @@ import ViewAttributeElement from '../../src/view/attributeelement'; import ViewContainerElement from '../../src/view/containerelement'; import ViewUIElement from '../../src/view/uielement'; import ViewText from '../../src/view/text'; +import ViewDocument from '../../src/view/document'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; @@ -34,18 +35,18 @@ import View from '../../src/view/view'; import createViewRoot from '../view/_utils/createroot'; import { setData as setModelData } from '../../src/dev-utils/model'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../src/view/stylesmap'; +import DowncastWriter from '../../src/view/downcastwriter'; describe( 'DowncastHelpers', () => { - let model, modelRoot, viewRoot, downcastHelpers, controller; - - let modelRootStart; + let model, modelRoot, viewRoot, downcastHelpers, controller, modelRootStart; beforeEach( () => { model = new Model(); const modelDoc = model.document; modelRoot = modelDoc.createRoot(); - controller = new EditingController( model ); + controller = new EditingController( model, new StylesProcessor() ); // Set name of view root the same as dom root. // This is a mock of attaching view root to dom root. @@ -1319,13 +1320,15 @@ describe( 'DowncastHelpers', () => { converterPriority: 7 }; - let markerRange; + let markerRange, viewDocument; beforeEach( () => { + viewDocument = new ViewDocument( new StylesProcessor() ); + downcastHelpers.elementToElement( { model: 'div', view: () => { - const viewContainer = new ViewContainerElement( 'div' ); + const viewContainer = new ViewContainerElement( viewDocument, 'div' ); viewContainer._setCustomProperty( 'addHighlight', ( element, descriptor, writer ) => { writer.addClass( descriptor.classes, element ); @@ -1453,7 +1456,7 @@ describe( 'downcast converters', () => { modelDoc = model.document; modelRoot = modelDoc.createRoot(); - controller = new EditingController( model ); + controller = new EditingController( model, new StylesProcessor() ); viewRoot = controller.view.document.getRoot(); // Set name of view root the same as dom root. @@ -1499,6 +1502,12 @@ describe( 'downcast converters', () => { // Remove converter is by default already added in `EditingController` instance. describe( 'remove()', () => { + let viewDocument; + + beforeEach( () => { + viewDocument = new ViewDocument( new StylesProcessor() ); + } ); + it( 'should remove items from view accordingly to changes in model #1', () => { const modelElement = new ModelElement( 'paragraph', null, new ModelText( 'foobar' ) ); @@ -1552,9 +1561,9 @@ describe( 'downcast converters', () => { it( 'should not remove view ui elements that are placed next to removed content', () => { modelRoot._appendChild( new ModelText( 'fozbar' ) ); viewRoot._appendChild( [ - new ViewText( 'foz' ), - new ViewUIElement( 'span' ), - new ViewText( 'bar' ) + new ViewText( viewDocument, 'foz' ), + new ViewUIElement( viewDocument, 'span' ), + new ViewText( viewDocument, 'bar' ) ] ); // Remove 'b'. @@ -1579,9 +1588,9 @@ describe( 'downcast converters', () => { it( 'should remove correct amount of text when it is split by view ui element', () => { modelRoot._appendChild( new ModelText( 'fozbar' ) ); viewRoot._appendChild( [ - new ViewText( 'foz' ), - new ViewUIElement( 'span' ), - new ViewText( 'bar' ) + new ViewText( viewDocument, 'foz' ), + new ViewUIElement( viewDocument, 'span' ), + new ViewText( viewDocument, 'bar' ) ] ); // Remove 'zb'. @@ -1649,10 +1658,10 @@ describe( 'downcast converters', () => { const modelP1 = new ModelElement( 'paragraph' ); const modelP2 = new ModelElement( 'paragraph' ); - const viewP1 = new ViewContainerElement( 'p' ); - const viewUi1 = new ViewUIElement( 'span' ); - const viewUi2 = new ViewUIElement( 'span' ); - const viewP2 = new ViewContainerElement( 'p' ); + const viewP1 = new ViewContainerElement( viewDocument, 'p' ); + const viewUi1 = new ViewUIElement( viewDocument, 'span' ); + const viewUi2 = new ViewUIElement( viewDocument, 'span' ); + const viewP2 = new ViewContainerElement( viewDocument, 'p' ); modelRoot._appendChild( [ modelP1, modelP2 ] ); viewRoot._appendChild( [ viewP1, viewUi1, viewUi2, viewP2 ] ); @@ -1685,13 +1694,19 @@ describe( 'downcast converters', () => { } ); describe( 'createViewElementFromHighlightDescriptor()', () => { + let viewWriter; + + beforeEach( () => { + viewWriter = new DowncastWriter( controller.view.document ); + } ); + it( 'should return attribute element from descriptor object', () => { const descriptor = { classes: 'foo-class', attributes: { one: '1', two: '2' }, priority: 7 }; - const element = createViewElementFromHighlightDescriptor( descriptor ); + const element = createViewElementFromHighlightDescriptor( viewWriter, descriptor ); expect( element.is( 'attributeElement' ) ).to.be.true; expect( element.name ).to.equal( 'span' ); @@ -1709,7 +1724,7 @@ describe( 'downcast converters', () => { attributes: { one: '1', two: '2' }, priority: 7 }; - const element = createViewElementFromHighlightDescriptor( descriptor ); + const element = createViewElementFromHighlightDescriptor( viewWriter, descriptor ); expect( element.is( 'attributeElement' ) ).to.be.true; expect( element.name ).to.equal( 'span' ); @@ -1727,7 +1742,7 @@ describe( 'downcast converters', () => { attributes: { one: '1', two: '2' }, priority: 7 }; - const element = createViewElementFromHighlightDescriptor( descriptor ); + const element = createViewElementFromHighlightDescriptor( viewWriter, descriptor ); expect( element.is( 'attributeElement' ) ).to.be.true; expect( element.name ).to.equal( 'span' ); @@ -1743,7 +1758,7 @@ describe( 'downcast converters', () => { classes: 'foo-class', attributes: { one: '1', two: '2' } }; - const element = createViewElementFromHighlightDescriptor( descriptor ); + const element = createViewElementFromHighlightDescriptor( viewWriter, descriptor ); expect( element.is( 'attributeElement' ) ).to.be.true; expect( element.name ).to.equal( 'span' ); @@ -1760,7 +1775,7 @@ describe( 'downcast converters', () => { classes: 'foo-class', priority: 7 }; - const element = createViewElementFromHighlightDescriptor( descriptor ); + const element = createViewElementFromHighlightDescriptor( viewWriter, descriptor ); expect( element.is( 'attributeElement' ) ).to.be.true; expect( element.name ).to.equal( 'span' ); @@ -1781,7 +1796,7 @@ describe( 'downcast selection converters', () => { model.schema.extend( '$text', { allowIn: '$root' } ); - view = new View(); + view = new View( new StylesProcessor() ); viewDoc = view.document; viewRoot = createViewRoot( viewDoc ); viewSelection = viewDoc.selection; @@ -1908,7 +1923,11 @@ describe( 'downcast selection converters', () => { } ); describe( 'collapsed selection', () => { - let marker; + let marker, viewDocument; + + beforeEach( () => { + viewDocument = new ViewDocument( new StylesProcessor() ); + } ); it( 'in container', () => { testSelection( @@ -2040,8 +2059,8 @@ describe( 'downcast selection converters', () => { // Add two ui elements to view. viewRoot._appendChild( [ - new ViewUIElement( 'span' ), - new ViewUIElement( 'span' ) + new ViewUIElement( viewDocument, 'span' ), + new ViewUIElement( viewDocument, 'span' ) ] ); model.change( writer => { @@ -2073,7 +2092,7 @@ describe( 'downcast selection converters', () => { dispatcher.convertInsert( model.createRangeIn( modelRoot ), writer ); // Add ui element to view. - const uiElement = new ViewUIElement( 'span' ); + const uiElement = new ViewUIElement( viewDocument, 'span' ); viewRoot._insertChild( 1, uiElement ); dispatcher.convertSelection( docSelection, model.markers, writer ); @@ -2098,7 +2117,7 @@ describe( 'downcast selection converters', () => { dispatcher.convertInsert( model.createRangeIn( modelRoot ), writer ); // Add ui element to view. - const uiElement = new ViewUIElement( 'span' ); + const uiElement = new ViewUIElement( viewDocument, 'span' ); viewRoot._insertChild( 1, uiElement, writer ); dispatcher.convertSelection( docSelection, model.markers, writer ); } ); diff --git a/tests/conversion/mapper.js b/tests/conversion/mapper.js index 619935780..2ddea3ad1 100644 --- a/tests/conversion/mapper.js +++ b/tests/conversion/mapper.js @@ -11,19 +11,27 @@ import ModelText from '../../src/model/text'; import ModelPosition from '../../src/model/position'; import ModelRange from '../../src/model/range'; +import ViewDocument from '../../src/view/document'; import ViewElement from '../../src/view/element'; import ViewUIElement from '../../src/view/uielement'; import ViewText from '../../src/view/text'; import ViewPosition from '../../src/view/position'; import ViewRange from '../../src/view/range'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'Mapper', () => { + let viewDocument; + + beforeEach( () => { + viewDocument = new ViewDocument( new StylesProcessor() ); + } ); + describe( 'clearBindings', () => { it( 'should remove all mapping', () => { - const viewA = new ViewElement( 'a' ); - const viewB = new ViewElement( 'b' ); - const viewC = new ViewElement( 'c' ); - const viewD = new ViewElement( 'd' ); + const viewA = new ViewElement( viewDocument, 'a' ); + const viewB = new ViewElement( viewDocument, 'b' ); + const viewC = new ViewElement( viewDocument, 'c' ); + const viewD = new ViewElement( viewDocument, 'd' ); const modelA = new ModelElement( 'a' ); const modelB = new ModelElement( 'b' ); @@ -69,7 +77,7 @@ describe( 'Mapper', () => { describe( 'unbindModelElement', () => { it( 'should remove binding between given model element and view element that it was bound to', () => { - const viewA = new ViewElement( 'a' ); + const viewA = new ViewElement( viewDocument, 'a' ); const modelA = new ModelElement( 'a' ); const mapper = new Mapper(); @@ -85,7 +93,7 @@ describe( 'Mapper', () => { } ); it( 'should not remove binding between view and model element if view element got rebound', () => { - const viewA = new ViewElement( 'a' ); + const viewA = new ViewElement( viewDocument, 'a' ); const modelA = new ModelElement( 'a' ); const modelB = new ModelElement( 'b' ); @@ -105,7 +113,7 @@ describe( 'Mapper', () => { describe( 'unbindViewElement', () => { it( 'should remove binding between given view element and model element that it was bound to', () => { - const viewA = new ViewElement( 'a' ); + const viewA = new ViewElement( viewDocument, 'a' ); const modelA = new ModelElement( 'a' ); const mapper = new Mapper(); @@ -121,8 +129,8 @@ describe( 'Mapper', () => { } ); it( 'should not remove binding between model and view element if model element got rebound', () => { - const viewA = new ViewElement( 'a' ); - const viewB = new ViewElement( 'b' ); + const viewA = new ViewElement( viewDocument, 'a' ); + const viewB = new ViewElement( viewDocument, 'b' ); const modelA = new ModelElement( 'a' ); const mapper = new Mapper(); @@ -201,21 +209,21 @@ describe( 'Mapper', () => { new ModelText( 'zz' ) ] ); - viewTextB = new ViewText( 'b' ); - viewTextO = new ViewText( 'o' ); - viewTextM = new ViewText( 'm' ); - viewTextX = new ViewText( 'x' ); - viewTextY = new ViewText( 'y' ); - viewTextZZ = new ViewText( 'zz' ); - viewTextFOO = new ViewText( 'foo' ); - viewTextBAR = new ViewText( 'bar' ); - viewImg = new ViewElement( 'img' ); - viewSup = new ViewElement( 'sup', {}, [ viewTextO ] ); - viewU = new ViewElement( 'u', {}, [ viewTextB, viewSup, viewTextM ] ); - viewI = new ViewElement( 'i', {}, [ viewTextFOO ] ); - viewB = new ViewElement( 'b', {}, [ viewI ] ); - viewP = new ViewElement( 'p', {}, [ viewTextY, viewB, viewTextBAR, viewImg, viewU ] ); - viewDiv = new ViewElement( 'div', {}, [ viewTextX, viewP, viewTextZZ ] ); + viewTextB = new ViewText( viewDocument, 'b' ); + viewTextO = new ViewText( viewDocument, 'o' ); + viewTextM = new ViewText( viewDocument, 'm' ); + viewTextX = new ViewText( viewDocument, 'x' ); + viewTextY = new ViewText( viewDocument, 'y' ); + viewTextZZ = new ViewText( viewDocument, 'zz' ); + viewTextFOO = new ViewText( viewDocument, 'foo' ); + viewTextBAR = new ViewText( viewDocument, 'bar' ); + viewImg = new ViewElement( viewDocument, 'img' ); + viewSup = new ViewElement( viewDocument, 'sup', {}, [ viewTextO ] ); + viewU = new ViewElement( viewDocument, 'u', {}, [ viewTextB, viewSup, viewTextM ] ); + viewI = new ViewElement( viewDocument, 'i', {}, [ viewTextFOO ] ); + viewB = new ViewElement( viewDocument, 'b', {}, [ viewI ] ); + viewP = new ViewElement( viewDocument, 'p', {}, [ viewTextY, viewB, viewTextBAR, viewImg, viewU ] ); + viewDiv = new ViewElement( viewDocument, 'div', {}, [ viewTextX, viewP, viewTextZZ ] ); mapper = new Mapper(); mapper.bindElements( modelP, viewP ); @@ -467,17 +475,17 @@ describe( 'Mapper', () => { modelDiv = new ModelRootElement(); modelDiv._appendChild( [ new ModelText( 'x' ), modelWidget, new ModelText( 'zz' ) ] ); - viewTextX = new ViewText( 'y' ); - viewTextZZ = new ViewText( 'zz' ); - viewTextFOO = new ViewText( 'foo' ); - viewTextLABEL = new ViewText( 'label' ); + viewTextX = new ViewText( viewDocument, 'y' ); + viewTextZZ = new ViewText( viewDocument, 'zz' ); + viewTextFOO = new ViewText( viewDocument, 'foo' ); + viewTextLABEL = new ViewText( viewDocument, 'label' ); - viewImg = new ViewElement( 'img' ); - viewMask = new ViewElement( 'mask', {}, [ viewTextLABEL ] ); - viewCaption = new ViewElement( 'caption', {}, [ viewTextFOO ] ); - viewWrapper = new ViewElement( 'wrapper', {}, [ viewImg, viewCaption ] ); - viewWidget = new ViewElement( 'widget', [ viewMask, viewWrapper ] ); - viewDiv = new ViewElement( 'div', {}, [ viewTextX, viewWidget, viewTextZZ ] ); + viewImg = new ViewElement( viewDocument, 'img' ); + viewMask = new ViewElement( viewDocument, 'mask', {}, [ viewTextLABEL ] ); + viewCaption = new ViewElement( viewDocument, 'caption', {}, [ viewTextFOO ] ); + viewWrapper = new ViewElement( viewDocument, 'wrapper', {}, [ viewImg, viewCaption ] ); + viewWidget = new ViewElement( viewDocument, 'widget', [ viewMask, viewWrapper ] ); + viewDiv = new ViewElement( viewDocument, 'div', {}, [ viewTextX, viewWidget, viewTextZZ ] ); mapper = new Mapper(); mapper.bindElements( modelDiv, viewDiv ); @@ -574,15 +582,15 @@ describe( 'Mapper', () => { modelRoot = new ModelRootElement( 'root', null, [ modelListItem1, modelListItem11, modelListItem12, modelListItem2 ] ); - viewListItem11 = new ViewElement( 'li', null, new ViewText( 'bbb' ) ); - viewListItem12 = new ViewElement( 'li', null, new ViewText( 'ccc' ) ); - viewListNested = new ViewElement( 'ul', null, [ viewListItem11, viewListItem12 ] ); + viewListItem11 = new ViewElement( viewDocument, 'li', null, new ViewText( viewDocument, 'bbb' ) ); + viewListItem12 = new ViewElement( viewDocument, 'li', null, new ViewText( viewDocument, 'ccc' ) ); + viewListNested = new ViewElement( viewDocument, 'ul', null, [ viewListItem11, viewListItem12 ] ); - viewListItem1 = new ViewElement( 'li', null, [ new ViewText( 'aaa' ), viewListNested ] ); - viewListItem2 = new ViewElement( 'li', null, new ViewText( 'ddd' ) ); - viewList = new ViewElement( 'ul', null, [ viewListItem1, viewListItem2 ] ); + viewListItem1 = new ViewElement( viewDocument, 'li', null, [ new ViewText( viewDocument, 'aaa' ), viewListNested ] ); + viewListItem2 = new ViewElement( viewDocument, 'li', null, new ViewText( viewDocument, 'ddd' ) ); + viewList = new ViewElement( viewDocument, 'ul', null, [ viewListItem1, viewListItem2 ] ); - viewRoot = new ViewElement( 'div', null, viewList ); + viewRoot = new ViewElement( viewDocument, 'div', null, viewList ); mapper = new Mapper(); mapper.bindElements( modelRoot, viewRoot ); @@ -632,7 +640,7 @@ describe( 'Mapper', () => { } ); it( 'should bind element to a marker name', () => { - const view = new ViewElement( 'a' ); + const view = new ViewElement( viewDocument, 'a' ); mapper.bindElementToMarker( view, 'marker' ); @@ -644,9 +652,9 @@ describe( 'Mapper', () => { } ); it( 'should bind multiple elements to a marker name', () => { - const viewA = new ViewElement( 'a' ); - const viewB = new ViewElement( 'b' ); - const viewC = new ViewElement( 'c' ); + const viewA = new ViewElement( viewDocument, 'a' ); + const viewB = new ViewElement( viewDocument, 'b' ); + const viewC = new ViewElement( viewDocument, 'c' ); mapper.bindElementToMarker( viewA, 'marker' ); mapper.bindElementToMarker( viewB, 'marker' ); @@ -658,8 +666,8 @@ describe( 'Mapper', () => { } ); it( 'should unbind element from a marker name', () => { - const viewA = new ViewElement( 'a' ); - const viewB = new ViewElement( 'b' ); + const viewA = new ViewElement( viewDocument, 'a' ); + const viewB = new ViewElement( viewDocument, 'b' ); mapper.bindElementToMarker( viewA, 'marker' ); mapper.bindElementToMarker( viewA, 'markerB' ); @@ -701,7 +709,7 @@ describe( 'Mapper', () => { } ); it( 'should return length according to callback added by registerViewToModelLength', () => { - const viewElement = new ViewElement( 'span' ); + const viewElement = new ViewElement( viewDocument, 'span' ); mapper.registerViewToModelLength( 'span', () => 4 ); @@ -709,7 +717,7 @@ describe( 'Mapper', () => { } ); it( 'should return 1 for mapped elements', () => { - const viewElement = new ViewElement( 'span' ); + const viewElement = new ViewElement( viewDocument, 'span' ); const modelElement = new ModelElement( 'span' ); mapper.bindElements( modelElement, viewElement ); @@ -717,24 +725,24 @@ describe( 'Mapper', () => { } ); it( 'should return 0 for ui elements', () => { - const viewUiElement = new ViewUIElement( 'span' ); + const viewUiElement = new ViewUIElement( viewDocument, 'span' ); expect( mapper.getModelLength( viewUiElement ) ).to.equal( 0 ); } ); it( 'should return length of data for text nodes', () => { - const viewText = new ViewText( 'foo' ); + const viewText = new ViewText( viewDocument, 'foo' ); expect( mapper.getModelLength( viewText ) ).to.equal( 3 ); } ); it( 'should return sum of length of children for unmapped element', () => { const modelP = new ModelElement( 'p' ); - const viewP = new ViewElement( 'p' ); - const viewUi = new ViewUIElement( 'span' ); - const viewFoo = new ViewText( 'foo' ); - const viewCallback = new ViewElement( 'xxx' ); - const viewDiv = new ViewElement( 'div', null, [ viewP, viewUi, viewFoo, viewCallback ] ); + const viewP = new ViewElement( viewDocument, 'p' ); + const viewUi = new ViewUIElement( viewDocument, 'span' ); + const viewFoo = new ViewText( viewDocument, 'foo' ); + const viewCallback = new ViewElement( viewDocument, 'xxx' ); + const viewDiv = new ViewElement( viewDocument, 'div', null, [ viewP, viewUi, viewFoo, viewCallback ] ); mapper.bindElements( modelP, viewP ); mapper.registerViewToModelLength( 'xxx', () => 2 ); @@ -750,10 +758,10 @@ describe( 'Mapper', () => { const modelP = new ModelElement( 'p' ); const modelDiv = new ModelElement( 'div' ); - const viewText = new ViewText( 'foo' ); - const viewSpan = new ViewElement( 'span', null, viewText ); - const viewP = new ViewElement( 'p', null, viewSpan ); - const viewDiv = new ViewElement( 'div', null, viewP ); + const viewText = new ViewText( viewDocument, 'foo' ); + const viewSpan = new ViewElement( viewDocument, 'span', null, viewText ); + const viewP = new ViewElement( viewDocument, 'p', null, viewSpan ); + const viewDiv = new ViewElement( viewDocument, 'div', null, viewP ); mapper.bindElements( modelP, viewP ); mapper.bindElements( modelDiv, viewDiv ); @@ -770,8 +778,8 @@ describe( 'Mapper', () => { describe( 'flushUnboundMarkerNames()', () => { it( 'should return marker names of markers which elements has been unbound and clear that list', () => { - const viewA = new ViewElement( 'a' ); - const viewB = new ViewElement( 'b' ); + const viewA = new ViewElement( viewDocument, 'a' ); + const viewB = new ViewElement( viewDocument, 'b' ); const mapper = new Mapper(); diff --git a/tests/conversion/upcastdispatcher.js b/tests/conversion/upcastdispatcher.js index d8d367ced..d376494b2 100644 --- a/tests/conversion/upcastdispatcher.js +++ b/tests/conversion/upcastdispatcher.js @@ -8,6 +8,7 @@ import ViewContainerElement from '../../src/view/containerelement'; import ViewElement from '../../src/view/element'; import ViewDocumentFragment from '../../src/view/documentfragment'; import ViewText from '../../src/view/text'; +import ViewDocument from '../../src/view/document'; import Model from '../../src/model/model'; import ModelText from '../../src/model/text'; @@ -20,12 +21,14 @@ import ModelWriter from '../../src/model/writer'; import first from '@ckeditor/ckeditor5-utils/src/first'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'UpcastDispatcher', () => { - let model; + let model, viewDocument; beforeEach( () => { model = new Model(); + viewDocument = new ViewDocument( new StylesProcessor() ); } ); describe( 'constructor()', () => { @@ -56,7 +59,7 @@ describe( 'UpcastDispatcher', () => { } ); it( 'should create api for a conversion process', () => { - const viewElement = new ViewContainerElement( 'p', null, new ViewText( 'foobar' ) ); + const viewElement = new ViewContainerElement( viewDocument, 'p', null, new ViewText( viewDocument, 'foobar' ) ); // To be sure that both converters was called. const spy = sinon.spy(); @@ -108,16 +111,16 @@ describe( 'UpcastDispatcher', () => { it( 'should fire viewCleanup event on converted view part', () => { sinon.spy( dispatcher, 'fire' ); - const viewP = new ViewContainerElement( 'p' ); + const viewP = new ViewContainerElement( viewDocument, 'p' ); model.change( writer => dispatcher.convert( viewP, writer ) ); expect( dispatcher.fire.calledWith( 'viewCleanup', viewP ) ).to.be.true; } ); it( 'should fire proper events', () => { - const viewText = new ViewText( 'foobar' ); - const viewElement = new ViewContainerElement( 'p', null, viewText ); - const viewFragment = new ViewDocumentFragment( viewElement ); + const viewText = new ViewText( viewDocument, 'foobar' ); + const viewElement = new ViewContainerElement( viewDocument, 'p', null, viewText ); + const viewFragment = new ViewDocumentFragment( viewDocument, viewElement ); sinon.spy( dispatcher, 'fire' ); @@ -134,7 +137,7 @@ describe( 'UpcastDispatcher', () => { it( 'should convert ViewText', () => { const spy = sinon.spy(); - const viewText = new ViewText( 'foobar' ); + const viewText = new ViewText( viewDocument, 'foobar' ); dispatcher.on( 'text', ( evt, data, conversionApi ) => { // Check if this method has been fired. @@ -170,7 +173,7 @@ describe( 'UpcastDispatcher', () => { it( 'should convert ViewContainerElement', () => { const spy = sinon.spy(); - const viewElement = new ViewContainerElement( 'p', { attrKey: 'attrValue' } ); + const viewElement = new ViewContainerElement( viewDocument, 'p', { attrKey: 'attrValue' } ); dispatcher.on( 'element', ( evt, data, conversionApi ) => { // Check if this method has been fired. @@ -208,7 +211,7 @@ describe( 'UpcastDispatcher', () => { it( 'should convert ViewDocumentFragment', () => { const spy = sinon.spy(); - const viewFragment = new ViewDocumentFragment(); + const viewFragment = new ViewDocumentFragment( viewDocument ); dispatcher.on( 'documentFragment', ( evt, data, conversionApi ) => { // Check if this method has been fired. @@ -242,9 +245,9 @@ describe( 'UpcastDispatcher', () => { } ); it( 'should remove empty elements that was created as a result of split', () => { - const viewElement = new ViewElement( 'div', null, [ - new ViewElement( 'p', null, [ - new ViewElement( 'img' ) + const viewElement = new ViewElement( viewDocument, 'div', null, [ + new ViewElement( viewDocument, 'p', null, [ + new ViewElement( viewDocument, 'img' ) ] ) ] ); @@ -289,7 +292,7 @@ describe( 'UpcastDispatcher', () => { } ); it( 'should extract temporary markers elements from converter element and create static markers list', () => { - const viewFragment = new ViewDocumentFragment(); + const viewFragment = new ViewDocumentFragment( viewDocument ); dispatcher.on( 'documentFragment', ( evt, data, conversionApi ) => { // Create model fragment. @@ -326,7 +329,7 @@ describe( 'UpcastDispatcher', () => { dispatcher = new UpcastDispatcher( { schema: model.schema } ); const spy = sinon.spy(); - const viewElement = new ViewContainerElement( 'third' ); + const viewElement = new ViewContainerElement( viewDocument, 'third' ); let checkChildResult; model.schema.register( 'first', { @@ -377,8 +380,8 @@ describe( 'UpcastDispatcher', () => { spyP = sinon.spy(); spyText = sinon.spy(); - viewP = new ViewContainerElement( 'p' ); - viewText = new ViewText( 'foobar' ); + viewP = new ViewContainerElement( viewDocument, 'p' ); + viewText = new ViewText( viewDocument, 'foobar' ); modelP = new ModelElement( 'paragraph' ); modelText = new ModelText( 'foobar' ); @@ -404,9 +407,9 @@ describe( 'UpcastDispatcher', () => { spyNull = sinon.spy(); spyArray = sinon.spy(); - viewDiv = new ViewContainerElement( 'div' ); // Will not be recognized and not converted. - viewNull = new ViewContainerElement( 'null' ); // Will return `null` in `data.modelRange` upon conversion. - viewArray = new ViewContainerElement( 'array' ); // Will return an array in `data.modelRange` upon conversion. + viewDiv = new ViewContainerElement( viewDocument, 'div' ); // Will not be recognized and not converted. + viewNull = new ViewContainerElement( viewDocument, 'null' ); // Will return `null` in `data.modelRange` upon conversion. + viewArray = new ViewContainerElement( viewDocument, 'array' ); // Will return an array in `data.modelRange` upon conversion. dispatcher.on( 'element:null', ( evt, data ) => { spyNull(); @@ -444,7 +447,7 @@ describe( 'UpcastDispatcher', () => { expect( textResult.modelCursor.path ).to.deep.equal( [ 7 ] ); } ); - model.change( writer => dispatcher.convert( new ViewDocumentFragment(), writer ) ); + model.change( writer => dispatcher.convert( new ViewDocumentFragment( viewDocument ), writer ) ); expect( spy.calledOnce ).to.be.true; expect( spyP.calledOnce ).to.be.true; @@ -459,7 +462,7 @@ describe( 'UpcastDispatcher', () => { expect( conversionApi.convertItem( viewNull, data.modelCursor ).modelRange ).to.equal( null ); } ); - model.change( writer => dispatcher.convert( new ViewDocumentFragment(), writer ) ); + model.change( writer => dispatcher.convert( new ViewDocumentFragment( viewDocument ), writer ) ); expect( spy.calledOnce ).to.be.true; expect( spyNull.calledOnce ).to.be.true; @@ -473,7 +476,7 @@ describe( 'UpcastDispatcher', () => { } ); expectToThrowCKEditorError( () => { - model.change( writer => dispatcher.convert( new ViewDocumentFragment(), writer ) ); + model.change( writer => dispatcher.convert( new ViewDocumentFragment( viewDocument ), writer ) ); }, /^view-conversion-dispatcher-incorrect-result/, model ); expect( spy.calledOnce ).to.be.true; @@ -501,7 +504,7 @@ describe( 'UpcastDispatcher', () => { expect( result.modelCursor.path ).to.deep.equal( [ 7 ] ); } ); - model.change( writer => dispatcher.convert( new ViewDocumentFragment( [ viewP, viewText ] ), writer ) ); + model.change( writer => dispatcher.convert( new ViewDocumentFragment( viewDocument, [ viewP, viewText ] ), writer ) ); expect( spy.calledOnce ).to.be.true; expect( spyP.calledOnce ).to.be.true; @@ -534,7 +537,7 @@ describe( 'UpcastDispatcher', () => { spy(); } ); - model.change( writer => dispatcher.convert( new ViewDocumentFragment(), writer ) ); + model.change( writer => dispatcher.convert( new ViewDocumentFragment( viewDocument ), writer ) ); sinon.assert.calledOnce( spy ); } ); @@ -571,7 +574,7 @@ describe( 'UpcastDispatcher', () => { spy(); } ); - model.change( writer => dispatcher.convert( new ViewDocumentFragment(), writer ) ); + model.change( writer => dispatcher.convert( new ViewDocumentFragment( viewDocument ), writer ) ); sinon.assert.calledOnce( spy ); } ); @@ -591,7 +594,7 @@ describe( 'UpcastDispatcher', () => { spy(); } ); - model.change( writer => dispatcher.convert( new ViewDocumentFragment(), writer ) ); + model.change( writer => dispatcher.convert( new ViewDocumentFragment( viewDocument ), writer ) ); sinon.assert.calledOnce( spy ); } ); @@ -610,7 +613,7 @@ describe( 'UpcastDispatcher', () => { spy(); } ); - model.change( writer => dispatcher.convert( new ViewDocumentFragment(), writer, [ '$root', 'paragraph' ] ) ); + model.change( writer => dispatcher.convert( new ViewDocumentFragment( viewDocument ), writer, [ '$root', 'paragraph' ] ) ); sinon.assert.calledOnce( spy ); } ); } ); @@ -633,7 +636,7 @@ describe( 'UpcastDispatcher', () => { evt.stop(); }, { priority: 'high' } ); - const viewElement = new ViewElement( 'p' ); + const viewElement = new ViewElement( viewDocument, 'p' ); model.change( writer => dispatcher.convert( viewElement, writer ) ); @@ -695,12 +698,12 @@ describe( 'UpcastDispatcher', () => { evt.stop(); }, { priority: 'high' } ); - const viewElement = new ViewElement( 'p', null, [ - new ViewText( 'foo' ), - new ViewElement( 'image' ), - new ViewText( 'bar' ), - new ViewElement( 'image' ), - new ViewText( 'xyz' ) + const viewElement = new ViewElement( viewDocument, 'p', null, [ + new ViewText( viewDocument, 'foo' ), + new ViewElement( viewDocument, 'image' ), + new ViewText( viewDocument, 'bar' ), + new ViewElement( viewDocument, 'image' ), + new ViewText( viewDocument, 'xyz' ) ] ); model.change( writer => dispatcher.convert( viewElement, writer, [ '$root' ] ) ); diff --git a/tests/conversion/upcasthelpers.js b/tests/conversion/upcasthelpers.js index 7a0289f32..8b3f6499d 100644 --- a/tests/conversion/upcasthelpers.js +++ b/tests/conversion/upcasthelpers.js @@ -10,6 +10,7 @@ import ViewDocumentFragment from '../../src/view/documentfragment'; import ViewText from '../../src/view/text'; import ViewUIElement from '../../src/view/uielement'; import ViewAttributeElement from '../../src/view/attributeelement'; +import ViewDocument from '../../src/view/document'; import Model from '../../src/model/model'; import ModelDocumentFragment from '../../src/model/documentfragment'; @@ -27,12 +28,14 @@ import { setData as viewSetData } from '../../src/dev-utils/view'; import Mapper from '../../src/conversion/mapper'; import ViewSelection from '../../src/view/selection'; import ViewRange from '../../src/view/range'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'UpcastHelpers', () => { - let upcastDispatcher, model, schema, upcastHelpers; + let upcastDispatcher, model, schema, upcastHelpers, viewDocument; beforeEach( () => { model = new Model(); + viewDocument = new ViewDocument( new StylesProcessor() ); schema = model.schema; @@ -61,7 +64,7 @@ describe( 'UpcastHelpers', () => { it( 'config.view is a string', () => { upcastHelpers.elementToElement( { view: 'p', model: 'paragraph' } ); - expectResult( new ViewContainerElement( 'p' ), '' ); + expectResult( new ViewContainerElement( viewDocument, 'p' ), '' ); } ); it( 'can be overwritten using converterPriority', () => { @@ -72,7 +75,7 @@ describe( 'UpcastHelpers', () => { upcastHelpers.elementToElement( { view: 'p', model: 'p' } ); upcastHelpers.elementToElement( { view: 'p', model: 'paragraph', converterPriority: 'high' } ); - expectResult( new ViewContainerElement( 'p' ), '' ); + expectResult( new ViewContainerElement( viewDocument, 'p' ), '' ); } ); it( 'config.view is an object', () => { @@ -88,8 +91,8 @@ describe( 'UpcastHelpers', () => { model: 'fancyParagraph' } ); - expectResult( new ViewContainerElement( 'p', { class: 'fancy' } ), '' ); - expectResult( new ViewContainerElement( 'p' ), '' ); + expectResult( new ViewContainerElement( viewDocument, 'p', { class: 'fancy' } ), '' ); + expectResult( new ViewContainerElement( viewDocument, 'p' ), '' ); } ); it( 'config.model is a function', () => { @@ -108,8 +111,11 @@ describe( 'UpcastHelpers', () => { } } ); - expectResult( new ViewContainerElement( 'p', { class: 'heading', 'data-level': 2 } ), '' ); - expectResult( new ViewContainerElement( 'p', { 'data-level': 2 } ), '' ); + expectResult( + new ViewContainerElement( viewDocument, 'p', { class: 'heading', 'data-level': 2 } ), + '' + ); + expectResult( new ViewContainerElement( viewDocument, 'p', { 'data-level': 2 } ), '' ); } ); it( 'config.view is not set - should fire conversion for every element', () => { @@ -117,20 +123,23 @@ describe( 'UpcastHelpers', () => { model: 'paragraph' } ); - expectResult( new ViewContainerElement( 'p' ), '' ); - expectResult( new ViewContainerElement( 'foo' ), '' ); + expectResult( new ViewContainerElement( viewDocument, 'p' ), '' ); + expectResult( new ViewContainerElement( viewDocument, 'foo' ), '' ); } ); it( 'should fire conversion of the element children', () => { upcastHelpers.elementToElement( { view: 'p', model: 'paragraph' } ); - expectResult( new ViewContainerElement( 'p', null, new ViewText( 'foo' ) ), 'foo' ); + expectResult( + new ViewContainerElement( viewDocument, 'p', null, new ViewText( viewDocument, 'foo' ) ), + 'foo' + ); } ); it( 'should not insert a model element if it is not allowed by schema', () => { upcastHelpers.elementToElement( { view: 'h2', model: 'heading' } ); - expectResult( new ViewContainerElement( 'h2' ), '' ); + expectResult( new ViewContainerElement( viewDocument, 'h2' ), '' ); } ); it( 'should auto-break elements', () => { @@ -142,10 +151,10 @@ describe( 'UpcastHelpers', () => { upcastHelpers.elementToElement( { view: 'h2', model: 'heading' } ); expectResult( - new ViewContainerElement( 'p', null, [ - new ViewText( 'Foo' ), - new ViewContainerElement( 'h2', null, new ViewText( 'Xyz' ) ), - new ViewText( 'Bar' ) + new ViewContainerElement( viewDocument, 'p', null, [ + new ViewText( viewDocument, 'Foo' ), + new ViewContainerElement( viewDocument, 'h2', null, new ViewText( viewDocument, 'Xyz' ) ), + new ViewText( viewDocument, 'Bar' ) ] ), 'FooXyzBar' ); @@ -155,7 +164,7 @@ describe( 'UpcastHelpers', () => { upcastHelpers.elementToElement( { view: 'p', model: 'paragraph' } ); upcastHelpers.elementToElement( { view: 'p', model: () => null, converterPriority: 'high' } ); - expectResult( new ViewContainerElement( 'p' ), '' ); + expectResult( new ViewContainerElement( viewDocument, 'p' ), '' ); } ); } ); @@ -168,7 +177,7 @@ describe( 'UpcastHelpers', () => { upcastHelpers.elementToAttribute( { view: 'strong', model: 'bold' } ); expectResult( - new ViewAttributeElement( 'strong', null, new ViewText( 'foo' ) ), + new ViewAttributeElement( viewDocument, 'strong', null, new ViewText( viewDocument, 'foo' ) ), '<$text bold="true">foo' ); } ); @@ -178,7 +187,7 @@ describe( 'UpcastHelpers', () => { upcastHelpers.elementToAttribute( { view: 'strong', model: 'bold', converterPriority: 'high' } ); expectResult( - new ViewAttributeElement( 'strong', null, new ViewText( 'foo' ) ), + new ViewAttributeElement( viewDocument, 'strong', null, new ViewText( viewDocument, 'foo' ) ), '<$text bold="true">foo' ); } ); @@ -193,11 +202,11 @@ describe( 'UpcastHelpers', () => { } ); expectResult( - new ViewAttributeElement( 'span', { class: 'bold' }, new ViewText( 'foo' ) ), + new ViewAttributeElement( viewDocument, 'span', { class: 'bold' }, new ViewText( viewDocument, 'foo' ) ), '<$text bold="true">foo' ); - expectResult( new ViewAttributeElement( 'span', {}, new ViewText( 'foo' ) ), 'foo' ); + expectResult( new ViewAttributeElement( viewDocument, 'span', {}, new ViewText( viewDocument, 'foo' ) ), 'foo' ); } ); it( 'model attribute value is given', () => { @@ -217,11 +226,11 @@ describe( 'UpcastHelpers', () => { } ); expectResult( - new ViewAttributeElement( 'span', { class: 'styled styled-dark' }, new ViewText( 'foo' ) ), + new ViewAttributeElement( viewDocument, 'span', { class: 'styled styled-dark' }, new ViewText( viewDocument, 'foo' ) ), '<$text styled="dark">foo' ); - expectResult( new ViewAttributeElement( 'span', {}, new ViewText( 'foo' ) ), 'foo' ); + expectResult( new ViewAttributeElement( viewDocument, 'span', {}, new ViewText( viewDocument, 'foo' ) ), 'foo' ); } ); it( 'model attribute value is a function', () => { @@ -254,17 +263,17 @@ describe( 'UpcastHelpers', () => { } ); expectResult( - new ViewAttributeElement( 'span', { style: 'font-size:9px' }, new ViewText( 'foo' ) ), + new ViewAttributeElement( viewDocument, 'span', { style: 'font-size:9px' }, new ViewText( viewDocument, 'foo' ) ), '<$text fontSize="small">foo' ); expectResult( - new ViewAttributeElement( 'span', { style: 'font-size:12px' }, new ViewText( 'foo' ) ), + new ViewAttributeElement( viewDocument, 'span', { style: 'font-size:12px' }, new ViewText( viewDocument, 'foo' ) ), 'foo' ); expectResult( - new ViewAttributeElement( 'span', { style: 'font-size:14px' }, new ViewText( 'foo' ) ), + new ViewAttributeElement( viewDocument, 'span', { style: 'font-size:14px' }, new ViewText( viewDocument, 'foo' ) ), '<$text fontSize="big">foo' ); } ); @@ -273,7 +282,7 @@ describe( 'UpcastHelpers', () => { upcastHelpers.elementToAttribute( { view: 'em', model: 'italic' } ); expectResult( - new ViewAttributeElement( 'em', null, new ViewText( 'foo' ) ), + new ViewAttributeElement( viewDocument, 'em', null, new ViewText( viewDocument, 'foo' ) ), 'foo' ); } ); @@ -290,7 +299,7 @@ describe( 'UpcastHelpers', () => { } ); expectResult( - new ViewAttributeElement( 'strong', null, new ViewText( 'foo' ) ), + new ViewAttributeElement( viewDocument, 'strong', null, new ViewText( viewDocument, 'foo' ) ), '<$text bold="true">foo' ); } ); @@ -307,7 +316,12 @@ describe( 'UpcastHelpers', () => { } ); expectResult( - new ViewAttributeElement( 'span', { class: 'attrib-a', style: 'color:attrib-b;' }, new ViewText( 'foo' ) ), + new ViewAttributeElement( + viewDocument, + 'span', + { class: 'attrib-a', style: 'color:attrib-b;' }, + new ViewText( viewDocument, 'foo' ) + ), '<$text attribA="true" attribB="true">foo' ); } ); @@ -329,7 +343,7 @@ describe( 'UpcastHelpers', () => { } ); expectResult( - new ViewAttributeElement( 'strong', { class: 'foo' }, new ViewText( 'foo' ) ), + new ViewAttributeElement( viewDocument, 'strong', { class: 'foo' }, new ViewText( viewDocument, 'foo' ) ), '<$text attribB="true" bold="true">foo' ); } ); @@ -345,9 +359,10 @@ describe( 'UpcastHelpers', () => { expectResult( new ViewAttributeElement( + viewDocument, 'strong', null, - new ViewContainerElement( 'p', null, new ViewText( 'Foo' ) ) + new ViewContainerElement( viewDocument, 'p', null, new ViewText( viewDocument, 'Foo' ) ) ), '<$text bold="true">Foo' ); @@ -375,7 +390,7 @@ describe( 'UpcastHelpers', () => { upcastHelpers.attributeToAttribute( { view: 'src', model: 'source' } ); expectResult( - new ViewAttributeElement( 'img', { src: 'foo.jpg' } ), + new ViewAttributeElement( viewDocument, 'img', { src: 'foo.jpg' } ), '' ); } ); @@ -388,7 +403,7 @@ describe( 'UpcastHelpers', () => { upcastHelpers.attributeToAttribute( { view: { key: 'src' }, model: 'source' } ); expectResult( - new ViewAttributeElement( 'img', { src: 'foo.jpg' } ), + new ViewAttributeElement( viewDocument, 'img', { src: 'foo.jpg' } ), '' ); } ); @@ -401,7 +416,7 @@ describe( 'UpcastHelpers', () => { upcastHelpers.attributeToAttribute( { view: { name: 'img', key: 'src' }, model: { name: 'image', key: 'source' } } ); expectResult( - new ViewAttributeElement( 'img', { src: 'foo.jpg' } ), + new ViewAttributeElement( viewDocument, 'img', { src: 'foo.jpg' } ), '' ); } ); @@ -415,7 +430,7 @@ describe( 'UpcastHelpers', () => { upcastHelpers.attributeToAttribute( { view: { key: 'src' }, model: 'source', converterPriority: 'normal' } ); expectResult( - new ViewAttributeElement( 'img', { src: 'foo.jpg' } ), + new ViewAttributeElement( viewDocument, 'img', { src: 'foo.jpg' } ), '' ); } ); @@ -434,7 +449,7 @@ describe( 'UpcastHelpers', () => { } ); expectResult( - new ViewAttributeElement( 'img', { 'data-style': 'dark' } ), + new ViewAttributeElement( viewDocument, 'img', { 'data-style': 'dark' } ), '' ); } ); @@ -459,17 +474,17 @@ describe( 'UpcastHelpers', () => { upcastHelpers.elementToElement( { view: 'p', model: 'paragraph' } ); expectResult( - new ViewContainerElement( 'img', { class: 'styled-dark' } ), + new ViewContainerElement( viewDocument, 'img', { class: 'styled-dark' } ), '' ); expectResult( - new ViewContainerElement( 'img', { class: 'styled-xxx' } ), + new ViewContainerElement( viewDocument, 'img', { class: 'styled-xxx' } ), '' ); expectResult( - new ViewContainerElement( 'p', { class: 'styled-dark' } ), + new ViewContainerElement( viewDocument, 'p', { class: 'styled-dark' } ), '' ); } ); @@ -496,7 +511,7 @@ describe( 'UpcastHelpers', () => { } ); expectResult( - new ViewAttributeElement( 'img', { 'class': 'styled-dark' } ), + new ViewAttributeElement( viewDocument, 'img', { 'class': 'styled-dark' } ), '' ); } ); @@ -505,7 +520,7 @@ describe( 'UpcastHelpers', () => { upcastHelpers.attributeToAttribute( { view: 'src', model: 'source' } ); expectResult( - new ViewAttributeElement( 'img', { src: 'foo.jpg' } ), + new ViewAttributeElement( viewDocument, 'img', { src: 'foo.jpg' } ), '' ); } ); @@ -538,7 +553,7 @@ describe( 'UpcastHelpers', () => { } ); expectResult( - new ViewAttributeElement( 'img', { class: 'styled' } ), + new ViewAttributeElement( viewDocument, 'img', { class: 'styled' } ), '' ); } ); @@ -559,9 +574,10 @@ describe( 'UpcastHelpers', () => { expectResult( new ViewContainerElement( + viewDocument, 'div', { class: 'border' }, - new ViewContainerElement( 'div', { class: 'shade' } ) + new ViewContainerElement( viewDocument, 'div', { class: 'shade' } ) ), '
' ); @@ -576,12 +592,12 @@ describe( 'UpcastHelpers', () => { it( 'config.view is a string', () => { upcastHelpers.elementToMarker( { view: 'marker-search', model: 'search' } ); - const frag = new ViewDocumentFragment( [ - new ViewText( 'fo' ), - new ViewUIElement( 'marker-search' ), - new ViewText( 'oba' ), - new ViewUIElement( 'marker-search' ), - new ViewText( 'r' ) + const frag = new ViewDocumentFragment( viewDocument, [ + new ViewText( viewDocument, 'fo' ), + new ViewUIElement( viewDocument, 'marker-search' ), + new ViewText( viewDocument, 'oba' ), + new ViewUIElement( viewDocument, 'marker-search' ), + new ViewText( viewDocument, 'r' ) ] ); const marker = { name: 'search', start: [ 2 ], end: [ 5 ] }; @@ -593,12 +609,12 @@ describe( 'UpcastHelpers', () => { upcastHelpers.elementToMarker( { view: 'marker-search', model: 'search-result' } ); upcastHelpers.elementToMarker( { view: 'marker-search', model: 'search', converterPriority: 'high' } ); - const frag = new ViewDocumentFragment( [ - new ViewText( 'fo' ), - new ViewUIElement( 'marker-search' ), - new ViewText( 'oba' ), - new ViewUIElement( 'marker-search' ), - new ViewText( 'r' ) + const frag = new ViewDocumentFragment( viewDocument, [ + new ViewText( viewDocument, 'fo' ), + new ViewUIElement( viewDocument, 'marker-search' ), + new ViewText( viewDocument, 'oba' ), + new ViewUIElement( viewDocument, 'marker-search' ), + new ViewText( viewDocument, 'r' ) ] ); const marker = { name: 'search', start: [ 2 ], end: [ 5 ] }; @@ -615,12 +631,12 @@ describe( 'UpcastHelpers', () => { model: 'search' } ); - const frag = new ViewDocumentFragment( [ - new ViewText( 'f' ), - new ViewUIElement( 'span', { 'data-marker': 'search' } ), - new ViewText( 'oob' ), - new ViewUIElement( 'span', { 'data-marker': 'search' } ), - new ViewText( 'ar' ) + const frag = new ViewDocumentFragment( viewDocument, [ + new ViewText( viewDocument, 'f' ), + new ViewUIElement( viewDocument, 'span', { 'data-marker': 'search' } ), + new ViewText( viewDocument, 'oob' ), + new ViewUIElement( viewDocument, 'span', { 'data-marker': 'search' } ), + new ViewText( viewDocument, 'ar' ) ] ); const marker = { name: 'search', start: [ 1 ], end: [ 4 ] }; @@ -634,12 +650,12 @@ describe( 'UpcastHelpers', () => { model: viewElement => 'comment:' + viewElement.getAttribute( 'data-comment-id' ) } ); - const frag = new ViewDocumentFragment( [ - new ViewText( 'foo' ), - new ViewUIElement( 'comment', { 'data-comment-id': 4 } ), - new ViewText( 'b' ), - new ViewUIElement( 'comment', { 'data-comment-id': 4 } ), - new ViewText( 'ar' ) + const frag = new ViewDocumentFragment( viewDocument, [ + new ViewText( viewDocument, 'foo' ), + new ViewUIElement( viewDocument, 'comment', { 'data-comment-id': 4 } ), + new ViewText( viewDocument, 'b' ), + new ViewUIElement( viewDocument, 'comment', { 'data-comment-id': 4 } ), + new ViewText( viewDocument, 'ar' ) ] ); const marker = { name: 'comment:4', start: [ 3 ], end: [ 4 ] }; @@ -652,12 +668,12 @@ describe( 'UpcastHelpers', () => { upcastHelpers.elementToMarker( { view: 'marker-search', model: 'search' } ); - const element = new ViewContainerElement( 'p', null, [ - new ViewText( 'fo' ), - new ViewUIElement( 'marker-search' ), - new ViewText( 'oba' ), - new ViewUIElement( 'marker-search' ), - new ViewText( 'r' ) + const element = new ViewContainerElement( viewDocument, 'p', null, [ + new ViewText( viewDocument, 'fo' ), + new ViewUIElement( viewDocument, 'marker-search' ), + new ViewText( viewDocument, 'oba' ), + new ViewUIElement( viewDocument, 'marker-search' ), + new ViewText( viewDocument, 'r' ) ] ); const marker = { name: 'search', start: [ 0, 2 ], end: [ 0, 5 ] }; @@ -683,10 +699,11 @@ describe( 'UpcastHelpers', () => { } ); describe( 'upcast-converters', () => { - let dispatcher, schema, context, model; + let dispatcher, schema, context, model, viewDocument; beforeEach( () => { model = new Model(); + viewDocument = new ViewDocument( new StylesProcessor() ); schema = model.schema; schema.register( 'paragraph', { inheritAllFrom: '$block' } ); @@ -699,7 +716,7 @@ describe( 'upcast-converters', () => { describe( 'convertText()', () => { it( 'should return converter converting ViewText to ModelText', () => { - const viewText = new ViewText( 'foobar' ); + const viewText = new ViewText( viewDocument, 'foobar' ); dispatcher.on( 'text', convertText() ); @@ -711,7 +728,7 @@ describe( 'upcast-converters', () => { } ); it( 'should not convert already consumed texts', () => { - const viewText = new ViewText( 'foofuckbafuckr' ); + const viewText = new ViewText( viewDocument, 'foofuckbafuckr' ); // Default converter for elements. Returns just converted children. Added with lowest priority. dispatcher.on( 'text', convertText(), { priority: 'lowest' } ); @@ -739,7 +756,7 @@ describe( 'upcast-converters', () => { } } ); - const viewText = new ViewText( 'foobar' ); + const viewText = new ViewText( viewDocument, 'foobar' ); dispatcher.on( 'text', convertText() ); let conversionResult = model.change( writer => dispatcher.convert( viewText, writer, context ) ); @@ -755,7 +772,7 @@ describe( 'upcast-converters', () => { } ); it( 'should support unicode', () => { - const viewText = new ViewText( 'நிலைக்கு' ); + const viewText = new ViewText( viewDocument, 'நிலைக்கு' ); dispatcher.on( 'text', convertText() ); @@ -769,9 +786,9 @@ describe( 'upcast-converters', () => { describe( 'convertToModelFragment()', () => { it( 'should return converter converting whole ViewDocumentFragment to ModelDocumentFragment', () => { - const viewFragment = new ViewDocumentFragment( [ - new ViewContainerElement( 'p', null, new ViewText( 'foo' ) ), - new ViewText( 'bar' ) + const viewFragment = new ViewDocumentFragment( viewDocument, [ + new ViewContainerElement( viewDocument, 'p', null, new ViewText( viewDocument, 'foo' ) ), + new ViewText( viewDocument, 'bar' ) ] ); // To get any meaningful results we have to actually convert something. @@ -788,7 +805,7 @@ describe( 'upcast-converters', () => { } ); it( 'should not convert already consumed (converted) changes', () => { - const viewP = new ViewContainerElement( 'p', null, new ViewText( 'foo' ) ); + const viewP = new ViewContainerElement( viewDocument, 'p', null, new ViewText( viewDocument, 'foo' ) ); // To get any meaningful results we have to actually convert something. dispatcher.on( 'text', convertText() ); @@ -818,9 +835,12 @@ describe( 'upcast-converters', () => { it( 'should forward correct modelCursor', () => { const spy = sinon.spy(); - const view = new ViewDocumentFragment( [ - new ViewContainerElement( 'div', null, [ new ViewText( 'abc' ), new ViewContainerElement( 'foo' ) ] ), - new ViewContainerElement( 'bar' ) + const view = new ViewDocumentFragment( viewDocument, [ + new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, 'abc' ), + new ViewContainerElement( viewDocument, 'foo' ) + ] ), + new ViewContainerElement( viewDocument, 'bar' ) ] ); const position = ModelPosition._createAt( new ModelElement( 'element' ), 0 ); @@ -857,7 +877,7 @@ describe( 'upcast-converters', () => { modelSetData( model, 'foobar' ); - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; viewRoot = createViewRoot( viewDocument, 'div', 'main' ); diff --git a/tests/conversion/viewconsumable.js b/tests/conversion/viewconsumable.js index a450f65a5..62d1b7084 100644 --- a/tests/conversion/viewconsumable.js +++ b/tests/conversion/viewconsumable.js @@ -3,21 +3,29 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ +import ViewDocument from '../../src/view/document'; import ViewElement from '../../src/view/element'; import ViewText from '../../src/view/text'; import ViewDocumentFragment from '../../src/view/documentfragment'; import ViewConsumable from '../../src/conversion/viewconsumable'; -import StylesMap, { StylesProcessor } from '../../src/view/stylesmap'; import { addBorderRules } from '../../src/view/styles/border'; import { addMarginRules } from '../../src/view/styles/margin'; import { addPaddingRules } from '../../src/view/styles/padding'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'ViewConsumable', () => { - let viewConsumable, el; + let viewConsumable, el, viewDocument; beforeEach( () => { + const stylesProcessor = new StylesProcessor(); + viewDocument = new ViewDocument( stylesProcessor ); + + addBorderRules( stylesProcessor ); + addMarginRules( stylesProcessor ); + addPaddingRules( stylesProcessor ); + viewConsumable = new ViewConsumable(); - el = new ViewElement( 'p' ); + el = new ViewElement( viewDocument, 'p' ); } ); describe( 'add', () => { @@ -28,14 +36,14 @@ describe( 'ViewConsumable', () => { } ); it( 'should allow to add text node', () => { - const text = new ViewText( 'foobar' ); + const text = new ViewText( viewDocument, 'foobar' ); viewConsumable.add( text ); expect( viewConsumable.test( text ) ).to.be.true; } ); it( 'should allow to add document fragment', () => { - const fragment = new ViewDocumentFragment(); + const fragment = new ViewDocumentFragment( viewDocument ); viewConsumable.add( fragment ); expect( viewConsumable.test( fragment ) ).to.be.true; } ); @@ -102,7 +110,7 @@ describe( 'ViewConsumable', () => { describe( 'test', () => { it( 'should test element name', () => { - const el2 = new ViewElement( 'p' ); + const el2 = new ViewElement( viewDocument, 'p' ); viewConsumable.add( el, { name: true } ); @@ -111,8 +119,8 @@ describe( 'ViewConsumable', () => { } ); it( 'should test text nodes', () => { - const text1 = new ViewText(); - const text2 = new ViewText(); + const text1 = new ViewText( viewDocument ); + const text2 = new ViewText( viewDocument ); viewConsumable.add( text1 ); @@ -121,8 +129,8 @@ describe( 'ViewConsumable', () => { } ); it( 'should test document fragments', () => { - const fragment1 = new ViewDocumentFragment(); - const fragment2 = new ViewDocumentFragment(); + const fragment1 = new ViewDocumentFragment( viewDocument ); + const fragment2 = new ViewDocumentFragment( viewDocument ); viewConsumable.add( fragment1 ); @@ -131,7 +139,7 @@ describe( 'ViewConsumable', () => { } ); it( 'should test attribute, classes and styles', () => { - const el = new ViewElement( 'p' ); + const el = new ViewElement( viewDocument, 'p' ); viewConsumable.add( el, { attributes: 'href', classes: 'foobar', styles: 'color' } ); @@ -241,7 +249,7 @@ describe( 'ViewConsumable', () => { } ); it( 'should consume text node', () => { - const text = new ViewText(); + const text = new ViewText( viewDocument ); viewConsumable.add( text ); const consumed = viewConsumable.consume( text ); expect( consumed ).to.be.true; @@ -250,7 +258,7 @@ describe( 'ViewConsumable', () => { } ); it( 'should consume document fragment', () => { - const fragment = new ViewDocumentFragment(); + const fragment = new ViewDocumentFragment( viewDocument ); viewConsumable.add( fragment ); const consumed = viewConsumable.consume( fragment ); expect( consumed ).to.be.true; @@ -357,8 +365,8 @@ describe( 'ViewConsumable', () => { } ); it( 'should revert text node', () => { - const text1 = new ViewText(); - const text2 = new ViewText(); + const text1 = new ViewText( viewDocument ); + const text2 = new ViewText( viewDocument ); viewConsumable.add( text1 ); viewConsumable.consume( text1 ); @@ -371,8 +379,8 @@ describe( 'ViewConsumable', () => { } ); it( 'should revert document fragment', () => { - const fragment1 = new ViewDocumentFragment(); - const fragment2 = new ViewDocumentFragment(); + const fragment1 = new ViewDocumentFragment( viewDocument ); + const fragment2 = new ViewDocumentFragment( viewDocument ); viewConsumable.add( fragment1 ); viewConsumable.consume( fragment1 ); @@ -528,7 +536,7 @@ describe( 'ViewConsumable', () => { } ); it( 'should return new ViewConsumable instance from document fragment', () => { - const fragment = new ViewDocumentFragment(); + const fragment = new ViewDocumentFragment( viewDocument ); const newConsumable = ViewConsumable.createFrom( fragment ); expect( newConsumable ).to.be.instanceof( ViewConsumable ); @@ -536,11 +544,11 @@ describe( 'ViewConsumable', () => { } ); it( 'should add all child elements', () => { - const text1 = new ViewText( 'foo' ); - const text2 = new ViewText( 'bar' ); - const child1 = new ViewElement( 'p', { 'title': 'baz' }, [ text1 ] ); - const child2 = new ViewElement( 'p' ); - const child3 = new ViewElement( 'p', { 'style': 'top:10px;', 'class': 'qux bar' }, [ text2, child2 ] ); + const text1 = new ViewText( viewDocument, 'foo' ); + const text2 = new ViewText( viewDocument, 'bar' ); + const child1 = new ViewElement( viewDocument, 'p', { 'title': 'baz' }, [ text1 ] ); + const child2 = new ViewElement( viewDocument, 'p' ); + const child3 = new ViewElement( viewDocument, 'p', { 'style': 'top:10px;', 'class': 'qux bar' }, [ text2, child2 ] ); el._appendChild( [ child1, child3 ] ); const newConsumable = ViewConsumable.createFrom( el ); @@ -555,16 +563,6 @@ describe( 'ViewConsumable', () => { } ); describe( 'style shorthands handling', () => { - before( () => { - const stylesProcessor = new StylesProcessor(); - - StylesMap._setProcessor( stylesProcessor ); - - addBorderRules( stylesProcessor ); - addMarginRules( stylesProcessor ); - addPaddingRules( stylesProcessor ); - } ); - describe( 'add', () => { it( 'should add padding shorthands', () => { viewConsumable.add( el, { styles: [ 'margin' ] } ); diff --git a/tests/dataprocessor/htmldataprocessor.js b/tests/dataprocessor/htmldataprocessor.js index acb0f8c3c..644b8f6d4 100644 --- a/tests/dataprocessor/htmldataprocessor.js +++ b/tests/dataprocessor/htmldataprocessor.js @@ -9,9 +9,16 @@ import HtmlDataProcessor from '../../src/dataprocessor/htmldataprocessor'; import xssTemplates from '../../tests/dataprocessor/_utils/xsstemplates'; import ViewDocumentFragment from '../../src/view/documentfragment'; import { stringify, parse } from '../../src/dev-utils/view'; +import { StylesProcessor } from '../../src/view/stylesmap'; +import ViewDocument from '../../src/view/document'; describe( 'HtmlDataProcessor', () => { - const dataProcessor = new HtmlDataProcessor(); + let dataProcessor, viewDocument; + + beforeEach( () => { + viewDocument = new ViewDocument( new StylesProcessor() ); + dataProcessor = new HtmlDataProcessor( viewDocument ); + } ); describe( 'toView()', () => { it( 'should return empty DocumentFragment when empty string is passed', () => { @@ -89,13 +96,13 @@ describe( 'HtmlDataProcessor', () => { describe( 'toData()', () => { it( 'should return empty string when empty DocumentFragment is passed', () => { - const fragment = new ViewDocumentFragment(); + const fragment = new ViewDocumentFragment( viewDocument ); expect( dataProcessor.toData( fragment ) ).to.equal( '' ); } ); it( 'should return text if document fragment with single text node is passed', () => { - const fragment = new ViewDocumentFragment(); + const fragment = new ViewDocumentFragment( viewDocument ); fragment._appendChild( parse( 'foo bar' ) ); expect( dataProcessor.toData( fragment ) ).to.equal( 'foo bar' ); diff --git a/tests/dataprocessor/xmldataprocessor.js b/tests/dataprocessor/xmldataprocessor.js index efa678ee7..b262eb4b8 100644 --- a/tests/dataprocessor/xmldataprocessor.js +++ b/tests/dataprocessor/xmldataprocessor.js @@ -8,13 +8,16 @@ import XmlDataProcessor from '../../src/dataprocessor/xmldataprocessor'; import xssTemplates from '../../tests/dataprocessor/_utils/xsstemplates'; import ViewDocumentFragment from '../../src/view/documentfragment'; +import ViewDocument from '../../src/view/document'; import { stringify, parse } from '../../src/dev-utils/view'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'XmlDataProcessor', () => { - let dataProcessor; + let dataProcessor, viewDocument; beforeEach( () => { - dataProcessor = new XmlDataProcessor(); + viewDocument = new ViewDocument( new StylesProcessor() ); + dataProcessor = new XmlDataProcessor( viewDocument ); } ); describe( 'toView', () => { @@ -43,7 +46,7 @@ describe( 'XmlDataProcessor', () => { } ); it( 'should allow to use registered namespaces', () => { - dataProcessor = new XmlDataProcessor( { + dataProcessor = new XmlDataProcessor( viewDocument, { namespaces: [ 'foo', 'bar' ] } ); @@ -82,13 +85,13 @@ describe( 'XmlDataProcessor', () => { describe( 'toData', () => { it( 'should return empty string when empty DocumentFragment is passed', () => { - const fragment = new ViewDocumentFragment(); + const fragment = new ViewDocumentFragment( viewDocument ); expect( dataProcessor.toData( fragment ) ).to.equal( '' ); } ); it( 'should return text if document fragment with single text node is passed', () => { - const fragment = new ViewDocumentFragment(); + const fragment = new ViewDocumentFragment( viewDocument ); fragment._appendChild( parse( 'foo bar' ) ); expect( dataProcessor.toData( fragment ) ).to.equal( 'foo bar' ); diff --git a/tests/dev-utils/view.js b/tests/dev-utils/view.js index 87d2b665f..27ee96320 100644 --- a/tests/dev-utils/view.js +++ b/tests/dev-utils/view.js @@ -6,6 +6,7 @@ /* globals document */ import { parse, stringify, getData, setData } from '../../src/dev-utils/view'; +import ViewDocument from '../../src/view/document'; import DocumentFragment from '../../src/view/documentfragment'; import Position from '../../src/view/position'; import Element from '../../src/view/element'; @@ -19,6 +20,7 @@ import Range from '../../src/view/range'; import View from '../../src/view/view'; import XmlDataProcessor from '../../src/dataprocessor/xmldataprocessor'; import createViewRoot from '../view/_utils/createroot'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'view test utils', () => { describe( 'getData, setData', () => { @@ -30,7 +32,7 @@ describe( 'view test utils', () => { it( 'should use stringify method', () => { const element = document.createElement( 'div' ); const stringifySpy = sinon.spy( getData, '_stringify' ); - const view = new View(); + const view = new View( new StylesProcessor() ); const viewDocument = view.document; const options = { showType: false, @@ -39,7 +41,7 @@ describe( 'view test utils', () => { renderUIElements: false }; const root = createAttachedRoot( viewDocument, element ); - root._appendChild( new Element( 'p' ) ); + root._appendChild( new Element( viewDocument, 'p' ) ); expect( getData( view, options ) ).to.equal( '

' ); sinon.assert.calledOnce( stringifySpy ); @@ -57,11 +59,11 @@ describe( 'view test utils', () => { it( 'should use stringify method with selection', () => { const element = document.createElement( 'div' ); const stringifySpy = sinon.spy( getData, '_stringify' ); - const view = new View(); + const view = new View( new StylesProcessor() ); const viewDocument = view.document; const options = { showType: false, showPriority: false }; const root = createAttachedRoot( viewDocument, element ); - root._appendChild( new Element( 'p' ) ); + root._appendChild( new Element( viewDocument, 'p' ) ); view.change( writer => { writer.setSelection( Range._createFromParentsAndOffsets( root, 0, root, 1 ) ); @@ -88,7 +90,7 @@ describe( 'view test utils', () => { describe( 'setData', () => { it( 'should use parse method', () => { - const view = new View(); + const view = new View( new StylesProcessor() ); const viewDocument = view.document; const data = 'foobarbaz'; const parseSpy = sinon.spy( setData, '_parse' ); @@ -107,7 +109,7 @@ describe( 'view test utils', () => { } ); it( 'should use parse method with selection', () => { - const view = new View(); + const view = new View( new StylesProcessor() ); const viewDocument = view.document; const data = '[baz]'; const parseSpy = sinon.spy( setData, '_parse' ); @@ -133,25 +135,31 @@ describe( 'view test utils', () => { } ); describe( 'stringify', () => { + let viewDocument; + + beforeEach( () => { + viewDocument = new ViewDocument( new StylesProcessor() ); + } ); + it( 'should write text', () => { - const text = new Text( 'foobar' ); + const text = new Text( viewDocument, 'foobar' ); expect( stringify( text ) ).to.equal( 'foobar' ); } ); it( 'should write elements and texts', () => { - const text = new Text( 'foobar' ); - const b = new Element( 'b', null, text ); - const p = new Element( 'p', null, b ); + const text = new Text( viewDocument, 'foobar' ); + const b = new Element( viewDocument, 'b', null, text ); + const p = new Element( viewDocument, 'p', null, b ); expect( stringify( p ) ).to.equal( '

foobar

' ); } ); it( 'should write elements with attributes (attributes in alphabetical order)', () => { - const text = new Text( 'foobar' ); - const b = new Element( 'b', { + const text = new Text( viewDocument, 'foobar' ); + const b = new Element( viewDocument, 'b', { foo: 'bar' }, text ); - const p = new Element( 'p', { + const p = new Element( viewDocument, 'p', { baz: 'qux', bar: 'taz', class: 'short wide' @@ -161,20 +169,20 @@ describe( 'view test utils', () => { } ); it( 'should write selection ranges inside elements', () => { - const text1 = new Text( 'foobar' ); - const text2 = new Text( 'bazqux' ); - const b1 = new Element( 'b', null, text1 ); - const b2 = new Element( 'b', null, text2 ); - const p = new Element( 'p', null, [ b1, b2 ] ); + const text1 = new Text( viewDocument, 'foobar' ); + const text2 = new Text( viewDocument, 'bazqux' ); + const b1 = new Element( viewDocument, 'b', null, text1 ); + const b2 = new Element( viewDocument, 'b', null, text2 ); + const p = new Element( viewDocument, 'p', null, [ b1, b2 ] ); const range = Range._createFromParentsAndOffsets( p, 1, p, 2 ); const selection = new DocumentSelection( [ range ] ); expect( stringify( p, selection ) ).to.equal( '

foobar[bazqux]

' ); } ); it( 'should support unicode', () => { - const text = new Text( 'நிலைக்கு' ); - const b = new Element( 'b', null, text ); - const p = new Element( 'p', null, b ); + const text = new Text( viewDocument, 'நிலைக்கு' ); + const b = new Element( viewDocument, 'b', null, text ); + const p = new Element( viewDocument, 'p', null, b ); const range = Range._createFromParentsAndOffsets( p, 0, text, 4 ); const selection = new DocumentSelection( [ range ] ); @@ -182,30 +190,30 @@ describe( 'view test utils', () => { } ); it( 'should write collapsed selection ranges inside elements', () => { - const text = new Text( 'foobar' ); - const p = new Element( 'p', null, text ); + const text = new Text( viewDocument, 'foobar' ); + const p = new Element( viewDocument, 'p', null, text ); const range = Range._createFromParentsAndOffsets( p, 0, p, 0 ); const selection = new DocumentSelection( [ range ] ); expect( stringify( p, selection ) ).to.equal( '

[]foobar

' ); } ); it( 'should write selection ranges inside text', () => { - const text1 = new Text( 'foobar' ); - const text2 = new Text( 'bazqux' ); - const b1 = new Element( 'b', null, text1 ); - const b2 = new Element( 'b', null, text2 ); - const p = new Element( 'p', null, [ b1, b2 ] ); + const text1 = new Text( viewDocument, 'foobar' ); + const text2 = new Text( viewDocument, 'bazqux' ); + const b1 = new Element( viewDocument, 'b', null, text1 ); + const b2 = new Element( viewDocument, 'b', null, text2 ); + const p = new Element( viewDocument, 'p', null, [ b1, b2 ] ); const range = Range._createFromParentsAndOffsets( text1, 1, text1, 5 ); const selection = new DocumentSelection( [ range ] ); expect( stringify( p, selection ) ).to.equal( '

f{ooba}rbazqux

' ); } ); it( 'should write selection ranges inside text represented by `[` and `]` characters', () => { - const text1 = new Text( 'foobar' ); - const text2 = new Text( 'bazqux' ); - const b1 = new Element( 'b', null, text1 ); - const b2 = new Element( 'b', null, text2 ); - const p = new Element( 'p', null, [ b1, b2 ] ); + const text1 = new Text( viewDocument, 'foobar' ); + const text2 = new Text( viewDocument, 'bazqux' ); + const b1 = new Element( viewDocument, 'b', null, text1 ); + const b2 = new Element( viewDocument, 'b', null, text2 ); + const p = new Element( viewDocument, 'p', null, [ b1, b2 ] ); const range = Range._createFromParentsAndOffsets( text1, 1, text1, 5 ); const selection = new DocumentSelection( [ range ] ); expect( stringify( p, selection, { sameSelectionCharacters: true } ) ) @@ -213,108 +221,108 @@ describe( 'view test utils', () => { } ); it( 'should write collapsed selection ranges inside texts', () => { - const text = new Text( 'foobar' ); - const p = new Element( 'p', null, text ); + const text = new Text( viewDocument, 'foobar' ); + const p = new Element( viewDocument, 'p', null, text ); const range = Range._createFromParentsAndOffsets( text, 0, text, 0 ); const selection = new DocumentSelection( [ range ] ); expect( stringify( p, selection ) ).to.equal( '

{}foobar

' ); } ); it( 'should write ranges that start inside text end ends between elements', () => { - const text1 = new Text( 'foobar' ); - const text2 = new Text( 'bazqux' ); - const b1 = new Element( 'b', null, text1 ); - const b2 = new Element( 'b', null, text2 ); - const p = new Element( 'p', null, [ b1, b2 ] ); + const text1 = new Text( viewDocument, 'foobar' ); + const text2 = new Text( viewDocument, 'bazqux' ); + const b1 = new Element( viewDocument, 'b', null, text1 ); + const b2 = new Element( viewDocument, 'b', null, text2 ); + const p = new Element( viewDocument, 'p', null, [ b1, b2 ] ); const range = Range._createFromParentsAndOffsets( p, 0, text2, 5 ); const selection = new DocumentSelection( [ range ] ); expect( stringify( p, selection ) ).to.equal( '

[foobarbazqu}x

' ); } ); it( 'should write elements types as namespaces when needed', () => { - const text = new Text( 'foobar' ); - const b = new AttributeElement( 'b', null, text ); - const p = new ContainerElement( 'p', null, b ); + const text = new Text( viewDocument, 'foobar' ); + const b = new AttributeElement( viewDocument, 'b', null, text ); + const p = new ContainerElement( viewDocument, 'p', null, b ); expect( stringify( p, null, { showType: true } ) ) .to.equal( 'foobar' ); } ); it( 'should not write element type when type is not specified', () => { - const p = new Element( 'p' ); + const p = new Element( viewDocument, 'p' ); expect( stringify( p, null, { showType: true } ) ).to.equal( '

' ); } ); it( 'should write elements priorities when needed', () => { - const text = new Text( 'foobar' ); - const b = new AttributeElement( 'b', null, text ); - const p = new ContainerElement( 'p', null, b ); + const text = new Text( viewDocument, 'foobar' ); + const b = new AttributeElement( viewDocument, 'b', null, text ); + const p = new ContainerElement( viewDocument, 'p', null, b ); expect( stringify( p, null, { showPriority: true } ) ) .to.equal( '

foobar

' ); } ); it( 'should write elements id when needed', () => { - const text = new Text( 'foobar' ); - const span = new AttributeElement( 'span', null, text ); + const text = new Text( viewDocument, 'foobar' ); + const span = new AttributeElement( viewDocument, 'span', null, text ); span._id = 'foo'; - const p = new ContainerElement( 'p', null, span ); + const p = new ContainerElement( viewDocument, 'p', null, span ); expect( stringify( p, null, { showAttributeElementId: true } ) ) .to.equal( '

foobar

' ); } ); it( 'should parse DocumentFragment as root', () => { - const text1 = new Text( 'foobar' ); - const text2 = new Text( 'bazqux' ); - const b1 = new Element( 'b', null, text1 ); - const b2 = new Element( 'b', null, text2 ); - const fragment = new DocumentFragment( [ b1, b2 ] ); + const text1 = new Text( viewDocument, 'foobar' ); + const text2 = new Text( viewDocument, 'bazqux' ); + const b1 = new Element( viewDocument, 'b', null, text1 ); + const b2 = new Element( viewDocument, 'b', null, text2 ); + const fragment = new DocumentFragment( viewDocument, [ b1, b2 ] ); expect( stringify( fragment, null ) ).to.equal( 'foobarbazqux' ); } ); it( 'should not write ranges outside elements - end position outside element', () => { - const text = new Text( 'foobar' ); - const b = new Element( 'b', null, text ); - const p = new Element( 'p', null, b ); + const text = new Text( viewDocument, 'foobar' ); + const b = new Element( viewDocument, 'b', null, text ); + const p = new Element( viewDocument, 'p', null, b ); const range = Range._createFromParentsAndOffsets( p, 0, p, 5 ); expect( stringify( p, range ) ).to.equal( '

[foobar

' ); } ); it( 'should not write ranges outside elements - start position outside element', () => { - const text = new Text( 'foobar' ); - const b = new Element( 'b', null, text ); - const p = new Element( 'p', null, b ); + const text = new Text( viewDocument, 'foobar' ); + const b = new Element( viewDocument, 'b', null, text ); + const p = new Element( viewDocument, 'p', null, b ); const range = Range._createFromParentsAndOffsets( p, -1, p, 1 ); expect( stringify( p, range ) ).to.equal( '

foobar]

' ); } ); it( 'should not write ranges outside elements - end position outside text', () => { - const text = new Text( 'foobar' ); - const b = new Element( 'b', null, text ); - const p = new Element( 'p', null, b ); + const text = new Text( viewDocument, 'foobar' ); + const b = new Element( viewDocument, 'b', null, text ); + const p = new Element( viewDocument, 'p', null, b ); const range = Range._createFromParentsAndOffsets( text, 0, text, 7 ); expect( stringify( p, range ) ).to.equal( '

{foobar

' ); } ); it( 'should not write ranges outside elements - start position outside text', () => { - const text = new Text( 'foobar' ); - const b = new Element( 'b', null, text ); - const p = new Element( 'p', null, b ); + const text = new Text( viewDocument, 'foobar' ); + const b = new Element( viewDocument, 'b', null, text ); + const p = new Element( viewDocument, 'p', null, b ); const range = Range._createFromParentsAndOffsets( text, -1, text, 2 ); expect( stringify( p, range ) ).to.equal( '

fo}obar

' ); } ); it( 'should write multiple ranges from selection #1', () => { - const text1 = new Text( 'foobar' ); - const text2 = new Text( 'bazqux' ); - const b1 = new Element( 'b', null, text1 ); - const b2 = new Element( 'b', null, text2 ); - const p = new Element( 'p', null, [ b1, b2 ] ); + const text1 = new Text( viewDocument, 'foobar' ); + const text2 = new Text( viewDocument, 'bazqux' ); + const b1 = new Element( viewDocument, 'b', null, text1 ); + const b2 = new Element( viewDocument, 'b', null, text2 ); + const p = new Element( viewDocument, 'p', null, [ b1, b2 ] ); const range1 = Range._createFromParentsAndOffsets( p, 0, p, 1 ); const range2 = Range._createFromParentsAndOffsets( p, 1, p, 1 ); const selection = new DocumentSelection( [ range2, range1 ] ); @@ -323,10 +331,10 @@ describe( 'view test utils', () => { } ); it( 'should write multiple ranges from selection #2', () => { - const text1 = new Text( 'foobar' ); - const text2 = new Text( 'bazqux' ); - const b = new Element( 'b', null, text1 ); - const p = new Element( 'p', null, [ b, text2 ] ); + const text1 = new Text( viewDocument, 'foobar' ); + const text2 = new Text( viewDocument, 'bazqux' ); + const b = new Element( viewDocument, 'b', null, text1 ); + const p = new Element( viewDocument, 'p', null, [ b, text2 ] ); const range1 = Range._createFromParentsAndOffsets( p, 0, p, 1 ); const range2 = Range._createFromParentsAndOffsets( text2, 0, text2, 3 ); const range3 = Range._createFromParentsAndOffsets( text2, 3, text2, 4 ); @@ -337,35 +345,35 @@ describe( 'view test utils', () => { } ); it( 'should use Position instance instead of Selection', () => { - const text = new Text( 'foobar' ); + const text = new Text( viewDocument, 'foobar' ); const position = new Position( text, 3 ); const string = stringify( text, position ); expect( string ).to.equal( 'foo{}bar' ); } ); it( 'should use Range instance instead of Selection', () => { - const text = new Text( 'foobar' ); + const text = new Text( viewDocument, 'foobar' ); const range = Range._createFromParentsAndOffsets( text, 3, text, 4 ); const string = stringify( text, range ); expect( string ).to.equal( 'foo{b}ar' ); } ); it( 'should stringify EmptyElement', () => { - const img = new EmptyElement( 'img' ); - const p = new ContainerElement( 'p', null, img ); + const img = new EmptyElement( viewDocument, 'img' ); + const p = new ContainerElement( viewDocument, 'p', null, img ); expect( stringify( p, null, { showType: true } ) ) .to.equal( '' ); } ); it( 'should stringify UIElement', () => { - const span = new UIElement( 'span' ); - const p = new ContainerElement( 'p', null, span ); + const span = new UIElement( viewDocument, 'span' ); + const p = new ContainerElement( viewDocument, 'p', null, span ); expect( stringify( p, null, { showType: true } ) ) .to.equal( '' ); } ); it( 'should not stringify inner UIElement content (renderUIElements=false)', () => { - const span = new UIElement( 'span' ); + const span = new UIElement( viewDocument, 'span' ); span.render = function( domDocument ) { const domElement = this.toDomElement( domDocument ); @@ -375,13 +383,13 @@ describe( 'view test utils', () => { return domElement; }; - const p = new ContainerElement( 'p', null, span ); + const p = new ContainerElement( viewDocument, 'p', null, span ); expect( stringify( p, null, { showType: true } ) ) .to.equal( '' ); } ); it( 'should stringify UIElement, (renderUIElements=true)', () => { - const span = new UIElement( 'span' ); + const span = new UIElement( viewDocument, 'span' ); span.render = function( domDocument ) { const domElement = this.toDomElement( domDocument ); @@ -391,14 +399,14 @@ describe( 'view test utils', () => { return domElement; }; - const p = new ContainerElement( 'p', null, span ); + const p = new ContainerElement( viewDocument, 'p', null, span ); expect( stringify( p, null, { showType: true, renderUIElements: true } ) ) .to.equal( 'foo' ); } ); it( 'should sort classes in specified element', () => { - const text = new Text( 'foobar' ); - const b = new Element( 'b', { + const text = new Text( viewDocument, 'foobar' ); + const b = new Element( viewDocument, 'b', { class: 'zz xx aa' }, text ); @@ -406,8 +414,8 @@ describe( 'view test utils', () => { } ); it( 'should sort styles in specified element', () => { - const text = new Text( 'foobar' ); - const i = new Element( 'i', { + const text = new Text( viewDocument, 'foobar' ); + const i = new Element( viewDocument, 'i', { style: 'text-decoration: underline; font-weight: bold' }, text ); @@ -416,6 +424,12 @@ describe( 'view test utils', () => { } ); describe( 'parse', () => { + let viewDocument; + + beforeEach( () => { + viewDocument = new ViewDocument( new StylesProcessor() ); + } ); + it( 'should return empty DocumentFragment for empty string', () => { const fragment = parse( '' ); @@ -445,8 +459,8 @@ describe( 'view test utils', () => { const view = parse( '' ); expect( view ).to.be.instanceOf( DocumentFragment ); expect( view.childCount ).to.equal( 2 ); - expect( view.getChild( 0 ).isSimilar( new Element( 'b' ) ) ).to.be.true; - expect( view.getChild( 1 ).isSimilar( new Element( 'i' ) ) ).to.be.true; + expect( view.getChild( 0 ).isSimilar( new Element( viewDocument, 'b' ) ) ).to.be.true; + expect( view.getChild( 1 ).isSimilar( new Element( viewDocument, 'i' ) ) ).to.be.true; } ); it( 'should parse text', () => { @@ -463,7 +477,7 @@ describe( 'view test utils', () => { it( 'should parse elements and texts', () => { const view = parse( 'foobar' ); - const element = new Element( 'b' ); + const element = new Element( viewDocument, 'b' ); expect( view ).to.be.instanceof( Element ); expect( view.isSimilar( element ) ).to.be.true; @@ -475,7 +489,7 @@ describe( 'view test utils', () => { it( 'should parse element attributes', () => { const view = parse( '' ); - const element = new Element( 'b', { name: 'foo', title: 'bar', class: 'foo bar', style: 'color:red;' } ); + const element = new Element( viewDocument, 'b', { name: 'foo', title: 'bar', class: 'foo bar', style: 'color:red;' } ); expect( view ).to.be.instanceof( Element ); expect( view.isSimilar( element ) ).to.be.true; @@ -484,9 +498,9 @@ describe( 'view test utils', () => { it( 'should parse element type', () => { const view1 = parse( '' ); - const attribute = new AttributeElement( 'b' ); + const attribute = new AttributeElement( viewDocument, 'b' ); const view2 = parse( '' ); - const container = new ContainerElement( 'p' ); + const container = new ContainerElement( viewDocument, 'p' ); expect( view1 ).to.be.instanceof( AttributeElement ); expect( view1.isSimilar( attribute ) ).to.be.true; @@ -496,10 +510,10 @@ describe( 'view test utils', () => { it( 'should parse element priority', () => { const parsed1 = parse( '' ); - const attribute1 = new AttributeElement( 'b' ); + const attribute1 = new AttributeElement( viewDocument, 'b' ); attribute1._priority = 12; const parsed2 = parse( '' ); - const attribute2 = new AttributeElement( 'b' ); + const attribute2 = new AttributeElement( viewDocument, 'b' ); attribute2._priority = 44; parsed1.isSimilar( attribute1 ); @@ -517,7 +531,7 @@ describe( 'view test utils', () => { it( 'should paste nested elements and texts', () => { const parsed = parse( 'foobarqux' ); - expect( parsed.isSimilar( new ContainerElement( 'p' ) ) ).to.be.true; + expect( parsed.isSimilar( new ContainerElement( viewDocument, 'p' ) ) ).to.be.true; expect( parsed.childCount ).to.equal( 2 ); expect( parsed.getChild( 0 ) ).to.be.instanceof( Text ).and.have.property( 'data' ).that.equal( 'foo' ); const b = parsed.getChild( 1 ); @@ -584,7 +598,7 @@ describe( 'view test utils', () => { it( 'should parse ranges #1', () => { const { view, selection } = parse( 'foo{bar]' ); - expect( view.isSimilar( new ContainerElement( 'p' ) ) ).to.be.true; + expect( view.isSimilar( new ContainerElement( viewDocument, 'p' ) ) ).to.be.true; expect( view.childCount ).to.equal( 1 ); const text = view.getChild( 0 ); expect( text ).to.be.instanceof( Text ); @@ -595,13 +609,13 @@ describe( 'view test utils', () => { it( 'should parse ranges #2', () => { const { view, selection } = parse( '[foob}ar{baz]' ); - expect( view.isSimilar( new AttributeElement( 'b' ) ) ).to.be.true; + expect( view.isSimilar( new AttributeElement( viewDocument, 'b' ) ) ).to.be.true; expect( view.childCount ).to.equal( 2 ); const text1 = view.getChild( 0 ); expect( text1 ).to.be.instanceof( Text ); expect( text1.data ).to.equal( 'foobar' ); const i = view.getChild( 1 ); - expect( i.isSimilar( new Element( 'i' ) ) ).to.be.true; + expect( i.isSimilar( new Element( viewDocument, 'i' ) ) ).to.be.true; expect( i.childCount ).to.equal( 1 ); const text2 = i.getChild( 0 ); expect( text2 ).to.be.instanceof( Text ); @@ -677,7 +691,7 @@ describe( 'view test utils', () => { } ); it( 'should throw when wrong type is provided', () => { - sinon.stub( XmlDataProcessor.prototype, 'toView' ).returns( new ContainerElement( 'invalidType:b' ) ); + sinon.stub( XmlDataProcessor.prototype, 'toView' ).returns( new ContainerElement( viewDocument, 'invalidType:b' ) ); expect( () => { parse( 'sth' ); @@ -687,14 +701,14 @@ describe( 'view test utils', () => { } ); it( 'should use provided root element #1', () => { - const root = new Element( 'p' ); + const root = new Element( viewDocument, 'p' ); const data = parse( 'text', { rootElement: root } ); expect( stringify( data ) ).to.equal( '

text

' ); } ); it( 'should use provided root element #2', () => { - const root = new Element( 'p' ); + const root = new Element( viewDocument, 'p' ); const data = parse( 'texttest', { rootElement: root } ); expect( stringify( data ) ).to.equal( '

texttest

' ); diff --git a/tests/model/node.js b/tests/model/node.js index 4284c5ecb..965df900b 100644 --- a/tests/model/node.js +++ b/tests/model/node.js @@ -8,8 +8,10 @@ import DocumentFragment from '../../src/model/documentfragment'; import Node from '../../src/model/node'; import Element from '../../src/model/element'; import Text from '../../src/model/text'; +import RootElement from '../../src/model/rootelement'; import count from '@ckeditor/ckeditor5-utils/src/count'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor'; describe( 'Node', () => { let doc, root, node, @@ -75,25 +77,6 @@ describe( 'Node', () => { expect( node ).to.have.property( 'previousSibling' ).that.is.null; } ); - - it( 'document', () => { - expect( root ).to.have.property( 'document' ).that.equals( doc ); - - expect( one ).to.have.property( 'document' ).that.equals( doc ); - expect( two ).to.have.property( 'document' ).that.equals( doc ); - expect( three ).to.have.property( 'document' ).that.equals( doc ); - - expect( textBA ).to.have.property( 'document' ).that.equals( doc ); - expect( img ).to.have.property( 'document' ).that.equals( doc ); - expect( textR ).to.have.property( 'document' ).that.equals( doc ); - - expect( node ).to.have.property( 'document' ).that.is.null; - - // DocumentFragment does not have document property, so node's document property should be null. - const docFrag = new DocumentFragment(); - docFrag._appendChild( node ); - expect( node ).to.have.property( 'document' ).that.is.null; - } ); } ); describe( 'constructor()', () => { @@ -405,6 +388,55 @@ describe( 'Node', () => { } ); } ); + describe( 'isAttached()', () => { + it( 'returns false for a fresh node', () => { + const char = new Text( 'x' ); + const el = new Element( 'one' ); + + expect( char.isAttached() ).to.equal( false ); + expect( el.isAttached() ).to.equal( false ); + } ); + + it( 'returns true for the root element', () => { + const model = new Model(); + const root = new RootElement( model.document, 'root' ); + + expect( root.isAttached() ).to.equal( true ); + } ); + + it( 'returns false for a node attached to a document fragment', () => { + const foo = new Text( 'foo' ); + new DocumentFragment( [ foo ] ); // eslint-disable-line no-new + + expect( foo.isAttached() ).to.equal( false ); + } ); + + it( 'returns true for a node moved to graveyard', () => { + return ModelTestEditor.create() + .then( editor => { + const model = editor.model; + const root = model.document.getRoot(); + + // Allow "paragraph" element to be added as a child in block elements. + model.schema.register( 'paragraph', { inheritAllFrom: '$block' } ); + + const node = model.change( writer => writer.createElement( 'paragraph' ) ); + + expect( node.isAttached() ).to.equal( false ); + + model.change( writer => writer.append( node, root ) ); + + expect( node.isAttached() ).to.equal( true ); + + model.change( writer => writer.remove( node ) ); + + expect( node.isAttached() ).to.equal( true ); + + return editor.destroy(); + } ); + } ); + } ); + describe( 'attributes interface', () => { const node = new Node( { foo: 'bar' } ); diff --git a/tests/model/textproxy.js b/tests/model/textproxy.js index c5c8938d6..294ea2b85 100644 --- a/tests/model/textproxy.js +++ b/tests/model/textproxy.js @@ -38,11 +38,6 @@ describe( 'TextProxy', () => { expect( textProxyNoParent ).to.have.property( 'root' ).that.equals( textNoParent ); } ); - it( 'should have document property', () => { - expect( textProxy ).to.have.property( 'document' ).that.equals( doc ); - expect( textProxyNoParent ).to.have.property( 'document' ).that.equals( null ); - } ); - it( 'should have parent property', () => { expect( textProxy ).to.have.property( 'parent' ).that.equals( element ); expect( textProxyNoParent ).to.have.property( 'parent' ).that.equals( null ); diff --git a/tests/tickets/1323.js b/tests/tickets/1323.js index 36f3c5826..de86e04f1 100644 --- a/tests/tickets/1323.js +++ b/tests/tickets/1323.js @@ -9,6 +9,7 @@ import Model from '../../src/model/model'; import ModelText from '../../src/model/text'; import MarkerOperation from '../../src/model/operation/markeroperation'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'Bug ckeditor5-engine@1323', () => { describe( 'constructor()', () => { @@ -16,7 +17,7 @@ describe( 'Bug ckeditor5-engine@1323', () => { beforeEach( () => { model = new Model(); - editing = new EditingController( model ); + editing = new EditingController( model, new StylesProcessor() ); root = model.document.createRoot(); root._appendChild( new ModelText( 'foo' ) ); range = model.createRange( model.createPositionAt( root, 0 ), model.createPositionAt( root, 0 ) ); diff --git a/tests/view/_utils/createdocumentmock.js b/tests/view/_utils/createdocumentmock.js index 43ecbebc0..05e645b91 100644 --- a/tests/view/_utils/createdocumentmock.js +++ b/tests/view/_utils/createdocumentmock.js @@ -5,6 +5,7 @@ import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin'; import DocumentSelection from '../../../src/view/documentselection'; +import { StylesProcessor } from '../../../src/view/stylesmap'; /** * Creates {@link module:engine/view/document~Document view Document} mock. @@ -16,6 +17,7 @@ export default function createDocumentMock() { doc.set( 'isFocused', false ); doc.set( 'isReadOnly', false ); doc.selection = new DocumentSelection(); + doc.stylesProcessor = new StylesProcessor(); return doc; } diff --git a/tests/view/_utils/createroot.js b/tests/view/_utils/createroot.js index a470bdbb7..fc7c98b0b 100644 --- a/tests/view/_utils/createroot.js +++ b/tests/view/_utils/createroot.js @@ -14,9 +14,8 @@ import RootEditableElement from '../../../src/view/rooteditableelement'; * @returns {module:engine/view/rooteditableelement~RootEditableElement} Root element. */ export default function createRoot( doc, name = 'div', rootName = 'main' ) { - const root = new RootEditableElement( name ); + const root = new RootEditableElement( doc, name ); - root._document = doc; root.rootName = rootName; doc.roots.add( root ); diff --git a/tests/view/attributeelement.js b/tests/view/attributeelement.js index e26dbc8de..d565c9272 100644 --- a/tests/view/attributeelement.js +++ b/tests/view/attributeelement.js @@ -5,14 +5,21 @@ import AttributeElement from '../../src/view/attributeelement'; import Element from '../../src/view/element'; +import Document from '../../src/view/document'; import { parse } from '../../src/dev-utils/view'; - import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'AttributeElement', () => { + let document; + + beforeEach( () => { + document = new Document( new StylesProcessor() ); + } ); + describe( 'constructor()', () => { it( 'should create element with default priority', () => { - const el = new AttributeElement( 'strong' ); + const el = new AttributeElement( document, 'strong' ); expect( el ).to.be.an.instanceof( AttributeElement ); expect( el ).to.be.an.instanceof( Element ); @@ -25,7 +32,7 @@ describe( 'AttributeElement', () => { let el; before( () => { - el = new AttributeElement( 'span' ); + el = new AttributeElement( document, 'span' ); } ); it( 'should return true for attributeElement/element, also with correct name and element name', () => { @@ -60,7 +67,7 @@ describe( 'AttributeElement', () => { describe( '_clone()', () => { it( 'should clone element with priority', () => { - const el = new AttributeElement( 'b' ); + const el = new AttributeElement( document, 'b' ); el._priority = 7; const clone = el._clone(); @@ -73,32 +80,32 @@ describe( 'AttributeElement', () => { describe( 'isSimilar', () => { it( 'should return true if priorities are the same', () => { - const b1 = new AttributeElement( 'b' ); + const b1 = new AttributeElement( document, 'b' ); b1._priority = 7; - const b2 = new AttributeElement( 'b' ); + const b2 = new AttributeElement( document, 'b' ); b2._priority = 7; expect( b1.isSimilar( b2 ) ).to.be.true; } ); it( 'should return false if priorities are different', () => { - const b1 = new AttributeElement( 'b' ); + const b1 = new AttributeElement( document, 'b' ); b1._priority = 7; - const b2 = new AttributeElement( 'b' ); // default priority + const b2 = new AttributeElement( document, 'b' ); // default priority expect( b1.isSimilar( b2 ) ).to.be.false; } ); it( 'should return true if ids are the same even if other properties are different', () => { - const element1 = new AttributeElement( 'b' ); + const element1 = new AttributeElement( document, 'b' ); element1._id = 'xyz'; - const element2 = new AttributeElement( 'b', { foo: 'bar' } ); + const element2 = new AttributeElement( document, 'b', { foo: 'bar' } ); element2._id = 'xyz'; - const element3 = new AttributeElement( 'span' ); + const element3 = new AttributeElement( document, 'span' ); element3._id = 'xyz'; expect( element1.isSimilar( element2 ) ).to.be.true; @@ -106,11 +113,11 @@ describe( 'AttributeElement', () => { } ); it( 'should return false if ids are different even if other properties are same', () => { - const element1 = new AttributeElement( 'span', { foo: 'bar' } ); + const element1 = new AttributeElement( document, 'span', { foo: 'bar' } ); element1._priority = 3; element1._id = 'foo'; - const element2 = new AttributeElement( 'span', { foo: 'bar' } ); + const element2 = new AttributeElement( document, 'span', { foo: 'bar' } ); element2._priority = 3; element2._id = 'bar'; @@ -121,8 +128,8 @@ describe( 'AttributeElement', () => { // More tests are available in DowncastWriter tests. describe( 'getElementsWithSameId', () => { it( 'should return a copy of _clonesGroup set', () => { - const attributeA = new AttributeElement( 'b' ); - const attributeB = new AttributeElement( 'b' ); + const attributeA = new AttributeElement( document, 'b' ); + const attributeB = new AttributeElement( document, 'b' ); attributeA._id = 'foo'; attributeB._id = 'foo'; @@ -135,7 +142,7 @@ describe( 'AttributeElement', () => { } ); it( 'should throw if attribute element has no id', () => { - const attribute = new AttributeElement( 'b' ); + const attribute = new AttributeElement( document, 'b' ); expectToThrowCKEditorError( () => { attribute.getElementsWithSameId(); @@ -194,14 +201,15 @@ describe( 'AttributeElement', () => { } ); it( 'should return null if there is no parent', () => { - const attribute = new AttributeElement( 'b' ); + const attribute = new AttributeElement( document, 'b' ); expect( attribute.getFillerOffset() ).to.be.null; } ); it( 'should return offset after all children if it is the only nested element in the container and has UIElement inside', () => { const { selection } = parse( - '[]' ); + '[]' + ); const attribute = selection.getFirstPosition().parent; expect( attribute.getFillerOffset() ).to.equal( 1 ); diff --git a/tests/view/containerelement.js b/tests/view/containerelement.js index ce70808d3..419a6be9f 100644 --- a/tests/view/containerelement.js +++ b/tests/view/containerelement.js @@ -5,12 +5,20 @@ import { default as ContainerElement, getFillerOffset } from '../../src/view/containerelement'; import Element from '../../src/view/element'; +import Document from '../../src/view/document'; import { parse } from '../../src/dev-utils/view'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'ContainerElement', () => { + let document; + + beforeEach( () => { + document = new Document( new StylesProcessor() ); + } ); + describe( 'constructor()', () => { it( 'should create element with default priority', () => { - const el = new ContainerElement( 'p' ); + const el = new ContainerElement( document, 'p' ); expect( el ).to.be.an.instanceof( ContainerElement ); expect( el ).to.be.an.instanceof( Element ); @@ -22,7 +30,7 @@ describe( 'ContainerElement', () => { let el; before( () => { - el = new ContainerElement( 'p' ); + el = new ContainerElement( document, 'p' ); } ); it( 'should return true for containerElement/element, also with correct name and element name', () => { diff --git a/tests/view/document.js b/tests/view/document.js index 16c442d76..5e42a0cbd 100644 --- a/tests/view/document.js +++ b/tests/view/document.js @@ -10,7 +10,7 @@ import Document from '../../src/view/document'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import count from '@ckeditor/ckeditor5-utils/src/count'; import createViewRoot from './_utils/createroot'; -import StylesMap from '../../src/view/stylesmap'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'Document', () => { let domRoot, viewDocument; @@ -24,7 +24,7 @@ describe( 'Document', () => { } ); document.body.appendChild( domRoot ); - viewDocument = new Document(); + viewDocument = new Document( new StylesProcessor() ); } ); afterEach( () => { @@ -92,15 +92,4 @@ describe( 'Document', () => { expect( calls ).to.equal( 4 ); } ); } ); - - describe( 'addStyleProcessorRules()', () => { - it( 'should ', () => { - const spy = sinon.spy(); - - viewDocument.addStyleProcessorRules( spy ); - - sinon.assert.calledOnce( spy ); - sinon.assert.calledWithExactly( spy, StylesMap._styleProcessor ); - } ); - } ); } ); diff --git a/tests/view/documentfragment.js b/tests/view/documentfragment.js index f85a0bb19..7e86b3c39 100644 --- a/tests/view/documentfragment.js +++ b/tests/view/documentfragment.js @@ -8,27 +8,35 @@ import Element from '../../src/view/element'; import Node from '../../src/view/node'; import Text from '../../src/view/text'; import TextProxy from '../../src/view/textproxy'; +import Document from '../../src/view/document'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'DocumentFragment', () => { + let document; + + beforeEach( () => { + document = new Document( new StylesProcessor() ); + } ); + describe( 'constructor()', () => { it( 'should create DocumentFragment without children', () => { - const fragment = new DocumentFragment(); + const fragment = new DocumentFragment( document ); expect( fragment ).to.be.an.instanceof( DocumentFragment ); expect( fragment.childCount ).to.equal( 0 ); } ); - it( 'should create DocumentFragment with child node', () => { - const child = new Element( 'p' ); - const fragment = new DocumentFragment( child ); + it( 'should create DocumentFragment document,with child node', () => { + const child = new Element( document, 'p' ); + const fragment = new DocumentFragment( document, child ); expect( fragment.childCount ).to.equal( 1 ); expect( fragment.getChild( 0 ) ).to.have.property( 'name' ).that.equals( 'p' ); } ); - it( 'should create DocumentFragment with multiple nodes', () => { - const children = [ new Element( 'p' ), new Element( 'div' ) ]; - const fragment = new DocumentFragment( children ); + it( 'should create DocumentFragment document,with multiple nodes', () => { + const children = [ new Element( document, 'p' ), new Element( document, 'div' ) ]; + const fragment = new DocumentFragment( document, children ); expect( fragment.childCount ).to.equal( 2 ); expect( fragment.getChild( 0 ) ).to.have.property( 'name' ).that.equals( 'p' ); @@ -38,8 +46,8 @@ describe( 'DocumentFragment', () => { describe( 'iterator', () => { it( 'should iterate over all nodes added to document fragment', () => { - const children = [ new Element( 'p' ), new Element( 'div' ) ]; - const fragment = new DocumentFragment( children ); + const children = [ new Element( document, 'p' ), new Element( document, 'div' ) ]; + const fragment = new DocumentFragment( document, children ); const arr = Array.from( fragment ); @@ -51,7 +59,7 @@ describe( 'DocumentFragment', () => { describe( 'getRoot', () => { it( 'should return document fragment', () => { - const fragment = new DocumentFragment(); + const fragment = new DocumentFragment( document ); expect( fragment.root ).to.equal( fragment ); } ); @@ -59,13 +67,13 @@ describe( 'DocumentFragment', () => { describe( 'isEmpty', () => { it( 'should return true if there are no children in document fragment', () => { - const fragment = new DocumentFragment(); + const fragment = new DocumentFragment( document ); expect( fragment.isEmpty ).to.be.true; } ); it( 'should return false if there are children in document fragment', () => { - const fragment = new DocumentFragment( [ new Element( 'p' ) ] ); + const fragment = new DocumentFragment( document, [ new Element( document, 'p' ) ] ); expect( fragment.isEmpty ).to.be.false; } ); @@ -75,7 +83,7 @@ describe( 'DocumentFragment', () => { let frag; before( () => { - frag = new DocumentFragment(); + frag = new DocumentFragment( document ); } ); it( 'should return true for documentFragment', () => { @@ -102,11 +110,11 @@ describe( 'DocumentFragment', () => { let fragment, el1, el2, el3, el4; beforeEach( () => { - fragment = new DocumentFragment(); - el1 = new Element( 'el1' ); - el2 = new Element( 'el2' ); - el3 = new Element( 'el3' ); - el4 = new Element( 'el4' ); + fragment = new DocumentFragment( document ); + el1 = new Element( document, 'el1' ); + el2 = new Element( document, 'el2' ); + el3 = new Element( document, 'el3' ); + el4 = new Element( document, 'el4' ); } ); describe( 'insertion', () => { @@ -129,7 +137,7 @@ describe( 'DocumentFragment', () => { expect( fragment.getChild( 0 ) ).to.have.property( 'data' ).that.equals( 'abc' ); fragment._removeChildren( 0, 1 ); - fragment._insertChild( 0, [ new Element( 'p' ), 'abc' ] ); + fragment._insertChild( 0, [ new Element( document, 'p' ), 'abc' ] ); expect( fragment.childCount ).to.equal( 2 ); expect( fragment.getChild( 1 ) ).to.have.property( 'data' ).that.equals( 'abc' ); @@ -168,8 +176,8 @@ describe( 'DocumentFragment', () => { } ); it( 'should accept and correctly handle text proxies', () => { - const frag = new DocumentFragment(); - const text = new Text( 'abcxyz' ); + const frag = new DocumentFragment( document ); + const text = new Text( document, 'abcxyz' ); const textProxy = new TextProxy( text, 2, 3 ); frag._insertChild( 0, textProxy ); @@ -260,10 +268,10 @@ describe( 'DocumentFragment', () => { describe( 'node methods when inserted to fragment', () => { it( 'index should return proper value', () => { - const node1 = new Node(); - const node2 = new Node(); - const node3 = new Node(); - const fragment = new DocumentFragment( [ node1, node2, node3 ] ); + const node1 = new Node( document ); + const node2 = new Node( document ); + const node3 = new Node( document ); + const fragment = new DocumentFragment( document, [ node1, node2, node3 ] ); expect( node1.index ).to.equal( 0 ); expect( node2.index ).to.equal( 1 ); @@ -274,10 +282,10 @@ describe( 'DocumentFragment', () => { } ); it( 'nextSibling should return proper node', () => { - const node1 = new Node(); - const node2 = new Node(); - const node3 = new Node(); - new DocumentFragment( [ node1, node2, node3 ] ); // eslint-disable-line no-new + const node1 = new Node( document ); + const node2 = new Node( document ); + const node3 = new Node( document ); + new DocumentFragment( document, [ node1, node2, node3 ] ); // eslint-disable-line no-new expect( node1.nextSibling ).to.equal( node2 ); expect( node2.nextSibling ).to.equal( node3 ); @@ -285,10 +293,10 @@ describe( 'DocumentFragment', () => { } ); it( 'previousSibling should return proper node', () => { - const node1 = new Node(); - const node2 = new Node(); - const node3 = new Node(); - new DocumentFragment( [ node1, node2, node3 ] ); // eslint-disable-line no-new + const node1 = new Node( document ); + const node2 = new Node( document ); + const node3 = new Node( document ); + new DocumentFragment( document, [ node1, node2, node3 ] ); // eslint-disable-line no-new expect( node1.previousSibling ).to.be.null; expect( node2.previousSibling ).to.equal( node1 ); @@ -296,10 +304,10 @@ describe( 'DocumentFragment', () => { } ); it( '_remove() should remove node from fragment', () => { - const node1 = new Node(); - const node2 = new Node(); - const node3 = new Node(); - const fragment = new DocumentFragment( [ node1, node2, node3 ] ); + const node1 = new Node( document ); + const node2 = new Node( document ); + const node3 = new Node( document ); + const fragment = new DocumentFragment( document, [ node1, node2, node3 ] ); node1._remove(); node3._remove(); diff --git a/tests/view/documentselection.js b/tests/view/documentselection.js index aa86b81e9..24dd0e03a 100644 --- a/tests/view/documentselection.js +++ b/tests/view/documentselection.js @@ -15,15 +15,17 @@ import createViewRoot from './_utils/createroot'; import { parse } from '../../src/dev-utils/view'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'DocumentSelection', () => { - let documentSelection, el, range1, range2, range3; + let documentSelection, el, range1, range2, range3, document; testUtils.createSinonSandbox(); beforeEach( () => { - const text = new Text( 'xxxxxxxxxxxxxxxxxxxx' ); - el = new Element( 'p', null, text ); + document = new Document( new StylesProcessor() ); + const text = new Text( document, 'xxxxxxxxxxxxxxxxxxxx' ); + el = new Element( document, 'p', null, text ); documentSelection = new DocumentSelection(); @@ -845,8 +847,8 @@ describe( 'DocumentSelection', () => { } ); it( 'should collapse selection at node and offset', () => { - const foo = new Text( 'foo' ); - const p = new Element( 'p', null, foo ); + const foo = new Text( document, 'foo' ); + const p = new Element( document, 'p', null, foo ); documentSelection._setTo( foo, 0 ); let range = documentSelection.getFirstRange(); @@ -864,7 +866,7 @@ describe( 'DocumentSelection', () => { } ); it( 'should throw an error when the second parameter is not passed and first is an item', () => { - const foo = new Text( 'foo' ); + const foo = new Text( document, 'foo' ); expectToThrowCKEditorError( () => { documentSelection._setTo( foo ); @@ -872,8 +874,8 @@ describe( 'DocumentSelection', () => { } ); it( 'should collapse selection at node and flag', () => { - const foo = new Text( 'foo' ); - const p = new Element( 'p', null, foo ); + const foo = new Text( document, 'foo' ); + const p = new Element( document, 'p', null, foo ); documentSelection._setTo( foo, 'end' ); let range = documentSelection.getFirstRange(); @@ -1029,10 +1031,10 @@ describe( 'DocumentSelection', () => { } ); it( 'should allow setting selection on an item', () => { - const textNode1 = new Text( 'foo' ); - const textNode2 = new Text( 'bar' ); - const textNode3 = new Text( 'baz' ); - const element = new Element( 'p', null, [ textNode1, textNode2, textNode3 ] ); + const textNode1 = new Text( document, 'foo' ); + const textNode2 = new Text( document, 'bar' ); + const textNode3 = new Text( document, 'baz' ); + const element = new Element( document, 'p', null, [ textNode1, textNode2, textNode3 ] ); documentSelection._setTo( textNode2, 'on' ); @@ -1045,7 +1047,7 @@ describe( 'DocumentSelection', () => { } ); it( 'should allow setting selection inside an element', () => { - const element = new Element( 'p', null, [ new Text( 'foo' ), new Text( 'bar' ) ] ); + const element = new Element( document, 'p', null, [ new Text( document, 'foo' ), new Text( document, 'bar' ) ] ); documentSelection._setTo( element, 'in' ); @@ -1058,7 +1060,7 @@ describe( 'DocumentSelection', () => { } ); it( 'should allow setting backward selection inside an element', () => { - const element = new Element( 'p', null, [ new Text( 'foo' ), new Text( 'bar' ) ] ); + const element = new Element( document, 'p', null, [ new Text( document, 'foo' ), new Text( document, 'bar' ) ] ); documentSelection._setTo( element, 'in', { backward: true } ); @@ -1084,10 +1086,10 @@ describe( 'DocumentSelection', () => { } ); it( 'should return EditableElement when selection is placed inside', () => { - const viewDocument = new Document(); + const viewDocument = new Document( new StylesProcessor() ); documentSelection._setTo( viewDocument.selection ); const root = createViewRoot( viewDocument, 'div', 'main' ); - const element = new Element( 'p' ); + const element = new Element( document, 'p' ); root._appendChild( element ); documentSelection._setTo( Range._createFromParentsAndOffsets( element, 0, element, 0 ) ); diff --git a/tests/view/domconverter/binding.js b/tests/view/domconverter/binding.js index c1160d908..999d1b8d8 100644 --- a/tests/view/domconverter/binding.js +++ b/tests/view/domconverter/binding.js @@ -9,23 +9,26 @@ import ViewElement from '../../../src/view/element'; import ViewDocumentSelection from '../../../src/view/documentselection'; import DomConverter from '../../../src/view/domconverter'; import ViewDocumentFragment from '../../../src/view/documentfragment'; +import ViewDocument from '../../../src/view/document'; import { INLINE_FILLER } from '../../../src/view/filler'; import { parse } from '../../../src/dev-utils/view'; import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DomConverter', () => { - let converter; + let converter, viewDocument; - before( () => { - converter = new DomConverter(); + beforeEach( () => { + viewDocument = new ViewDocument( new StylesProcessor() ); + converter = new DomConverter( viewDocument ); } ); describe( 'bindElements()', () => { it( 'should bind elements', () => { const domElement = document.createElement( 'p' ); - const viewElement = new ViewElement( 'p' ); + const viewElement = new ViewElement( viewDocument, 'p' ); converter.bindElements( domElement, viewElement ); @@ -37,7 +40,7 @@ describe( 'DomConverter', () => { describe( 'bindDocumentFragments()', () => { it( 'should bind document fragments', () => { const domFragment = document.createDocumentFragment(); - const viewFragment = new ViewDocumentFragment(); + const viewFragment = new ViewDocumentFragment( viewDocument ); converter.bindDocumentFragments( domFragment, viewFragment ); @@ -49,7 +52,7 @@ describe( 'DomConverter', () => { describe( 'mapDomToView()', () => { it( 'should return corresponding view element if element is passed', () => { const domElement = document.createElement( 'p' ); - const viewElement = new ViewElement( 'p' ); + const viewElement = new ViewElement( viewDocument, 'p' ); converter.bindElements( domElement, viewElement ); @@ -77,7 +80,7 @@ describe( 'DomConverter', () => { const domText = document.createTextNode( 'foo' ); const domP = createElement( document, 'p', null, [ domImg, domText ] ); - const viewImg = new ViewElement( 'img' ); + const viewImg = new ViewElement( viewDocument, 'img' ); converter.bindElements( domImg, viewImg ); @@ -173,7 +176,7 @@ describe( 'DomConverter', () => { describe( 'mapViewToDom()', () => { it( 'should return corresponding DOM element if element was passed', () => { const domElement = document.createElement( 'p' ); - const viewElement = new ViewElement( 'p' ); + const viewElement = new ViewElement( viewDocument, 'p' ); converter.bindElements( domElement, viewElement ); @@ -182,7 +185,7 @@ describe( 'DomConverter', () => { it( 'should return corresponding DOM document fragment', () => { const domFragment = document.createDocumentFragment(); - const viewFragment = new ViewDocumentFragment(); + const viewFragment = new ViewDocumentFragment( viewDocument ); converter.bindElements( domFragment, viewFragment ); @@ -203,7 +206,7 @@ describe( 'DomConverter', () => { domP.appendChild( domImg ); domP.appendChild( domText ); - const viewImg = new ViewElement( 'img' ); + const viewImg = new ViewElement( viewDocument, 'img' ); converter.bindElements( domImg, viewImg ); @@ -267,7 +270,7 @@ describe( 'DomConverter', () => { let domEl, selection, viewElement; beforeEach( () => { - viewElement = new ViewElement(); + viewElement = new ViewElement( viewDocument ); domEl = document.createElement( 'div' ); selection = new ViewDocumentSelection( viewElement, 'in' ); converter.bindFakeSelection( domEl, selection ); @@ -282,7 +285,7 @@ describe( 'DomConverter', () => { it( 'should keep a copy of selection', () => { const selectionCopy = new ViewDocumentSelection( selection ); - selection._setTo( new ViewElement(), 'in', { backward: true } ); + selection._setTo( new ViewElement( viewDocument ), 'in', { backward: true } ); const bindSelection = converter.fakeSelectionToView( domEl ); expect( bindSelection ).to.not.equal( selection ); @@ -294,7 +297,7 @@ describe( 'DomConverter', () => { describe( 'unbindDomElement', () => { it( 'should unbind elements', () => { const domElement = document.createElement( 'p' ); - const viewElement = new ViewElement( 'p' ); + const viewElement = new ViewElement( viewDocument, 'p' ); converter.bindElements( domElement, viewElement ); @@ -312,8 +315,8 @@ describe( 'DomConverter', () => { const domChild = document.createElement( 'span' ); domElement.appendChild( domChild ); - const viewElement = new ViewElement( 'p' ); - const viewChild = new ViewElement( 'span' ); + const viewElement = new ViewElement( viewDocument, 'p' ); + const viewChild = new ViewElement( viewDocument, 'span' ); converter.bindElements( domElement, viewElement ); converter.bindElements( domChild, viewChild ); @@ -329,7 +332,7 @@ describe( 'DomConverter', () => { it( 'should do nothing if there are no elements bind', () => { const domElement = document.createElement( 'p' ); - const viewElement = new ViewElement( 'p' ); + const viewElement = new ViewElement( viewDocument, 'p' ); expect( converter.mapDomToView( domElement ) ).to.be.undefined; expect( converter.mapViewToDom( viewElement ) ).to.be.undefined; diff --git a/tests/view/domconverter/dom-to-view.js b/tests/view/domconverter/dom-to-view.js index 069eafaea..2e2b942bf 100644 --- a/tests/view/domconverter/dom-to-view.js +++ b/tests/view/domconverter/dom-to-view.js @@ -6,21 +6,23 @@ /* globals document */ import ViewElement from '../../../src/view/element'; +import ViewDocument from '../../../src/view/document'; import ViewDocumentSelection from '../../../src/view/documentselection'; import DomConverter from '../../../src/view/domconverter'; import ViewDocumentFragment from '../../../src/view/documentfragment'; import { BR_FILLER, INLINE_FILLER, INLINE_FILLER_LENGTH, NBSP_FILLER } from '../../../src/view/filler'; - +import { StylesProcessor } from '../../../src/view/stylesmap'; import { parse, stringify } from '../../../src/dev-utils/view'; import count from '@ckeditor/ckeditor5-utils/src/count'; import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; describe( 'DomConverter', () => { - let converter; + let converter, viewDocument; before( () => { - converter = new DomConverter(); + viewDocument = new ViewDocument( new StylesProcessor() ); + converter = new DomConverter( viewDocument ); } ); describe( 'domToView()', () => { @@ -29,7 +31,7 @@ describe( 'DomConverter', () => { const domText = document.createTextNode( 'foo' ); const domP = createElement( document, 'p', { 'class': 'foo' }, [ domImg, domText ] ); - const viewImg = new ViewElement( 'img' ); + const viewImg = new ViewElement( viewDocument, 'img' ); converter.bindElements( domImg, viewImg ); @@ -90,7 +92,7 @@ describe( 'DomConverter', () => { const domText = document.createTextNode( 'foo' ); const domP = createElement( document, 'p', { 'class': 'foo' }, [ domImg, domText ] ); - const viewImg = new ViewElement( 'img' ); + const viewImg = new ViewElement( viewDocument, 'img' ); converter.bindElements( domImg, viewImg ); @@ -133,7 +135,7 @@ describe( 'DomConverter', () => { domFragment.appendChild( domImg ); domFragment.appendChild( domText ); - const viewImg = new ViewElement( 'img' ); + const viewImg = new ViewElement( viewDocument, 'img' ); converter.bindElements( domImg, viewImg ); @@ -763,7 +765,7 @@ describe( 'DomConverter', () => { } ); it( 'should converter position inside block filler', () => { - const converter = new DomConverter( { blockFillerMode: 'nbsp' } ); + const converter = new DomConverter( viewDocument, { blockFillerMode: 'nbsp' } ); const domFiller = NBSP_FILLER( document ); // eslint-disable-line new-cap const domP = createElement( document, 'p', null, domFiller ); @@ -1001,7 +1003,7 @@ describe( 'DomConverter', () => { domContainer.innerHTML = 'fake selection container'; document.body.appendChild( domContainer ); - const viewSelection = new ViewDocumentSelection( new ViewElement(), 'in' ); + const viewSelection = new ViewDocumentSelection( new ViewElement( viewDocument ), 'in' ); converter.bindFakeSelection( domContainer, viewSelection ); const domRange = document.createRange(); @@ -1022,7 +1024,7 @@ describe( 'DomConverter', () => { domContainer.innerHTML = 'fake selection container'; document.body.appendChild( domContainer ); - const viewSelection = new ViewDocumentSelection( new ViewElement(), 'in' ); + const viewSelection = new ViewDocumentSelection( new ViewElement( viewDocument ), 'in' ); converter.bindFakeSelection( domContainer, viewSelection ); const domRange = document.createRange(); diff --git a/tests/view/domconverter/domconverter.js b/tests/view/domconverter/domconverter.js index a77701cc4..fa72f72fd 100644 --- a/tests/view/domconverter/domconverter.js +++ b/tests/view/domconverter/domconverter.js @@ -13,14 +13,16 @@ import ViewContainerElement from '../../../src/view/containerelement'; import { BR_FILLER, INLINE_FILLER, INLINE_FILLER_LENGTH, NBSP_FILLER } from '../../../src/view/filler'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import global from '@ckeditor/ckeditor5-utils/src/dom/global'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DomConverter', () => { - let converter; + let converter, viewDocument; testUtils.createSinonSandbox(); beforeEach( () => { - converter = new DomConverter(); + viewDocument = new ViewDocument( new StylesProcessor() ); + converter = new DomConverter( viewDocument ); } ); describe( 'constructor()', () => { @@ -29,7 +31,7 @@ describe( 'DomConverter', () => { } ); it( 'should create converter with defined block mode filler', () => { - converter = new DomConverter( { blockFillerMode: 'nbsp' } ); + converter = new DomConverter( viewDocument, { blockFillerMode: 'nbsp' } ); expect( converter.blockFillerMode ).to.equal( 'nbsp' ); } ); } ); @@ -38,9 +40,8 @@ describe( 'DomConverter', () => { let viewEditable, domEditable, domEditableParent, viewDocument; beforeEach( () => { - viewDocument = new ViewDocument(); - viewEditable = new ViewEditable( 'div' ); - viewEditable._document = viewDocument; + viewDocument = new ViewDocument( new StylesProcessor() ); + viewEditable = new ViewEditable( viewDocument, 'div' ); domEditable = document.createElement( 'div' ); domEditableParent = document.createElement( 'div' ); @@ -192,7 +193,7 @@ describe( 'DomConverter', () => { return sel; } - let domP, domFillerTextNode, domUiSpan, domUiDeepSpan; + let domP, domFillerTextNode, domUiSpan, domUiDeepSpan, viewDocument; beforeEach( () => { //

INLINE_FILLERfoo

. @@ -203,8 +204,10 @@ describe( 'DomConverter', () => { domUiDeepSpan = document.createElement( 'span' ); domUiSpan.appendChild( domUiDeepSpan ); - const viewUiSpan = new ViewUIElement( 'span' ); - const viewElementSpan = new ViewContainerElement( 'span' ); + viewDocument = new ViewDocument( new StylesProcessor() ); + + const viewUiSpan = new ViewUIElement( viewDocument, 'span' ); + const viewElementSpan = new ViewContainerElement( viewDocument, 'span' ); domP.appendChild( domFillerTextNode ); domP.appendChild( domUiSpan ); @@ -294,7 +297,7 @@ describe( 'DomConverter', () => { describe( 'isBlockFiller()', () => { describe( 'mode "nbsp"', () => { beforeEach( () => { - converter = new DomConverter( { blockFillerMode: 'nbsp' } ); + converter = new DomConverter( viewDocument, { blockFillerMode: 'nbsp' } ); } ); it( 'should return true if the node is an nbsp filler and is a single child of a block level element', () => { @@ -377,7 +380,7 @@ describe( 'DomConverter', () => { describe( 'mode "br"', () => { beforeEach( () => { - converter = new DomConverter( { blockFillerMode: 'br' } ); + converter = new DomConverter( viewDocument, { blockFillerMode: 'br' } ); } ); it( 'should return true if the node is an instance of the BR block filler', () => { @@ -389,7 +392,7 @@ describe( 'DomConverter', () => { } ); it( 'should return false if the node is an instance of the NBSP block filler', () => { - converter = new DomConverter( { blockFillerMode: 'br' } ); + converter = new DomConverter( viewDocument, { blockFillerMode: 'br' } ); const nbspFillerInstance = NBSP_FILLER( document ); // eslint-disable-line new-cap // NBSP must be check inside a context. const context = document.createElement( 'div' ); diff --git a/tests/view/domconverter/uielement.js b/tests/view/domconverter/uielement.js index 88b6680ec..90eec9c51 100644 --- a/tests/view/domconverter/uielement.js +++ b/tests/view/domconverter/uielement.js @@ -8,12 +8,14 @@ import ViewUIElement from '../../../src/view/uielement'; import ViewContainer from '../../../src/view/containerelement'; import DomConverter from '../../../src/view/domconverter'; +import ViewDocument from '../../../src/view/document'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DOMConverter UIElement integration', () => { - let converter; + let converter, viewDocument; function createUIElement( name ) { - const element = new ViewUIElement( name ); + const element = new ViewUIElement( viewDocument, name ); element.render = function( domDocument ) { const root = this.toDomElement( domDocument ); @@ -26,12 +28,13 @@ describe( 'DOMConverter UIElement integration', () => { } beforeEach( () => { - converter = new DomConverter(); + viewDocument = new ViewDocument( new StylesProcessor() ); + converter = new DomConverter( viewDocument ); } ); describe( 'viewToDom()', () => { it( 'should create DOM element from UIElement', () => { - const uiElement = new ViewUIElement( 'div' ); + const uiElement = new ViewUIElement( viewDocument, 'div' ); const domElement = converter.viewToDom( uiElement, document ); expect( domElement ).to.be.instanceOf( HTMLElement ); @@ -81,7 +84,7 @@ describe( 'DOMConverter UIElement integration', () => { describe( 'domPositionToView()', () => { it( 'should convert position inside UIElement to position before it', () => { const uiElement = createUIElement( 'h1' ); - const container = new ViewContainer( 'div', null, [ new ViewContainer( 'div' ), uiElement ] ); + const container = new ViewContainer( viewDocument, 'div', null, [ new ViewContainer( viewDocument, 'div' ), uiElement ] ); const domContainer = converter.viewToDom( container, document, { bind: true } ); const viewPosition = converter.domPositionToView( domContainer.childNodes[ 1 ], 0 ); @@ -92,7 +95,7 @@ describe( 'DOMConverter UIElement integration', () => { it( 'should convert position inside UIElement children to position before UIElement', () => { const uiElement = createUIElement( 'h1' ); - const container = new ViewContainer( 'div', null, [ new ViewContainer( 'div' ), uiElement ] ); + const container = new ViewContainer( viewDocument, 'div', null, [ new ViewContainer( viewDocument, 'div' ), uiElement ] ); const domContainer = converter.viewToDom( container, document, { bind: true } ); const viewPosition = converter.domPositionToView( domContainer.childNodes[ 1 ].childNodes[ 0 ], 1 ); diff --git a/tests/view/domconverter/view-to-dom.js b/tests/view/domconverter/view-to-dom.js index d2edc628d..79e09b3c5 100644 --- a/tests/view/domconverter/view-to-dom.js +++ b/tests/view/domconverter/view-to-dom.js @@ -13,24 +13,27 @@ import ViewAttributeElement from '../../../src/view/attributeelement'; import ViewEmptyElement from '../../../src/view/emptyelement'; import DomConverter from '../../../src/view/domconverter'; import ViewDocumentFragment from '../../../src/view/documentfragment'; +import ViewDocument from '../../../src/view/document'; import { INLINE_FILLER, INLINE_FILLER_LENGTH } from '../../../src/view/filler'; import { parse } from '../../../src/dev-utils/view'; import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DomConverter', () => { - let converter; + let converter, viewDocument; - before( () => { - converter = new DomConverter(); + beforeEach( () => { + viewDocument = new ViewDocument( new StylesProcessor() ); + converter = new DomConverter( viewDocument ); } ); describe( 'viewToDom()', () => { it( 'should create tree of DOM elements from view elements', () => { - const viewImg = new ViewElement( 'img' ); - const viewText = new ViewText( 'foo' ); - const viewP = new ViewElement( 'p', { class: 'foo' } ); + const viewImg = new ViewElement( viewDocument, 'img' ); + const viewText = new ViewText( viewDocument, 'foo' ); + const viewP = new ViewElement( viewDocument, 'p', { class: 'foo' } ); viewP._appendChild( viewImg ); viewP._appendChild( viewText ); @@ -56,9 +59,9 @@ describe( 'DomConverter', () => { } ); it( 'should create tree of DOM elements from view elements and bind elements', () => { - const viewImg = new ViewElement( 'img' ); - const viewText = new ViewText( 'foo' ); - const viewP = new ViewElement( 'p', { class: 'foo' } ); + const viewImg = new ViewElement( viewDocument, 'img' ); + const viewText = new ViewText( viewDocument, 'foo' ); + const viewP = new ViewElement( viewDocument, 'p', { class: 'foo' } ); viewP._appendChild( viewImg ); viewP._appendChild( viewText ); @@ -80,8 +83,8 @@ describe( 'DomConverter', () => { } ); it( 'should support unicode', () => { - const viewText = new ViewText( 'நிலைக்கு' ); - const viewP = new ViewElement( 'p', null, viewText ); + const viewText = new ViewText( viewDocument, 'நிலைக்கு' ); + const viewP = new ViewElement( viewDocument, 'p', null, viewText ); const domP = converter.viewToDom( viewP, document, { bind: true } ); @@ -93,9 +96,9 @@ describe( 'DomConverter', () => { } ); it( 'should create tree of DOM elements from view element without children', () => { - const viewImg = new ViewElement( 'img' ); - const viewText = new ViewText( 'foo' ); - const viewP = new ViewElement( 'p', { class: 'foo' } ); + const viewImg = new ViewElement( viewDocument, 'img' ); + const viewText = new ViewText( viewDocument, 'foo' ); + const viewP = new ViewElement( viewDocument, 'p', { class: 'foo' } ); viewP._appendChild( viewImg ); viewP._appendChild( viewText ); @@ -117,9 +120,9 @@ describe( 'DomConverter', () => { } ); it( 'should create DOM document fragment from view document fragment and bind elements', () => { - const viewImg = new ViewElement( 'img' ); - const viewText = new ViewText( 'foo' ); - const viewFragment = new ViewDocumentFragment(); + const viewImg = new ViewElement( viewDocument, 'img' ); + const viewText = new ViewText( viewDocument, 'foo' ); + const viewFragment = new ViewDocumentFragment( viewDocument ); viewFragment._appendChild( viewImg ); viewFragment._appendChild( viewText ); @@ -136,9 +139,9 @@ describe( 'DomConverter', () => { } ); it( 'should create DOM document fragment from view document without children', () => { - const viewImg = new ViewElement( 'img' ); - const viewText = new ViewText( 'foo' ); - const viewFragment = new ViewDocumentFragment(); + const viewImg = new ViewElement( viewDocument, 'img' ); + const viewText = new ViewText( viewDocument, 'foo' ); + const viewFragment = new ViewDocumentFragment( viewDocument ); viewFragment._appendChild( viewImg ); viewFragment._appendChild( viewText ); @@ -157,7 +160,7 @@ describe( 'DomConverter', () => { it( 'should return already bind document fragment', () => { const domFragment = document.createDocumentFragment(); - const viewFragment = new ViewDocumentFragment(); + const viewFragment = new ViewDocumentFragment( viewDocument ); converter.bindDocumentFragments( domFragment, viewFragment ); @@ -167,7 +170,7 @@ describe( 'DomConverter', () => { } ); it( 'should create DOM text node from view text node', () => { - const viewTextNode = new ViewText( 'foo' ); + const viewTextNode = new ViewText( viewDocument, 'foo' ); const domTextNode = converter.viewToDom( viewTextNode, document ); expect( domTextNode ).to.be.instanceof( Text ); @@ -176,7 +179,7 @@ describe( 'DomConverter', () => { it( 'should create namespaced elements', () => { const namespace = 'http://www.w3.org/2000/svg'; - const viewSvg = new ViewElement( 'svg', { xmlns: namespace } ); + const viewSvg = new ViewElement( viewDocument, 'svg', { xmlns: namespace } ); const domSvg = converter.viewToDom( viewSvg, document ); @@ -185,10 +188,10 @@ describe( 'DomConverter', () => { describe( 'it should convert spaces to  ', () => { it( 'at the beginning of each container element', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewContainerElement( 'p', null, new ViewText( ' foo' ) ), - new ViewContainerElement( 'p', null, new ViewText( 'bar' ) ), - new ViewContainerElement( 'p', null, new ViewText( ' xxx' ) ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewContainerElement( viewDocument, 'p', null, new ViewText( viewDocument, ' foo' ) ), + new ViewContainerElement( viewDocument, 'p', null, new ViewText( viewDocument, 'bar' ) ), + new ViewContainerElement( viewDocument, 'p', null, new ViewText( viewDocument, ' xxx' ) ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -197,10 +200,10 @@ describe( 'DomConverter', () => { } ); it( 'at the end of each container element', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewContainerElement( 'p', null, new ViewText( 'foo ' ) ), - new ViewContainerElement( 'p', null, new ViewText( 'bar' ) ), - new ViewContainerElement( 'p', null, new ViewText( 'xxx ' ) ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewContainerElement( viewDocument, 'p', null, new ViewText( viewDocument, 'foo ' ) ), + new ViewContainerElement( viewDocument, 'p', null, new ViewText( viewDocument, 'bar' ) ), + new ViewContainerElement( viewDocument, 'p', null, new ViewText( viewDocument, 'xxx ' ) ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -209,12 +212,12 @@ describe( 'DomConverter', () => { } ); it( 'when there are multiple spaces next to each other or between attribute elements', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewText( 'x x x x ' ), - new ViewAttributeElement( 'b', null, new ViewText( ' x ' ) ), - new ViewAttributeElement( 'i', null, - new ViewAttributeElement( 'b', null, - new ViewAttributeElement( 'u', null, new ViewText( ' x' ) ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, 'x x x x ' ), + new ViewAttributeElement( viewDocument, 'b', null, new ViewText( viewDocument, ' x ' ) ), + new ViewAttributeElement( viewDocument, 'i', null, + new ViewAttributeElement( viewDocument, 'b', null, + new ViewAttributeElement( viewDocument, 'u', null, new ViewText( viewDocument, ' x' ) ) ) ) ] ); @@ -225,17 +228,17 @@ describe( 'DomConverter', () => { } ); it( 'all together', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewContainerElement( 'p', null, [ - new ViewText( ' x x x x ' ), - new ViewAttributeElement( 'b', null, new ViewText( ' x ' ) ), - new ViewAttributeElement( 'i', null, - new ViewAttributeElement( 'b', null, - new ViewAttributeElement( 'u', null, new ViewText( ' x ' ) ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewContainerElement( viewDocument, 'p', null, [ + new ViewText( viewDocument, ' x x x x ' ), + new ViewAttributeElement( viewDocument, 'b', null, new ViewText( viewDocument, ' x ' ) ), + new ViewAttributeElement( viewDocument, 'i', null, + new ViewAttributeElement( viewDocument, 'b', null, + new ViewAttributeElement( viewDocument, 'u', null, new ViewText( viewDocument, ' x ' ) ) ) ) ] ), - new ViewContainerElement( 'p', null, new ViewText( ' x ' ) ) + new ViewContainerElement( viewDocument, 'p', null, new ViewText( viewDocument, ' x ' ) ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -251,10 +254,10 @@ describe( 'DomConverter', () => { } it( 'spaces in a text node: ' + inputTexts.join( '|' ) + ' -> ' + output, () => { - const viewElement = new ViewContainerElement( 'p' ); + const viewElement = new ViewContainerElement( viewDocument, 'p' ); for ( const text of inputTexts ) { - viewElement._appendChild( new ViewText( text.replace( /_/g, '\u00A0' ) ) ); + viewElement._appendChild( new ViewText( viewDocument, text.replace( /_/g, '\u00A0' ) ) ); } const domElement = converter.viewToDom( viewElement, document ); @@ -415,15 +418,18 @@ describe( 'DomConverter', () => { testConvert( [ ' ', ' ' ], '_ _ __' ); it( 'not in preformatted blocks', () => { - const viewPre = new ViewContainerElement( 'pre', null, [ new ViewText( ' foo ' ), new ViewText( ' bar ' ) ] ); + const viewPre = new ViewContainerElement( viewDocument, 'pre', null, [ + new ViewText( viewDocument, ' foo ' ), + new ViewText( viewDocument, ' bar ' ) + ] ); const domPre = converter.viewToDom( viewPre, document ); expect( domPre.innerHTML ).to.equal( ' foo bar ' ); } ); it( 'not in a preformatted block followed by a text', () => { - const viewPre = new ViewAttributeElement( 'pre', null, new ViewText( 'foo ' ) ); - const viewDiv = new ViewContainerElement( 'div', null, [ viewPre, new ViewText( ' bar' ) ] ); + const viewPre = new ViewAttributeElement( viewDocument, 'pre', null, new ViewText( viewDocument, 'foo ' ) ); + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ viewPre, new ViewText( viewDocument, ' bar' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); expect( domDiv.innerHTML ).to.equal( '
foo   
bar' ); @@ -431,10 +437,10 @@ describe( 'DomConverter', () => { describe( 'around
s', () => { it( 'before
– a single space', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewText( 'foo ' ), - new ViewEmptyElement( 'br' ), - new ViewText( 'bar' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, 'foo ' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, 'bar' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -442,10 +448,10 @@ describe( 'DomConverter', () => { } ); it( 'before
– two spaces', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewText( 'foo ' ), - new ViewEmptyElement( 'br' ), - new ViewText( 'bar' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, 'foo ' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, 'bar' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -453,10 +459,10 @@ describe( 'DomConverter', () => { } ); it( 'before
– three spaces', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewText( 'foo ' ), - new ViewEmptyElement( 'br' ), - new ViewText( 'bar' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, 'foo ' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, 'bar' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -464,10 +470,10 @@ describe( 'DomConverter', () => { } ); it( 'before
– only a space', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewText( ' ' ), - new ViewEmptyElement( 'br' ), - new ViewText( 'bar' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, ' ' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, 'bar' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -475,10 +481,10 @@ describe( 'DomConverter', () => { } ); it( 'before
– only two spaces', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewText( ' ' ), - new ViewEmptyElement( 'br' ), - new ViewText( 'bar' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, ' ' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, 'bar' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -486,10 +492,10 @@ describe( 'DomConverter', () => { } ); it( 'before
– only three spaces', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewText( ' ' ), - new ViewEmptyElement( 'br' ), - new ViewText( 'bar' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, ' ' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, 'bar' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -497,10 +503,10 @@ describe( 'DomConverter', () => { } ); it( 'after
– a single space', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewText( 'foo' ), - new ViewEmptyElement( 'br' ), - new ViewText( ' bar' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, 'foo' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, ' bar' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -508,10 +514,10 @@ describe( 'DomConverter', () => { } ); it( 'after
– two spaces', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewText( 'foo' ), - new ViewEmptyElement( 'br' ), - new ViewText( ' bar' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, 'foo' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, ' bar' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -519,10 +525,10 @@ describe( 'DomConverter', () => { } ); it( 'after
– three spaces', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewText( 'foo' ), - new ViewEmptyElement( 'br' ), - new ViewText( ' bar' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, 'foo' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, ' bar' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -530,10 +536,10 @@ describe( 'DomConverter', () => { } ); it( 'after
– only a space', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewText( 'foo' ), - new ViewEmptyElement( 'br' ), - new ViewText( ' ' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, 'foo' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, ' ' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -541,10 +547,10 @@ describe( 'DomConverter', () => { } ); it( 'after
– only two spaces', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewText( 'foo' ), - new ViewEmptyElement( 'br' ), - new ViewText( ' ' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, 'foo' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, ' ' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -552,10 +558,10 @@ describe( 'DomConverter', () => { } ); it( 'after
– only three spaces', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewText( 'foo' ), - new ViewEmptyElement( 'br' ), - new ViewText( ' ' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewText( viewDocument, 'foo' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, ' ' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -563,11 +569,11 @@ describe( 'DomConverter', () => { } ); it( 'between
s – a single space', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewEmptyElement( 'br' ), - new ViewText( ' ' ), - new ViewEmptyElement( 'br' ), - new ViewText( 'foo' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, ' ' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, 'foo' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -575,11 +581,11 @@ describe( 'DomConverter', () => { } ); it( 'between
s – only two spaces', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewEmptyElement( 'br' ), - new ViewText( ' ' ), - new ViewEmptyElement( 'br' ), - new ViewText( 'foo' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, ' ' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, 'foo' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -587,11 +593,11 @@ describe( 'DomConverter', () => { } ); it( 'between
s – only three spaces', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewEmptyElement( 'br' ), - new ViewText( ' ' ), - new ViewEmptyElement( 'br' ), - new ViewText( 'foo' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, ' ' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, 'foo' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -599,11 +605,11 @@ describe( 'DomConverter', () => { } ); it( 'between
s – space and text', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewEmptyElement( 'br' ), - new ViewText( ' foo' ), - new ViewEmptyElement( 'br' ), - new ViewText( 'foo' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, ' foo' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, 'foo' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -611,11 +617,11 @@ describe( 'DomConverter', () => { } ); it( 'between
s – text and space', () => { - const viewDiv = new ViewContainerElement( 'div', null, [ - new ViewEmptyElement( 'br' ), - new ViewText( 'foo ' ), - new ViewEmptyElement( 'br' ), - new ViewText( 'foo' ) + const viewDiv = new ViewContainerElement( viewDocument, 'div', null, [ + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, 'foo ' ), + new ViewEmptyElement( viewDocument, 'br' ), + new ViewText( viewDocument, 'foo' ) ] ); const domDiv = converter.viewToDom( viewDiv, document ); @@ -793,7 +799,7 @@ describe( 'DomConverter', () => { } ); it( 'should return null if view position is in a view text node that has not been rendered to DOM', () => { - const viewText = new ViewText( 'foo' ); + const viewText = new ViewText( viewDocument, 'foo' ); const viewPosition = new ViewPosition( viewText, 1 ); const domPosition = converter.viewPositionToDom( viewPosition ); @@ -801,7 +807,7 @@ describe( 'DomConverter', () => { } ); it( 'should return null if view position is in a view element that has not been rendered to DOM', () => { - const viewElement = new ViewContainerElement( 'div' ); + const viewElement = new ViewContainerElement( viewDocument, 'div' ); const viewPosition = new ViewPosition( viewElement, 0 ); const domPosition = converter.viewPositionToDom( viewPosition ); diff --git a/tests/view/downcastwriter/breakattributes.js b/tests/view/downcastwriter/breakattributes.js index 6fc5f8fe2..eb7177c1b 100644 --- a/tests/view/downcastwriter/breakattributes.js +++ b/tests/view/downcastwriter/breakattributes.js @@ -14,13 +14,14 @@ import Range from '../../../src/view/range'; import Position from '../../../src/view/position'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DowncastWriter', () => { describe( 'breakAttributes()', () => { let writer, document; beforeEach( () => { - document = new Document(); + document = new Document( new StylesProcessor() ); writer = new DowncastWriter( document ); } ); @@ -152,8 +153,8 @@ describe( 'DowncastWriter', () => { } it( 'should throw when range placed in two containers', () => { - const p1 = new ContainerElement( 'p' ); - const p2 = new ContainerElement( 'p' ); + const p1 = new ContainerElement( document, 'p' ); + const p2 = new ContainerElement( document, 'p' ); expectToThrowCKEditorError( () => { writer.breakAttributes( Range._createFromParentsAndOffsets( p1, 0, p2, 0 ) ); @@ -161,7 +162,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw when range has no parent container', () => { - const el = new AttributeElement( 'b' ); + const el = new AttributeElement( document, 'b' ); expectToThrowCKEditorError( () => { writer.breakAttributes( Range._createFromParentsAndOffsets( el, 0, el, 0 ) ); @@ -241,8 +242,8 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if breaking inside EmptyElement #1', () => { - const img = new EmptyElement( 'img' ); - new ContainerElement( 'p', null, img ); // eslint-disable-line no-new + const img = new EmptyElement( document, 'img' ); + new ContainerElement( document, 'p', null, img ); // eslint-disable-line no-new const position = new Position( img, 0 ); expectToThrowCKEditorError( () => { @@ -251,9 +252,9 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if breaking inside EmptyElement #2', () => { - const img = new EmptyElement( 'img' ); - const b = new AttributeElement( 'b' ); - new ContainerElement( 'p', null, [ img, b ] ); // eslint-disable-line no-new + const img = new EmptyElement( document, 'img' ); + const b = new AttributeElement( document, 'b' ); + new ContainerElement( document, 'p', null, [ img, b ] ); // eslint-disable-line no-new const range = Range._createFromParentsAndOffsets( img, 0, b, 0 ); expectToThrowCKEditorError( () => { @@ -262,8 +263,8 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if breaking inside UIElement #1', () => { - const span = new UIElement( 'span' ); - new ContainerElement( 'p', null, span ); // eslint-disable-line no-new + const span = new UIElement( document, 'span' ); + new ContainerElement( document, 'p', null, span ); // eslint-disable-line no-new const position = new Position( span, 0 ); expectToThrowCKEditorError( () => { @@ -272,9 +273,9 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if breaking inside UIElement #2', () => { - const span = new UIElement( 'span' ); - const b = new AttributeElement( 'b' ); - new ContainerElement( 'p', null, [ span, b ] ); // eslint-disable-line no-new + const span = new UIElement( document, 'span' ); + const b = new AttributeElement( document, 'b' ); + new ContainerElement( document, 'p', null, [ span, b ] ); // eslint-disable-line no-new const range = Range._createFromParentsAndOffsets( span, 0, b, 0 ); expectToThrowCKEditorError( () => { diff --git a/tests/view/downcastwriter/breakcontainer.js b/tests/view/downcastwriter/breakcontainer.js index fd0bcb790..3e5e39ea9 100644 --- a/tests/view/downcastwriter/breakcontainer.js +++ b/tests/view/downcastwriter/breakcontainer.js @@ -10,10 +10,11 @@ import ContainerElement from '../../../src/view/containerelement'; import Position from '../../../src/view/position'; import Document from '../../../src/view/document'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DowncastWriter', () => { describe( 'breakContainer()', () => { - let writer; + let writer, document; // Executes test using `parse` and `stringify` utils functions. Uses range delimiters `[]{}` to create and // test break position. @@ -28,7 +29,8 @@ describe( 'DowncastWriter', () => { } before( () => { - writer = new DowncastWriter( new Document() ); + document = new Document( new StylesProcessor() ); + writer = new DowncastWriter( document ); } ); it( 'break inside element - should break container element at given position', () => { @@ -73,7 +75,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if position parent is root', () => { - const element = new ContainerElement( 'div' ); + const element = new ContainerElement( document, 'div' ); const position = Position._createAt( element, 0 ); expectToThrowCKEditorError( () => { diff --git a/tests/view/downcastwriter/clear.js b/tests/view/downcastwriter/clear.js index 7a5c5a0b2..eb5b01dca 100644 --- a/tests/view/downcastwriter/clear.js +++ b/tests/view/downcastwriter/clear.js @@ -13,6 +13,7 @@ import UIElement from '../../../src/view/uielement'; import Document from '../../../src/view/document'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DowncastWriter', () => { describe( 'clear()', () => { @@ -32,13 +33,13 @@ describe( 'DowncastWriter', () => { } beforeEach( () => { - document = new Document(); + document = new Document( new StylesProcessor() ); writer = new DowncastWriter( document ); } ); it( 'should throw when range placed in two containers', () => { - const p1 = new ContainerElement( 'p' ); - const p2 = new ContainerElement( 'p' ); + const p1 = new ContainerElement( document, 'p' ); + const p2 = new ContainerElement( document, 'p' ); expectToThrowCKEditorError( () => { writer.clear( Range._createFromParentsAndOffsets( p1, 0, p2, 0 ) ); @@ -46,7 +47,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw when range has no parent container', () => { - const el = new AttributeElement( 'b' ); + const el = new AttributeElement( document, 'b' ); expectToThrowCKEditorError( () => { writer.clear( Range._createFromParentsAndOffsets( el, 0, el, 0 ) ); @@ -54,7 +55,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should remove matched element from range', () => { - const elementToRemove = new AttributeElement( 'b' ); + const elementToRemove = new AttributeElement( document, 'b' ); testDowncast( elementToRemove, @@ -64,7 +65,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should remove matched element from range when range is inside text node', () => { - const elementToRemove = new AttributeElement( 'b' ); + const elementToRemove = new AttributeElement( document, 'b' ); testDowncast( elementToRemove, @@ -74,7 +75,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should remove multiple matched elements from range', () => { - const elementToRemove = new AttributeElement( 'b' ); + const elementToRemove = new AttributeElement( document, 'b' ); testDowncast( elementToRemove, @@ -84,7 +85,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should remove multiple matched elements from range when range is inside text node', () => { - const elementToRemove = new AttributeElement( 'b' ); + const elementToRemove = new AttributeElement( document, 'b' ); testDowncast( elementToRemove, @@ -94,7 +95,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should remove only matched element', () => { - const elementToRemove = new AttributeElement( 'b' ); + const elementToRemove = new AttributeElement( document, 'b' ); testDowncast( elementToRemove, @@ -104,7 +105,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should remove part of node when range ends inside this node', () => { - const elementToRemove = new AttributeElement( 'b' ); + const elementToRemove = new AttributeElement( document, 'b' ); testDowncast( elementToRemove, @@ -114,7 +115,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should remove part of node when range starts inside this node', () => { - const elementToRemove = new AttributeElement( 'b' ); + const elementToRemove = new AttributeElement( document, 'b' ); testDowncast( elementToRemove, @@ -124,7 +125,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should remove part of node when range starts and ends inside this node', () => { - const elementToRemove = new AttributeElement( 'b' ); + const elementToRemove = new AttributeElement( document, 'b' ); testDowncast( elementToRemove, @@ -134,7 +135,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should merge after removing', () => { - const elementToRemove = new AttributeElement( 'b' ); + const elementToRemove = new AttributeElement( document, 'b' ); testDowncast( elementToRemove, @@ -146,7 +147,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should remove EmptyElement', () => { - const elementToRemove = new EmptyElement( 'img' ); + const elementToRemove = new EmptyElement( document, 'img' ); testDowncast( elementToRemove, @@ -156,7 +157,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should remove UIElement', () => { - const elementToRemove = new UIElement( 'span' ); + const elementToRemove = new UIElement( document, 'span' ); testDowncast( elementToRemove, @@ -166,7 +167,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should remove ContainerElement', () => { - const elementToRemove = new ContainerElement( 'p' ); + const elementToRemove = new ContainerElement( document, 'p' ); testDowncast( elementToRemove, diff --git a/tests/view/downcastwriter/insert.js b/tests/view/downcastwriter/insert.js index 4bb7049e1..ba9ded24c 100644 --- a/tests/view/downcastwriter/insert.js +++ b/tests/view/downcastwriter/insert.js @@ -14,6 +14,7 @@ import { stringify, parse } from '../../../src/dev-utils/view'; import AttributeElement from '../../../src/view/attributeelement'; import Document from '../../../src/view/document'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DowncastWriter', () => { describe( 'insert()', () => { @@ -29,11 +30,12 @@ describe( 'DowncastWriter', () => { const { view, selection } = parse( input ); const newRange = writer.insert( selection.getFirstPosition(), nodesToInsert ); + expect( stringify( view.root, newRange, { showType: true, showPriority: true } ) ).to.equal( expected ); } beforeEach( () => { - document = new Document(); + document = new Document( new StylesProcessor() ); writer = new DowncastWriter( document ); } ); @@ -154,8 +156,8 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw when inserting Element', () => { - const element = new Element( 'b' ); - const container = new ContainerElement( 'p' ); + const element = new Element( document, 'b' ); + const container = new ContainerElement( document, 'p' ); const position = new Position( container, 0 ); expectToThrowCKEditorError( () => { @@ -164,9 +166,9 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw when Element is inserted as child node', () => { - const element = new Element( 'b' ); - const root = new ContainerElement( 'p', null, element ); - const container = new ContainerElement( 'p' ); + const element = new Element( document, 'b' ); + const root = new ContainerElement( document, 'p', null, element ); + const container = new ContainerElement( document, 'p' ); const position = new Position( container, 0 ); expectToThrowCKEditorError( () => { @@ -175,9 +177,9 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw when position is not placed inside container', () => { - const element = new Element( 'b' ); + const element = new Element( document, 'b' ); const position = new Position( element, 0 ); - const attributeElement = new AttributeElement( 'i' ); + const attributeElement = new AttributeElement( document, 'i' ); expectToThrowCKEditorError( () => { writer.insert( position, attributeElement ); @@ -193,10 +195,10 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if trying to insert inside EmptyElement', () => { - const emptyElement = new EmptyElement( 'img' ); - new ContainerElement( 'p', null, emptyElement ); // eslint-disable-line no-new + const emptyElement = new EmptyElement( document, 'img' ); + new ContainerElement( document, 'p', null, emptyElement ); // eslint-disable-line no-new const position = new Position( emptyElement, 0 ); - const attributeElement = new AttributeElement( 'i' ); + const attributeElement = new AttributeElement( document, 'i' ); expectToThrowCKEditorError( () => { writer.insert( position, attributeElement ); @@ -204,10 +206,10 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if trying to insert inside UIElement', () => { - const uiElement = new UIElement( 'span' ); - new ContainerElement( 'p', null, uiElement ); // eslint-disable-line no-new + const uiElement = new UIElement( document, 'span' ); + new ContainerElement( document, 'p', null, uiElement ); // eslint-disable-line no-new const position = new Position( uiElement, 0 ); - const attributeElement = new AttributeElement( 'i' ); + const attributeElement = new AttributeElement( document, 'i' ); expectToThrowCKEditorError( () => { writer.insert( position, attributeElement ); diff --git a/tests/view/downcastwriter/mergeattributes.js b/tests/view/downcastwriter/mergeattributes.js index 57ae6c514..7bf725dc1 100644 --- a/tests/view/downcastwriter/mergeattributes.js +++ b/tests/view/downcastwriter/mergeattributes.js @@ -9,10 +9,11 @@ import Text from '../../../src/view/text'; import Position from '../../../src/view/position'; import { stringify, parse } from '../../../src/dev-utils/view'; import Document from '../../../src/view/document'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DowncastWriter', () => { describe( 'mergeAttributes', () => { - let writer; + let writer, document; // Executes test using `parse` and `stringify` utils functions. Uses range delimiters `[]{}` to create and // test merge position. @@ -26,7 +27,8 @@ describe( 'DowncastWriter', () => { } before( () => { - writer = new DowncastWriter( new Document() ); + document = new Document( new StylesProcessor() ); + writer = new DowncastWriter( document ); } ); it( 'should not merge if inside text node', () => { @@ -63,9 +65,9 @@ describe( 'DowncastWriter', () => { it( 'should merge when placed between two text nodes', () => { //

foobar

->

foo|bar

- const t1 = new Text( 'foo' ); - const t2 = new Text( 'bar' ); - const p = new ContainerElement( 'p', null, [ t1, t2 ] ); + const t1 = new Text( document, 'foo' ); + const t2 = new Text( document, 'bar' ); + const p = new ContainerElement( document, 'p', null, [ t1, t2 ] ); const position = new Position( p, 1 ); const newPosition = writer.mergeAttributes( position ); diff --git a/tests/view/downcastwriter/mergecontainers.js b/tests/view/downcastwriter/mergecontainers.js index a337fa5aa..3ee50085e 100644 --- a/tests/view/downcastwriter/mergecontainers.js +++ b/tests/view/downcastwriter/mergecontainers.js @@ -8,6 +8,7 @@ import { stringify, parse } from '../../../src/dev-utils/view'; import Document from '../../../src/view/document'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DowncastWriter', () => { describe( 'mergeContainers()', () => { @@ -26,7 +27,7 @@ describe( 'DowncastWriter', () => { } before( () => { - writer = new DowncastWriter( new Document() ); + writer = new DowncastWriter( new Document( new StylesProcessor() ) ); } ); it( 'should merge two container elements - position between elements', () => { diff --git a/tests/view/downcastwriter/move.js b/tests/view/downcastwriter/move.js index 38172f207..21acbb2de 100644 --- a/tests/view/downcastwriter/move.js +++ b/tests/view/downcastwriter/move.js @@ -16,10 +16,11 @@ import Position from '../../../src/view/position'; import Document from '../../../src/view/document'; import Mapper from '../../../src/conversion/mapper'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DowncastWriter', () => { describe( 'move()', () => { - let writer; + let writer, document; // Executes test using `parse` and `stringify` utils functions. Uses range delimiters `[]{}` to create and // test ranges. @@ -38,7 +39,8 @@ describe( 'DowncastWriter', () => { } before( () => { - writer = new DowncastWriter( new Document() ); + document = new Document( new StylesProcessor() ); + writer = new DowncastWriter( document ); } ); it( 'should move single text node', () => { @@ -148,12 +150,12 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if trying to move to EmptyElement', () => { - const srcAttribute = new AttributeElement( 'b' ); - const srcContainer = new ContainerElement( 'p', null, srcAttribute ); + const srcAttribute = new AttributeElement( document, 'b' ); + const srcContainer = new ContainerElement( document, 'p', null, srcAttribute ); const srcRange = Range._createFromParentsAndOffsets( srcContainer, 0, srcContainer, 1 ); - const dstEmpty = new EmptyElement( 'img' ); - new ContainerElement( 'p', null, dstEmpty ); // eslint-disable-line no-new + const dstEmpty = new EmptyElement( document, 'img' ); + new ContainerElement( document, 'p', null, dstEmpty ); // eslint-disable-line no-new const dstPosition = new Position( dstEmpty, 0 ); expectToThrowCKEditorError( () => { @@ -171,12 +173,12 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if trying to move to UIElement', () => { - const srcAttribute = new AttributeElement( 'b' ); - const srcContainer = new ContainerElement( 'p', null, srcAttribute ); + const srcAttribute = new AttributeElement( document, 'b' ); + const srcContainer = new ContainerElement( document, 'p', null, srcAttribute ); const srcRange = Range._createFromParentsAndOffsets( srcContainer, 0, srcContainer, 1 ); - const dstUI = new UIElement( 'span' ); - new ContainerElement( 'p', null, dstUI ); // eslint-disable-line no-new + const dstUI = new UIElement( document, 'span' ); + new ContainerElement( document, 'p', null, dstUI ); // eslint-disable-line no-new const dstPosition = new Position( dstUI, 0 ); expectToThrowCKEditorError( () => { @@ -187,16 +189,16 @@ describe( 'DowncastWriter', () => { it( 'should not break marker mappings if marker element was split and the original element was removed', () => { const mapper = new Mapper(); - const srcContainer = new ContainerElement( 'p' ); - const dstContainer = new ContainerElement( 'p' ); + const srcContainer = new ContainerElement( document, 'p' ); + const dstContainer = new ContainerElement( document, 'p' ); - const root = new RootEditableElement( 'div' ); + const root = new RootEditableElement( document, 'div' ); root._appendChild( [ srcContainer, dstContainer ] ); - const attrElemA = new AttributeElement( 'span' ); + const attrElemA = new AttributeElement( document, 'span' ); attrElemA._id = 'foo'; - const attrElemB = new AttributeElement( 'span' ); + const attrElemB = new AttributeElement( document, 'span' ); attrElemB._id = 'foo'; writer.insert( new Position( srcContainer, 0 ), [ attrElemA, attrElemB ] ); diff --git a/tests/view/downcastwriter/remove.js b/tests/view/downcastwriter/remove.js index 8f2675061..7a8c1d874 100644 --- a/tests/view/downcastwriter/remove.js +++ b/tests/view/downcastwriter/remove.js @@ -14,6 +14,7 @@ import UIElement from '../../../src/view/uielement'; import Document from '../../../src/view/document'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DowncastWriter', () => { describe( 'remove()', () => { @@ -38,13 +39,13 @@ describe( 'DowncastWriter', () => { } beforeEach( () => { - document = new Document(); + document = new Document( new StylesProcessor() ); writer = new DowncastWriter( document ); } ); it( 'should throw when range placed in two containers', () => { - const p1 = new ContainerElement( 'p' ); - const p2 = new ContainerElement( 'p' ); + const p1 = new ContainerElement( document, 'p' ); + const p2 = new ContainerElement( document, 'p' ); expectToThrowCKEditorError( () => { writer.remove( Range._createFromParentsAndOffsets( p1, 0, p2, 0 ) ); @@ -52,7 +53,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw when range has no parent container', () => { - const el = new AttributeElement( 'b' ); + const el = new AttributeElement( document, 'b' ); expectToThrowCKEditorError( () => { writer.remove( Range._createFromParentsAndOffsets( el, 0, el, 0 ) ); @@ -60,7 +61,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should return empty DocumentFragment when range is collapsed', () => { - const p = new ContainerElement( 'p' ); + const p = new ContainerElement( document, 'p' ); const range = Range._createFromParentsAndOffsets( p, 0, p, 0 ); const fragment = writer.remove( range ); @@ -130,9 +131,9 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if range is placed inside EmptyElement', () => { - const emptyElement = new EmptyElement( 'img' ); - const attributeElement = new AttributeElement( 'b' ); - new ContainerElement( 'p', null, [ emptyElement, attributeElement ] ); // eslint-disable-line no-new + const emptyElement = new EmptyElement( document, 'img' ); + const attributeElement = new AttributeElement( document, 'b' ); + new ContainerElement( document, 'p', null, [ emptyElement, attributeElement ] ); // eslint-disable-line no-new const range = Range._createFromParentsAndOffsets( emptyElement, 0, attributeElement, 0 ); expectToThrowCKEditorError( () => { @@ -149,9 +150,9 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if range is placed inside UIElement', () => { - const uiElement = new UIElement( 'span' ); - const attributeElement = new AttributeElement( 'b' ); - new ContainerElement( 'p', null, [ uiElement, attributeElement ] ); // eslint-disable-line no-new + const uiElement = new UIElement( document, 'span' ); + const attributeElement = new AttributeElement( document, 'b' ); + new ContainerElement( document, 'p', null, [ uiElement, attributeElement ] ); // eslint-disable-line no-new const range = Range._createFromParentsAndOffsets( uiElement, 0, attributeElement, 0 ); expectToThrowCKEditorError( () => { @@ -201,7 +202,7 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw when item has no parent container', () => { - const el = new AttributeElement( 'b' ); + const el = new AttributeElement( document, 'b' ); expectToThrowCKEditorError( () => { writer.remove( el ); diff --git a/tests/view/downcastwriter/rename.js b/tests/view/downcastwriter/rename.js index 258a0e8c7..46b7e142d 100644 --- a/tests/view/downcastwriter/rename.js +++ b/tests/view/downcastwriter/rename.js @@ -6,13 +6,14 @@ import DowncastWriter from '../../../src/view/downcastwriter'; import { parse } from '../../../src/dev-utils/view'; import Document from '../../../src/view/document'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DowncastWriter', () => { describe( 'rename()', () => { let root, foo, writer; before( () => { - writer = new DowncastWriter( new Document() ); + writer = new DowncastWriter( new Document( new StylesProcessor() ) ); } ); beforeEach( () => { diff --git a/tests/view/downcastwriter/unwrap.js b/tests/view/downcastwriter/unwrap.js index 9c39e63b8..695430a01 100644 --- a/tests/view/downcastwriter/unwrap.js +++ b/tests/view/downcastwriter/unwrap.js @@ -16,6 +16,7 @@ import Text from '../../../src/view/text'; import { stringify, parse } from '../../../src/dev-utils/view'; import Document from '../../../src/view/document'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DowncastWriter', () => { describe( 'unwrap()', () => { @@ -34,7 +35,7 @@ describe( 'DowncastWriter', () => { } beforeEach( () => { - document = new Document(); + document = new Document( new StylesProcessor() ); writer = new DowncastWriter( document ); } ); @@ -55,12 +56,12 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw error when element is not instance of AttributeElement', () => { - const container = new ContainerElement( 'p', null, new AttributeElement( 'b', null, new Text( 'foo' ) ) ); + const container = new ContainerElement( document, 'p', null, new AttributeElement( document, 'b', null, new Text( 'foo' ) ) ); const range = new Range( new Position( container, 0 ), new Position( container, 1 ) ); - const b = new Element( 'b' ); + const b = new Element( document, 'b' ); expectToThrowCKEditorError( () => { writer.unwrap( range, b ); @@ -68,13 +69,13 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw error when range placed in two containers', () => { - const container1 = new ContainerElement( 'p' ); - const container2 = new ContainerElement( 'p' ); + const container1 = new ContainerElement( document, 'p' ); + const container2 = new ContainerElement( document, 'p' ); const range = new Range( new Position( container1, 0 ), new Position( container2, 1 ) ); - const b = new AttributeElement( 'b' ); + const b = new AttributeElement( document, 'b' ); expectToThrowCKEditorError( () => { writer.unwrap( range, b ); @@ -82,8 +83,8 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw when range has no parent container', () => { - const el = new AttributeElement( 'b' ); - const b = new AttributeElement( 'b' ); + const el = new AttributeElement( document, 'b' ); + const b = new AttributeElement( document, 'b' ); expectToThrowCKEditorError( () => { writer.unwrap( Range._createFromParentsAndOffsets( el, 0, el, 0 ), b ); @@ -396,9 +397,9 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if range is inside EmptyElement', () => { - const empty = new EmptyElement( 'img' ); - const attribute = new AttributeElement( 'b' ); - const container = new ContainerElement( 'p', null, [ empty, attribute ] ); + const empty = new EmptyElement( document, 'img' ); + const attribute = new AttributeElement( document, 'b' ); + const container = new ContainerElement( document, 'p', null, [ empty, attribute ] ); const range = Range._createFromParentsAndOffsets( empty, 0, container, 2 ); expectToThrowCKEditorError( () => { @@ -415,9 +416,9 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if range is placed inside UIElement', () => { - const uiElement = new UIElement( 'span' ); - const attribute = new AttributeElement( 'b' ); - const container = new ContainerElement( 'p', null, [ uiElement, attribute ] ); + const uiElement = new UIElement( document, 'span' ); + const attribute = new AttributeElement( document, 'b' ); + const container = new ContainerElement( document, 'p', null, [ uiElement, attribute ] ); const range = Range._createFromParentsAndOffsets( uiElement, 0, container, 2 ); expectToThrowCKEditorError( () => { diff --git a/tests/view/downcastwriter/wrap.js b/tests/view/downcastwriter/wrap.js index 061d288a3..89d8a8ef5 100644 --- a/tests/view/downcastwriter/wrap.js +++ b/tests/view/downcastwriter/wrap.js @@ -19,13 +19,14 @@ import { stringify, parse } from '../../../src/dev-utils/view'; import createViewRoot from '../_utils/createroot'; import Document from '../../../src/view/document'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DowncastWriter', () => { describe( 'wrap()', () => { let writer, document; beforeEach( () => { - document = new Document(); + document = new Document( new StylesProcessor() ); writer = new DowncastWriter( document ); } ); @@ -62,12 +63,12 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw error when element is not instance of AttributeElement', () => { - const container = new ContainerElement( 'p', null, new Text( 'foo' ) ); + const container = new ContainerElement( document, 'p', null, new Text( 'foo' ) ); const range = new Range( new Position( container, 0 ), new Position( container, 1 ) ); - const b = new Element( 'b' ); + const b = new Element( document, 'b' ); expectToThrowCKEditorError( () => { writer.wrap( range, b ); @@ -75,13 +76,13 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw error when range placed in two containers', () => { - const container1 = new ContainerElement( 'p' ); - const container2 = new ContainerElement( 'p' ); + const container1 = new ContainerElement( document, 'p' ); + const container2 = new ContainerElement( document, 'p' ); const range = new Range( new Position( container1, 0 ), new Position( container2, 1 ) ); - const b = new AttributeElement( 'b' ); + const b = new AttributeElement( document, 'b' ); expectToThrowCKEditorError( () => { writer.wrap( range, b ); @@ -89,8 +90,8 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw when range has no parent container', () => { - const el = new AttributeElement( 'b' ); - const b = new AttributeElement( 'b' ); + const el = new AttributeElement( document, 'b' ); + const b = new AttributeElement( document, 'b' ); expectToThrowCKEditorError( () => { writer.wrap( Range._createFromParentsAndOffsets( el, 0, el, 0 ), b ); @@ -394,12 +395,12 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if range is inside EmptyElement', () => { - const emptyElement = new EmptyElement( 'img' ); - const container = new ContainerElement( 'p', null, emptyElement ); + const emptyElement = new EmptyElement( document, 'img' ); + const container = new ContainerElement( document, 'p', null, emptyElement ); const range = Range._createFromParentsAndOffsets( emptyElement, 0, container, 1 ); expectToThrowCKEditorError( () => { - writer.wrap( range, new AttributeElement( 'b' ) ); + writer.wrap( range, new AttributeElement( document, 'b' ) ); }, 'view-writer-cannot-break-empty-element', document ); } ); @@ -412,12 +413,12 @@ describe( 'DowncastWriter', () => { } ); it( 'should throw if range is inside UIElement', () => { - const uiElement = new UIElement( 'span' ); - const container = new ContainerElement( 'p', null, uiElement ); + const uiElement = new UIElement( document, 'span' ); + const container = new ContainerElement( document, 'p', null, uiElement ); const range = Range._createFromParentsAndOffsets( uiElement, 0, container, 1 ); expectToThrowCKEditorError( () => { - writer.wrap( range, new AttributeElement( 'b' ) ); + writer.wrap( range, new AttributeElement( document, 'b' ) ); }, 'view-writer-cannot-break-ui-element', document ); } ); @@ -520,7 +521,7 @@ describe( 'DowncastWriter', () => { let view, viewDocument, viewRoot; beforeEach( () => { - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; viewRoot = createViewRoot( viewDocument ); } ); @@ -543,15 +544,15 @@ describe( 'DowncastWriter', () => { const newPosition = writer.wrap( selection.getFirstRange(), parse( wrapAttribute ) ); // Moving parsed elements to a document fragment so the view root is not shown in `stringify`. - const viewChildren = new DocumentFragment( view.getChildren() ); + const viewChildren = new DocumentFragment( viewDocument, view.getChildren() ); expect( stringify( viewChildren, newPosition, { showType: true, showPriority: true } ) ).to.equal( expected ); } it( 'should throw error when element is not instance of AttributeElement', () => { - const container = new ContainerElement( 'p', null, new Text( 'foo' ) ); + const container = new ContainerElement( document, 'p', null, new Text( 'foo' ) ); const position = new Position( container, 0 ); - const b = new Element( 'b' ); + const b = new Element( document, 'b' ); expectToThrowCKEditorError( () => { writer.wrap( new Range( position ), b ); diff --git a/tests/view/downcastwriter/writer.js b/tests/view/downcastwriter/writer.js index 05651fdb2..971f1d428 100644 --- a/tests/view/downcastwriter/writer.js +++ b/tests/view/downcastwriter/writer.js @@ -11,13 +11,14 @@ import ViewRange from '../../../src/view/range'; import createViewRoot from '../_utils/createroot'; import ViewElement from '../../../src/view/element'; import ViewSelection from '../../../src/view/selection'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DowncastWriter', () => { let writer, attributes, root, doc; beforeEach( () => { attributes = { foo: 'bar', baz: 'quz' }; - doc = new Document(); + doc = new Document( new StylesProcessor() ); root = createViewRoot( doc ); writer = new DowncastWriter( doc ); } ); diff --git a/tests/view/editableelement.js b/tests/view/editableelement.js index ea66e7726..b956dbf5c 100644 --- a/tests/view/editableelement.js +++ b/tests/view/editableelement.js @@ -7,14 +7,15 @@ import createDocumentMock from '../../tests/view/_utils/createdocumentmock'; import EditableElement from '../../src/view/editableelement'; import Range from '../../src/view/range'; -import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import Document from '../../src/view/document'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'EditableElement', () => { describe( 'is', () => { let el; before( () => { - el = new EditableElement( 'div' ); + el = new EditableElement( new Document( new StylesProcessor() ), 'div' ); } ); it( 'should return true for containerElement/editable/element, also with correct name and element name', () => { @@ -52,58 +53,20 @@ describe( 'EditableElement', () => { } ); } ); - describe( 'document', () => { - let element, docMock; - - beforeEach( () => { - element = new EditableElement( 'div' ); - docMock = createDocumentMock(); - } ); - - it( 'should allow to set document', () => { - element._document = docMock; - - expect( element.document ).to.equal( docMock ); - } ); - - it( 'should return undefined if document is not set', () => { - expect( element.document ).to.be.undefined; - } ); - - it( 'should throw if trying to set document again', () => { - element._document = docMock; - const newDoc = createDocumentMock(); - - expectToThrowCKEditorError( () => { - element._document = newDoc; - }, 'view-editableelement-document-already-set: View document is already set.', docMock ); - } ); - - it( 'should be cloned properly', () => { - element._document = docMock; - const newElement = element._clone(); - - expect( newElement.document ).to.equal( docMock ); - } ); - } ); - describe( 'isFocused', () => { let docMock, viewMain, viewHeader; beforeEach( () => { docMock = createDocumentMock(); - viewMain = new EditableElement( 'div' ); - viewMain._document = docMock; + viewMain = new EditableElement( docMock, 'div' ); - viewHeader = new EditableElement( 'h1' ); - viewHeader._document = docMock; + viewHeader = new EditableElement( docMock, 'h1' ); viewHeader.rootName = 'header'; } ); it( 'should be observable', () => { - const root = new EditableElement( 'div' ); - root._document = createDocumentMock(); + const root = new EditableElement( docMock, 'div' ); expect( root.isFocused ).to.be.false; @@ -155,9 +118,14 @@ describe( 'EditableElement', () => { } ); describe( 'isReadOnly', () => { + let docMock; + + beforeEach( () => { + docMock = createDocumentMock(); + } ); + it( 'should be observable', () => { - const root = new EditableElement( 'div' ); - root._document = createDocumentMock(); + const root = new EditableElement( docMock, 'div' ); expect( root.isReadOnly ).to.be.false; @@ -173,8 +141,7 @@ describe( 'EditableElement', () => { } ); it( 'should be bound to the document#isReadOnly', () => { - const root = new EditableElement( 'div' ); - root._document = createDocumentMock(); + const root = new EditableElement( docMock, 'div' ); root.document.isReadOnly = false; @@ -186,13 +153,18 @@ describe( 'EditableElement', () => { } ); } ); - describe( 'getDocument', () => { - it( 'should return document', () => { - const docMock = createDocumentMock(); - const root = new EditableElement( 'div' ); - root._document = docMock; + describe( 'document', () => { + let element, docMock; + + beforeEach( () => { + docMock = createDocumentMock(); + element = new EditableElement( docMock, 'div' ); + } ); - expect( root.document ).to.equal( docMock ); + it( 'should be cloned properly', () => { + const newElement = element._clone(); + + expect( newElement.document ).to.equal( docMock ); } ); } ); } ); diff --git a/tests/view/element.js b/tests/view/element.js index da77ac34f..1a4bbd498 100644 --- a/tests/view/element.js +++ b/tests/view/element.js @@ -8,11 +8,19 @@ import Node from '../../src/view/node'; import Element from '../../src/view/element'; import Text from '../../src/view/text'; import TextProxy from '../../src/view/textproxy'; +import Document from '../../src/view/document'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'Element', () => { + let document; + + beforeEach( () => { + document = new Document( new StylesProcessor() ); + } ); + describe( 'constructor()', () => { it( 'should create element without attributes', () => { - const el = new Element( 'p' ); + const el = new Element( document, 'p' ); expect( el ).to.be.an.instanceof( Node ); expect( el ).to.have.property( 'name' ).that.equals( 'p' ); @@ -21,7 +29,7 @@ describe( 'Element', () => { } ); it( 'should create element with attributes as plain object', () => { - const el = new Element( 'p', { foo: 'bar' } ); + const el = new Element( document, 'p', { foo: 'bar' } ); expect( el ).to.have.property( 'name' ).that.equals( 'p' ); expect( count( el.getAttributeKeys() ) ).to.equal( 1 ); @@ -32,7 +40,7 @@ describe( 'Element', () => { const attrs = new Map(); attrs.set( 'foo', 'bar' ); - const el = new Element( 'p', attrs ); + const el = new Element( document, 'p', attrs ); expect( el ).to.have.property( 'name' ).that.equals( 'p' ); expect( count( el.getAttributeKeys() ) ).to.equal( 1 ); @@ -40,7 +48,7 @@ describe( 'Element', () => { } ); it( 'should stringify attributes', () => { - const el = new Element( 'p', { foo: true, bar: null, object: {} } ); + const el = new Element( document, 'p', { foo: true, bar: null, object: {} } ); expect( el.getAttribute( 'foo' ) ).to.equal( 'true' ); expect( el.getAttribute( 'bar' ) ).to.be.undefined; @@ -48,8 +56,8 @@ describe( 'Element', () => { } ); it( 'should create element with children', () => { - const child = new Element( 'p', { foo: 'bar' } ); - const parent = new Element( 'div', [], [ child ] ); + const child = new Element( document, 'p', { foo: 'bar' } ); + const parent = new Element( document, 'div', [], [ child ] ); expect( parent ).to.have.property( 'name' ).that.equals( 'div' ); expect( parent.childCount ).to.equal( 1 ); @@ -57,7 +65,7 @@ describe( 'Element', () => { } ); it( 'should move class attribute to class set ', () => { - const el = new Element( 'p', { id: 'test', class: 'one two three' } ); + const el = new Element( document, 'p', { id: 'test', class: 'one two three' } ); expect( el._attrs.has( 'class' ) ).to.be.false; expect( el._attrs.has( 'id' ) ).to.be.true; @@ -67,7 +75,7 @@ describe( 'Element', () => { } ); it( 'should move style attribute to style proxy', () => { - const el = new Element( 'p', { id: 'test', style: 'one: style1; two:style2 ; three : url(http://ckeditor.com)' } ); + const el = new Element( document, 'p', { id: 'test', style: 'one: style1; two:style2 ; three : url(http://ckeditor.com)' } ); expect( el._attrs.has( 'style' ) ).to.be.false; expect( el._attrs.has( 'id' ) ).to.be.true; @@ -85,7 +93,7 @@ describe( 'Element', () => { let el; before( () => { - el = new Element( 'p' ); + el = new Element( document, 'p' ); } ); it( 'should return true for node, element, element with correct name and element name', () => { @@ -120,13 +128,13 @@ describe( 'Element', () => { describe( 'isEmpty', () => { it( 'should return true if there are no children in element', () => { - const element = new Element( 'p' ); + const element = new Element( document, 'p' ); expect( element.isEmpty ).to.be.true; } ); it( 'should return false if there are children in element', () => { - const fragment = new Element( 'p', null, new Element( 'img' ) ); + const fragment = new Element( document, 'p', null, new Element( document, 'img' ) ); expect( fragment.isEmpty ).to.be.false; } ); @@ -134,7 +142,7 @@ describe( 'Element', () => { describe( '_clone()', () => { it( 'should clone element', () => { - const el = new Element( 'p', { attr1: 'foo', attr2: 'bar' } ); + const el = new Element( document, 'p', { attr1: 'foo', attr2: 'bar' } ); const clone = el._clone(); expect( clone ).to.not.equal( el ); @@ -144,9 +152,9 @@ describe( 'Element', () => { } ); it( 'should deeply clone element', () => { - const el = new Element( 'p', { attr1: 'foo', attr2: 'bar' }, [ - new Element( 'b', { attr: 'baz' } ), - new Element( 'span', { attr: 'qux' } ) + const el = new Element( document, 'p', { attr1: 'foo', attr2: 'bar' }, [ + new Element( document, 'b', { attr: 'baz' } ), + new Element( document, 'span', { attr: 'qux' } ) ] ); const count = el.childCount; const clone = el._clone( true ); @@ -168,9 +176,9 @@ describe( 'Element', () => { } ); it( 'shouldn\'t clone any children when deep copy is not performed', () => { - const el = new Element( 'p', { attr1: 'foo', attr2: 'bar' }, [ - new Element( 'b', { attr: 'baz' } ), - new Element( 'span', { attr: 'qux' } ) + const el = new Element( document, 'p', { attr1: 'foo', attr2: 'bar' }, [ + new Element( document, 'b', { attr: 'baz' } ), + new Element( document, 'span', { attr: 'qux' } ) ] ); const clone = el._clone( false ); @@ -182,7 +190,7 @@ describe( 'Element', () => { } ); it( 'should clone class attribute', () => { - const el = new Element( 'p', { foo: 'bar' } ); + const el = new Element( document, 'p', { foo: 'bar' } ); el._addClass( [ 'baz', 'qux' ] ); const clone = el._clone( false ); @@ -193,7 +201,7 @@ describe( 'Element', () => { } ); it( 'should clone style attribute', () => { - const el = new Element( 'p', { style: 'color: red; font-size: 12px;' } ); + const el = new Element( document, 'p', { style: 'color: red; font-size: 12px;' } ); const clone = el._clone( false ); expect( clone ).to.not.equal( el ); @@ -205,7 +213,7 @@ describe( 'Element', () => { } ); it( 'should clone custom properties', () => { - const el = new Element( 'p' ); + const el = new Element( document, 'p' ); const symbol = Symbol( 'custom' ); el._setCustomProperty( 'foo', 'bar' ); el._setCustomProperty( symbol, 'baz' ); @@ -217,7 +225,7 @@ describe( 'Element', () => { } ); it( 'should clone getFillerOffset', () => { - const el = new Element( 'p' ); + const el = new Element( document, 'p' ); const fm = () => 'foo bar'; expect( el.getFillerOffset ).to.be.undefined; @@ -230,7 +238,12 @@ describe( 'Element', () => { } ); describe( 'isSimilar()', () => { - const el = new Element( 'p', { foo: 'bar' } ); + let el; + + beforeEach( () => { + el = new Element( document, 'p', { foo: 'bar' } ); + } ); + it( 'should return false when comparing to non-element', () => { expect( el.isSimilar( null ) ).to.be.false; expect( el.isSimilar( {} ) ).to.be.false; @@ -241,7 +254,7 @@ describe( 'Element', () => { } ); it( 'should return true for element with same attributes and name', () => { - const other = new Element( 'p', { foo: 'bar' } ); + const other = new Element( document, 'p', { foo: 'bar' } ); expect( el.isSimilar( other ) ).to.be.true; } ); @@ -265,10 +278,10 @@ describe( 'Element', () => { } ); it( 'should compare class attribute', () => { - const el1 = new Element( 'p' ); - const el2 = new Element( 'p' ); - const el3 = new Element( 'p' ); - const el4 = new Element( 'p' ); + const el1 = new Element( document, 'p' ); + const el2 = new Element( document, 'p' ); + const el3 = new Element( document, 'p' ); + const el4 = new Element( document, 'p' ); el1._addClass( [ 'foo', 'bar' ] ); el2._addClass( [ 'bar', 'foo' ] ); @@ -284,8 +297,8 @@ describe( 'Element', () => { let element, other; beforeEach( () => { - element = new Element( 'p' ); - other = new Element( 'p' ); + element = new Element( document, 'p' ); + other = new Element( document, 'p' ); element._setStyle( 'color', 'red' ); element._setStyle( 'top', '10px' ); @@ -338,11 +351,11 @@ describe( 'Element', () => { let parent, el1, el2, el3, el4; beforeEach( () => { - parent = new Element( 'p' ); - el1 = new Element( 'el1' ); - el2 = new Element( 'el2' ); - el3 = new Element( 'el3' ); - el4 = new Element( 'el4' ); + parent = new Element( document, 'p' ); + el1 = new Element( document, 'el1' ); + el2 = new Element( document, 'el2' ); + el3 = new Element( document, 'el3' ); + el4 = new Element( document, 'el4' ); } ); describe( 'insertion', () => { @@ -365,7 +378,7 @@ describe( 'Element', () => { expect( parent.getChild( 0 ) ).to.have.property( 'data' ).that.equals( 'abc' ); parent._removeChildren( 0, 1 ); - parent._insertChild( 0, [ new Element( 'p' ), 'abc' ] ); + parent._insertChild( 0, [ new Element( document, 'p' ), 'abc' ] ); expect( parent.childCount ).to.equal( 2 ); expect( parent.getChild( 1 ) ).to.have.property( 'data' ).that.equals( 'abc' ); @@ -386,8 +399,8 @@ describe( 'Element', () => { } ); it( 'should accept and correctly handle text proxies', () => { - const element = new Element( 'div' ); - const text = new Text( 'abcxyz' ); + const element = new Element( document, 'div' ); + const text = new Text( document, 'abcxyz' ); const textProxy = new TextProxy( text, 2, 3 ); element._insertChild( 0, textProxy ); @@ -396,6 +409,15 @@ describe( 'Element', () => { expect( element.getChild( 0 ) ).to.be.instanceof( Text ); expect( element.getChild( 0 ).data ).to.equal( 'cxy' ); } ); + + it( 'set proper #document on inserted children', () => { + const anotherDocument = new Document( new StylesProcessor() ); + const anotherEl = new Element( anotherDocument, 'p' ); + + parent._insertChild( 0, anotherEl ); + + expect( anotherEl.document ).to.be.equal( document ); + } ); } ); describe( 'getChildIndex', () => { @@ -469,7 +491,7 @@ describe( 'Element', () => { let el; beforeEach( () => { - el = new Element( 'p' ); + el = new Element( document, 'p' ); } ); describe( '_setAttribute', () => { @@ -662,7 +684,7 @@ describe( 'Element', () => { it( 'should remove class attribute', () => { el._addClass( [ 'foo', 'bar' ] ); - const el2 = new Element( 'p' ); + const el2 = new Element( document, 'p' ); const removed1 = el._removeAttribute( 'class' ); const removed2 = el2._removeAttribute( 'class' ); @@ -676,7 +698,7 @@ describe( 'Element', () => { it( 'should remove style attribute', () => { el._setStyle( 'color', 'red' ); el._setStyle( 'position', 'fixed' ); - const el2 = new Element( 'p' ); + const el2 = new Element( document, 'p' ); const removed1 = el._removeAttribute( 'style' ); const removed2 = el2._removeAttribute( 'style' ); @@ -693,7 +715,7 @@ describe( 'Element', () => { let el; beforeEach( () => { - el = new Element( 'p' ); + el = new Element( document, 'p' ); } ); describe( '_addClass()', () => { @@ -791,7 +813,7 @@ describe( 'Element', () => { let el; beforeEach( () => { - el = new Element( 'p' ); + el = new Element( document, 'p' ); } ); describe( '_setStyle()', () => { @@ -919,29 +941,29 @@ describe( 'Element', () => { describe( 'findAncestor', () => { it( 'should return null if element have no ancestor', () => { - const el = new Element( 'p' ); + const el = new Element( document, 'p' ); expect( el.findAncestor( 'div' ) ).to.be.null; } ); it( 'should return ancestor if matching', () => { - const el1 = new Element( 'p' ); - const el2 = new Element( 'div', null, el1 ); + const el1 = new Element( document, 'p' ); + const el2 = new Element( document, 'div', null, el1 ); expect( el1.findAncestor( 'div' ) ).to.equal( el2 ); } ); it( 'should return parent\'s ancestor if matching', () => { - const el1 = new Element( 'p' ); - const el2 = new Element( 'div', null, el1 ); - const el3 = new Element( 'div', { class: 'foo bar' }, el2 ); + const el1 = new Element( document, 'p' ); + const el2 = new Element( document, 'div', null, el1 ); + const el3 = new Element( document, 'div', { class: 'foo bar' }, el2 ); expect( el1.findAncestor( { classes: 'foo' } ) ).to.equal( el3 ); } ); it( 'should return null if no matches found', () => { - const el1 = new Element( 'p' ); - new Element( 'div', null, el1 ); // eslint-disable-line no-new + const el1 = new Element( document, 'p' ); + new Element( document, 'div', null, el1 ); // eslint-disable-line no-new expect( el1.findAncestor( { name: 'div', @@ -952,14 +974,14 @@ describe( 'Element', () => { describe( 'custom properties', () => { it( 'should allow to set and get custom properties', () => { - const el = new Element( 'p' ); + const el = new Element( document, 'p' ); el._setCustomProperty( 'foo', 'bar' ); expect( el.getCustomProperty( 'foo' ) ).to.equal( 'bar' ); } ); it( 'should allow to add symbol property', () => { - const el = new Element( 'p' ); + const el = new Element( document, 'p' ); const symbol = Symbol( 'custom' ); el._setCustomProperty( symbol, 'bar' ); @@ -967,7 +989,7 @@ describe( 'Element', () => { } ); it( 'should allow to remove custom property', () => { - const el = new Element( 'foo' ); + const el = new Element( document, 'foo' ); const symbol = Symbol( 'quix' ); el._setCustomProperty( 'bar', 'baz' ); el._setCustomProperty( symbol, 'test' ); @@ -983,7 +1005,7 @@ describe( 'Element', () => { } ); it( 'should allow to iterate over custom properties', () => { - const el = new Element( 'p' ); + const el = new Element( document, 'p' ); el._setCustomProperty( 'foo', 1 ); el._setCustomProperty( 'bar', 2 ); el._setCustomProperty( 'baz', 3 ); @@ -1001,20 +1023,20 @@ describe( 'Element', () => { describe( 'getIdentity()', () => { it( 'should return only name if no other attributes are present', () => { - const el = new Element( 'foo' ); + const el = new Element( document, 'foo' ); expect( el.getIdentity() ).to.equal( 'foo' ); } ); it( 'should return classes in sorted order', () => { - const el = new Element( 'fruit' ); + const el = new Element( document, 'fruit' ); el._addClass( [ 'banana', 'lemon', 'apple' ] ); expect( el.getIdentity() ).to.equal( 'fruit class="apple,banana,lemon"' ); } ); it( 'should return styles in sorted order', () => { - const el = new Element( 'foo', { + const el = new Element( document, 'foo', { style: 'margin-top: 2em; background-color: red' } ); @@ -1022,7 +1044,7 @@ describe( 'Element', () => { } ); it( 'should return attributes in sorted order', () => { - const el = new Element( 'foo', { + const el = new Element( document, 'foo', { a: 1, d: 4, b: 3 @@ -1032,7 +1054,7 @@ describe( 'Element', () => { } ); it( 'should return classes, styles and attributes', () => { - const el = new Element( 'baz', { + const el = new Element( document, 'baz', { foo: 'one', bar: 'two', style: 'text-align:center;border-radius:10px' diff --git a/tests/view/emptyelement.js b/tests/view/emptyelement.js index 577d6f6d7..e1696a5b2 100644 --- a/tests/view/emptyelement.js +++ b/tests/view/emptyelement.js @@ -5,15 +5,18 @@ import EmptyElement from '../../src/view/emptyelement'; import Element from '../../src/view/element'; +import Document from '../../src/view/document'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'EmptyElement', () => { - let element, emptyElement; + let element, emptyElement, document; beforeEach( () => { - element = new Element( 'b' ); - emptyElement = new EmptyElement( 'img', { + document = new Document( new StylesProcessor() ); + element = new Element( document, 'b' ); + emptyElement = new EmptyElement( document, 'img', { alt: 'alternative text', style: 'margin-top: 2em;color: white;', class: 'image big' @@ -24,7 +27,7 @@ describe( 'EmptyElement', () => { let el; before( () => { - el = new EmptyElement( 'p' ); + el = new EmptyElement( document, 'p' ); } ); it( 'should return true for emptyElement/element, also with correct name and element name', () => { @@ -59,10 +62,10 @@ describe( 'EmptyElement', () => { } ); it( 'should throw if child elements are passed to constructor', () => { - const el = new Element( 'i' ); + const el = new Element( document, 'i' ); expectToThrowCKEditorError( () => { - new EmptyElement( 'img', null, [ el ] ); // eslint-disable-line no-new + new EmptyElement( document, 'img', null, [ el ] ); // eslint-disable-line no-new }, 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.', el ); } ); diff --git a/tests/view/manual/clickobserver.js b/tests/view/manual/clickobserver.js index df1289598..ac7f67541 100644 --- a/tests/view/manual/clickobserver.js +++ b/tests/view/manual/clickobserver.js @@ -8,8 +8,9 @@ import View from '../../../src/view/view'; import DomEventObserver from '../../../src/view/observer/domeventobserver'; import createViewRoot from '../_utils/createroot'; +import { StylesProcessor } from '../../../src/view/stylesmap'; -const view = new View(); +const view = new View( new StylesProcessor() ); const viewDocument = view.document; // Disable rendering for this example, because it re-enables all observers each time view is rendered. diff --git a/tests/view/manual/fakeselection.js b/tests/view/manual/fakeselection.js index 019a8c504..eff403434 100644 --- a/tests/view/manual/fakeselection.js +++ b/tests/view/manual/fakeselection.js @@ -10,8 +10,9 @@ import DomEventObserver from '../../../src/view/observer/domeventobserver'; import ViewRange from '../../../src/view/range'; import createViewRoot from '../_utils/createroot'; import { setData } from '../../../src/dev-utils/view'; +import { StylesProcessor } from '../../../src/view/stylesmap'; -const view = new View(); +const view = new View( new StylesProcessor() ); const viewDocument = view.document; const domEditable = document.getElementById( 'editor' ); const viewRoot = createViewRoot( viewDocument ); diff --git a/tests/view/manual/focus.js b/tests/view/manual/focus.js index 78b2a54ed..e73ad2350 100644 --- a/tests/view/manual/focus.js +++ b/tests/view/manual/focus.js @@ -9,8 +9,9 @@ import View from '../../../src/view/view'; import ViewPosition from '../../../src/view/position'; import ViewRange from '../../../src/view/range'; import createViewRoot from '../_utils/createroot'; +import { StylesProcessor } from '../../../src/view/stylesmap'; -const view = new View(); +const view = new View( new StylesProcessor() ); const viewDocument = view.document; const domEditable1 = document.getElementById( 'editable1' ); diff --git a/tests/view/manual/focusobserver.js b/tests/view/manual/focusobserver.js index ba1eef1d1..13b0ce5ca 100644 --- a/tests/view/manual/focusobserver.js +++ b/tests/view/manual/focusobserver.js @@ -7,8 +7,9 @@ import View from '../../../src/view/view'; import createViewRoot from '../_utils/createroot'; +import { StylesProcessor } from '../../../src/view/stylesmap'; -const view = new View(); +const view = new View( new StylesProcessor() ); const viewDocument = view.document; viewDocument.on( 'focus', ( evt, data ) => console.log( `Focus in ${ data.domTarget.id }.` ) ); diff --git a/tests/view/manual/immutable.js b/tests/view/manual/immutable.js index 244695a61..243cebaf6 100644 --- a/tests/view/manual/immutable.js +++ b/tests/view/manual/immutable.js @@ -8,8 +8,9 @@ import View from '../../../src/view/view'; import { setData } from '../../../src/dev-utils/view'; import createViewRoot from '../_utils/createroot'; +import { StylesProcessor } from '../../../src/view/stylesmap'; -const view = new View(); +const view = new View( new StylesProcessor() ); const viewDocument = view.document; createViewRoot( viewDocument, 'div' ); view.attachDomRoot( document.getElementById( 'editor' ) ); diff --git a/tests/view/manual/inline-filler.js b/tests/view/manual/inline-filler.js index 28bfabc17..c2b4c6238 100644 --- a/tests/view/manual/inline-filler.js +++ b/tests/view/manual/inline-filler.js @@ -8,8 +8,9 @@ import View from '../../../src/view/view'; import createViewRoot from '../_utils/createroot'; import { setData } from '../../../src/dev-utils/view'; +import { StylesProcessor } from '../../../src/view/stylesmap'; -const view = new View(); +const view = new View( new StylesProcessor() ); const viewDocument = view.document; createViewRoot( viewDocument ); view.attachDomRoot( document.getElementById( 'editor' ) ); diff --git a/tests/view/manual/keyobserver.js b/tests/view/manual/keyobserver.js index d39221af2..3cc9bd0d0 100644 --- a/tests/view/manual/keyobserver.js +++ b/tests/view/manual/keyobserver.js @@ -7,8 +7,9 @@ import View from '../../../src/view/view'; import createViewRoot from '../_utils/createroot'; +import { StylesProcessor } from '../../../src/view/stylesmap'; -const view = new View(); +const view = new View( new StylesProcessor() ); const viewDocument = view.document; viewDocument.on( 'keydown', ( evt, data ) => console.log( 'keydown', data ) ); diff --git a/tests/view/manual/mutationobserver.js b/tests/view/manual/mutationobserver.js index 85272d161..8306de744 100644 --- a/tests/view/manual/mutationobserver.js +++ b/tests/view/manual/mutationobserver.js @@ -8,8 +8,9 @@ import View from '../../../src/view/view'; import createViewRoot from '../_utils/createroot'; import { setData } from '../../../src/dev-utils/view'; +import { StylesProcessor } from '../../../src/view/stylesmap'; -const view = new View(); +const view = new View( new StylesProcessor() ); const viewDocument = view.document; createViewRoot( viewDocument ); view.attachDomRoot( document.getElementById( 'editor' ) ); diff --git a/tests/view/manual/noselection-iframe.js b/tests/view/manual/noselection-iframe.js index 0564e9fe8..2ff1a4b3b 100644 --- a/tests/view/manual/noselection-iframe.js +++ b/tests/view/manual/noselection-iframe.js @@ -8,12 +8,13 @@ import View from '../../../src/view/view'; import { setData } from '../../../src/dev-utils/view'; import createViewRoot from '../_utils/createroot'; +import { StylesProcessor } from '../../../src/view/stylesmap'; const iframe = document.getElementById( 'iframe' ); iframe.srcdoc = '
'; iframe.addEventListener( 'load', () => { - const view = new View(); + const view = new View( new StylesProcessor() ); const viewDocument = view.document; createViewRoot( viewDocument ); diff --git a/tests/view/manual/noselection.js b/tests/view/manual/noselection.js index 390f5ca43..b836460c7 100644 --- a/tests/view/manual/noselection.js +++ b/tests/view/manual/noselection.js @@ -8,8 +8,9 @@ import View from '../../../src/view/view'; import { setData } from '../../../src/dev-utils/view'; import createViewRoot from '../_utils/createroot'; +import { StylesProcessor } from '../../../src/view/stylesmap'; -const view = new View(); +const view = new View( new StylesProcessor() ); const viewDocument = view.document; createViewRoot( viewDocument ); view.attachDomRoot( document.getElementById( 'editor' ) ); diff --git a/tests/view/manual/selectionobserver.js b/tests/view/manual/selectionobserver.js index 01a5eedc4..9a81860b1 100644 --- a/tests/view/manual/selectionobserver.js +++ b/tests/view/manual/selectionobserver.js @@ -8,8 +8,9 @@ import View from '../../../src/view/view'; import { setData } from '../../../src/dev-utils/view'; import createViewRoot from '../_utils/createroot'; +import { StylesProcessor } from '../../../src/view/stylesmap'; -const view = new View(); +const view = new View( new StylesProcessor() ); const viewDocument = view.document; createViewRoot( viewDocument ); view.attachDomRoot( document.getElementById( 'editor' ) ); diff --git a/tests/view/manual/x-index.js b/tests/view/manual/x-index.js index d6087a774..801eab3cb 100644 --- a/tests/view/manual/x-index.js +++ b/tests/view/manual/x-index.js @@ -8,8 +8,9 @@ import View from '../../../src/view/view'; import { setData } from '../../../src/dev-utils/view'; import createViewRoot from '../_utils/createroot'; +import { StylesProcessor } from '../../../src/view/stylesmap'; -const view = new View(); +const view = new View( new StylesProcessor() ); const viewDocument = view.document; createViewRoot( viewDocument ); view.attachDomRoot( document.getElementById( 'editor' ) ); diff --git a/tests/view/matcher.js b/tests/view/matcher.js index 42d2171df..3b78b67db 100644 --- a/tests/view/matcher.js +++ b/tests/view/matcher.js @@ -5,12 +5,20 @@ import Matcher from '../../src/view/matcher'; import Element from '../../src/view/element'; +import Document from '../../src/view/document'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'Matcher', () => { + let document; + + beforeEach( () => { + document = new Document( new StylesProcessor() ); + } ); + describe( 'add', () => { it( 'should allow to add pattern to matcher', () => { const matcher = new Matcher( 'div' ); - const el = new Element( 'p', { title: 'foobar' } ); + const el = new Element( document, 'p', { title: 'foobar' } ); expect( matcher.match( el ) ).to.be.null; const pattern = { name: 'p', attributes: { title: 'foobar' } }; @@ -26,8 +34,8 @@ describe( 'Matcher', () => { it( 'should allow to add more than one pattern', () => { const matcher = new Matcher(); - const el1 = new Element( 'p' ); - const el2 = new Element( 'div' ); + const el1 = new Element( document, 'p' ); + const el2 = new Element( document, 'div' ); matcher.add( 'p', 'div' ); @@ -46,8 +54,8 @@ describe( 'Matcher', () => { describe( 'match', () => { it( 'should match element name', () => { const matcher = new Matcher( 'p' ); - const el = new Element( 'p' ); - const el2 = new Element( 'div' ); + const el = new Element( document, 'p' ); + const el2 = new Element( document, 'div' ); const result = matcher.match( el ); @@ -63,8 +71,8 @@ describe( 'Matcher', () => { it( 'should match element name with RegExp', () => { const pattern = /^text...a$/; const matcher = new Matcher( pattern ); - const el1 = new Element( 'textarea' ); - const el2 = new Element( 'div' ); + const el1 = new Element( document, 'textarea' ); + const el2 = new Element( document, 'div' ); const result = matcher.match( el1 ); @@ -82,9 +90,9 @@ describe( 'Matcher', () => { } }; const matcher = new Matcher( pattern ); - const el1 = new Element( 'p', { title: 'foobar' } ); - const el2 = new Element( 'p', { title: 'foobaz' } ); - const el3 = new Element( 'p', { name: 'foobar' } ); + const el1 = new Element( document, 'p', { title: 'foobar' } ); + const el2 = new Element( document, 'p', { title: 'foobaz' } ); + const el3 = new Element( document, 'p', { name: 'foobar' } ); const result = matcher.match( el1 ); @@ -106,9 +114,9 @@ describe( 'Matcher', () => { } }; const matcher = new Matcher( pattern ); - const el1 = new Element( 'p', { title: 'foobar' } ); - const el2 = new Element( 'p', { title: 'foobaz' } ); - const el3 = new Element( 'p', { title: 'qux' } ); + const el1 = new Element( document, 'p', { title: 'foobar' } ); + const el2 = new Element( document, 'p', { title: 'foobaz' } ); + const el3 = new Element( document, 'p', { title: 'qux' } ); let result = matcher.match( el1 ); expect( result ).to.be.an( 'object' ); @@ -133,9 +141,9 @@ describe( 'Matcher', () => { } }; const matcher = new Matcher( pattern ); - const el1 = new Element( 'p', { title: 'foobar' } ); - const el2 = new Element( 'p', { title: '' } ); - const el3 = new Element( 'p' ); + const el1 = new Element( document, 'p', { title: 'foobar' } ); + const el2 = new Element( document, 'p', { title: '' } ); + const el3 = new Element( document, 'p' ); let result = matcher.match( el1 ); expect( result ).to.be.an( 'object' ); @@ -157,7 +165,7 @@ describe( 'Matcher', () => { it( 'should match element class names', () => { const pattern = { classes: 'foobar' }; const matcher = new Matcher( pattern ); - const el1 = new Element( 'p', { class: 'foobar' } ); + const el1 = new Element( document, 'p', { class: 'foobar' } ); const result = matcher.match( el1 ); expect( result ).to.be.an( 'object' ); @@ -171,9 +179,9 @@ describe( 'Matcher', () => { it( 'should match element class names using RegExp', () => { const pattern = { classes: /fooba./ }; const matcher = new Matcher( pattern ); - const el1 = new Element( 'p', { class: 'foobar' } ); - const el2 = new Element( 'p', { class: 'foobaz' } ); - const el3 = new Element( 'p', { class: 'qux' } ); + const el1 = new Element( document, 'p', { class: 'foobar' } ); + const el2 = new Element( document, 'p', { class: 'foobaz' } ); + const el3 = new Element( document, 'p', { class: 'qux' } ); let result = matcher.match( el1 ); expect( result ).to.be.an( 'object' ); @@ -198,8 +206,8 @@ describe( 'Matcher', () => { } }; const matcher = new Matcher( pattern ); - const el1 = new Element( 'p', { style: 'color: red' } ); - const el2 = new Element( 'p', { style: 'position: absolute' } ); + const el1 = new Element( document, 'p', { style: 'color: red' } ); + const el2 = new Element( document, 'p', { style: 'position: absolute' } ); const result = matcher.match( el1 ); expect( result ).to.be.an( 'object' ); @@ -218,9 +226,9 @@ describe( 'Matcher', () => { } }; const matcher = new Matcher( pattern ); - const el1 = new Element( 'p', { style: 'color: blue' } ); - const el2 = new Element( 'p', { style: 'color: darkblue' } ); - const el3 = new Element( 'p', { style: 'color: red' } ); + const el1 = new Element( document, 'p', { style: 'color: blue' } ); + const el2 = new Element( document, 'p', { style: 'color: darkblue' } ); + const el3 = new Element( document, 'p', { style: 'color: red' } ); let result = matcher.match( el1 ); expect( result ).to.be.an( 'object' ); @@ -248,8 +256,8 @@ describe( 'Matcher', () => { return null; }; const matcher = new Matcher( pattern ); - const el1 = new Element( 'p' ); - const el2 = new Element( 'div', null, [ el1 ] ); + const el1 = new Element( document, 'p' ); + const el2 = new Element( document, 'div', null, [ el1 ] ); expect( matcher.match( el1 ) ).to.be.null; const result = matcher.match( el2 ); @@ -262,9 +270,9 @@ describe( 'Matcher', () => { const pattern = { name: 'p' }; - const el1 = new Element( 'div' ); - const el2 = new Element( 'p' ); - const el3 = new Element( 'span' ); + const el1 = new Element( document, 'div' ); + const el2 = new Element( document, 'p' ); + const el3 = new Element( document, 'span' ); const matcher = new Matcher( pattern ); const result = matcher.match( el1, el2, el3 ); @@ -284,7 +292,7 @@ describe( 'Matcher', () => { } }; const matcher = new Matcher( pattern ); - const el = new Element( 'a', { + const el = new Element( document, 'a', { name: 'foo', title: 'bar' } ); @@ -305,7 +313,7 @@ describe( 'Matcher', () => { classes: [ 'foo', 'bar' ] }; const matcher = new Matcher( pattern ); - const el = new Element( 'a' ); + const el = new Element( document, 'a' ); el._addClass( [ 'foo', 'bar', 'baz' ] ); const result = matcher.match( el ); @@ -327,7 +335,7 @@ describe( 'Matcher', () => { } }; const matcher = new Matcher( pattern ); - const el = new Element( 'a' ); + const el = new Element( document, 'a' ); el._setStyle( { color: 'red', position: 'relative' @@ -347,9 +355,9 @@ describe( 'Matcher', () => { describe( 'matchAll', () => { it( 'should return all matched elements with correct patterns', () => { const matcher = new Matcher( 'p', 'div' ); - const el1 = new Element( 'p' ); - const el2 = new Element( 'div' ); - const el3 = new Element( 'span' ); + const el1 = new Element( document, 'p' ); + const el2 = new Element( document, 'div' ); + const el3 = new Element( document, 'span' ); const result = matcher.matchAll( el1, el2, el3 ); expect( result ).to.be.an( 'array' ); @@ -372,9 +380,9 @@ describe( 'Matcher', () => { it( 'should return all matched elements when using RegExp pattern', () => { const pattern = { classes: /^red-.*/ }; const matcher = new Matcher( pattern ); - const el1 = new Element( 'p' ); - const el2 = new Element( 'p' ); - const el3 = new Element( 'p' ); + const el1 = new Element( document, 'p' ); + const el2 = new Element( document, 'p' ); + const el3 = new Element( document, 'p' ); el1._addClass( 'red-foreground' ); el2._addClass( 'red-background' ); diff --git a/tests/view/node.js b/tests/view/node.js index 59aa43b41..465abffed 100644 --- a/tests/view/node.js +++ b/tests/view/node.js @@ -9,25 +9,28 @@ import Node from '../../src/view/node'; import DocumentFragment from '../../src/view/documentfragment'; import RootEditableElement from '../../src/view/rooteditableelement'; -import createDocumentMock from '../../tests/view/_utils/createdocumentmock'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import Document from '../../src/view/document'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'Node', () => { - let root, + let root, document, one, two, three, charB, charA, charR, img; before( () => { - charB = new Text( 'b' ); - charA = new Text( 'a' ); - img = new Element( 'img' ); - charR = new Text( 'r' ); + document = new Document( new StylesProcessor() ); - one = new Element( 'one' ); - two = new Element( 'two', null, [ charB, charA, img, charR ] ); - three = new Element( 'three' ); + charB = new Text( document, 'b' ); + charA = new Text( document, 'a' ); + img = new Element( document, 'img' ); + charR = new Text( document, 'r' ); - root = new Element( null, null, [ one, two, three ] ); + one = new Element( document, 'one' ); + two = new Element( document, 'two', null, [ charB, charA, img, charR ] ); + three = new Element( document, 'three' ); + + root = new Element( document, null, null, [ one, two, three ] ); } ); describe( 'is()', () => { @@ -125,7 +128,7 @@ describe( 'Node', () => { } ); it( 'should return ancestors including DocumentFragment', () => { - const fragment = new DocumentFragment( root ); + const fragment = new DocumentFragment( document, root ); const result = img.getAncestors(); root._remove(); @@ -146,7 +149,7 @@ describe( 'Node', () => { } ); it( 'should return null for detached subtrees', () => { - const detached = new Element( 'foo' ); + const detached = new Element( document, 'foo' ); expect( img.getCommonAncestor( detached ) ).to.be.null; expect( detached.getCommonAncestor( img ) ).to.be.null; @@ -176,14 +179,14 @@ describe( 'Node', () => { } ); it( 'should return proper element for nodes in different branches and on different levels', () => { - const foo = new Text( 'foo' ); - const bar = new Text( 'bar' ); - const bom = new Text( 'bom' ); - const d = new Element( 'd', null, [ bar ] ); - const c = new Element( 'c', null, [ foo, d ] ); - const b = new Element( 'b', null, [ c ] ); - const e = new Element( 'e', null, [ bom ] ); - const a = new Element( 'a', null, [ b, e ] ); + const foo = new Text( document, 'foo' ); + const bar = new Text( document, 'bar' ); + const bom = new Text( document, 'bom' ); + const d = new Element( document, 'd', null, [ bar ] ); + const c = new Element( document, 'c', null, [ foo, d ] ); + const b = new Element( document, 'b', null, [ c ] ); + const e = new Element( document, 'e', null, [ bom ] ); + const a = new Element( document, 'a', null, [ b, e ] ); // foobarbom @@ -203,9 +206,9 @@ describe( 'Node', () => { } ); it( 'should return document fragment', () => { - const foo = new Text( 'foo' ); - const bar = new Text( 'bar' ); - const df = new DocumentFragment( [ foo, bar ] ); + const foo = new Text( document, 'foo' ); + const bar = new Text( document, 'bar' ); + const df = new DocumentFragment( document, [ foo, bar ] ); expect( foo.getCommonAncestor( bar ) ).to.equal( df ); } ); @@ -228,8 +231,8 @@ describe( 'Node', () => { } ); it( 'should throw an error if parent does not contain element', () => { - const f = new Text( 'f' ); - const bar = new Element( 'bar', [], [] ); + const f = new Text( document, 'f' ); + const bar = new Element( document, 'bar', [], [] ); f.parent = bar; @@ -253,42 +256,16 @@ describe( 'Node', () => { } ); } ); - describe( 'getDocument()', () => { - it( 'should return null if any parent has not set Document', () => { - expect( charA.document ).to.be.null; - } ); - - it( 'should return Document attached to the parent element', () => { - const docMock = createDocumentMock(); - const parent = new RootEditableElement( 'div' ); - parent._document = docMock; - const child = new Element( 'p' ); - - child.parent = parent; - - expect( parent.document ).to.equal( docMock ); - expect( child.document ).to.equal( docMock ); - } ); - - it( 'should return null if element is inside DocumentFragment', () => { - const child = new Element( 'p' ); - new DocumentFragment( [ child ] ); // eslint-disable-line no-new - - expect( child.document ).to.be.null; - } ); - } ); - describe( 'getRoot()', () => { it( 'should return this element if it has no parent', () => { - const child = new Element( 'p' ); + const child = new Element( document, 'p' ); expect( child.root ).to.equal( child ); } ); it( 'should return root element', () => { - const parent = new RootEditableElement( 'div' ); - parent._document = createDocumentMock(); - const child = new Element( 'p' ); + const parent = new RootEditableElement( document, 'div' ); + const child = new Element( document, 'p' ); child.parent = parent; @@ -326,8 +303,8 @@ describe( 'Node', () => { } ); it( 'should return false if elements are in different roots', () => { - const otherRoot = new Element( 'root' ); - const otherElement = new Element( 'element' ); + const otherRoot = new Element( document, 'root' ); + const otherElement = new Element( document, 'element' ); otherRoot._appendChild( otherElement ); @@ -364,8 +341,8 @@ describe( 'Node', () => { } ); it( 'should return false if elements are in different roots', () => { - const otherRoot = new Element( 'root' ); - const otherElement = new Element( 'element' ); + const otherRoot = new Element( document, 'root' ); + const otherElement = new Element( document, 'element' ); otherRoot._appendChild( otherElement ); @@ -373,18 +350,41 @@ describe( 'Node', () => { } ); } ); + describe( 'isAttached()', () => { + it( 'returns false for a fresh node', () => { + const char = new Text( document, 'x' ); + const el = new Element( document, 'one' ); + + expect( char.isAttached() ).to.equal( false ); + expect( el.isAttached() ).to.equal( false ); + } ); + + it( 'returns true for the root element', () => { + const root = new RootEditableElement( document, 'div' ); + + expect( root.isAttached() ).to.equal( true ); + } ); + + it( 'returns false for a node attached to a document fragment', () => { + const foo = new Text( document, 'foo' ); + new DocumentFragment( document, [ foo ] ); // eslint-disable-line no-new + + expect( foo.isAttached() ).to.equal( false ); + } ); + } ); + describe( '_remove()', () => { it( 'should remove node from its parent', () => { - const char = new Text( 'a' ); - const parent = new Element( 'p', null, [ char ] ); + const char = new Text( document, 'a' ); + const parent = new Element( document, 'p', null, [ char ] ); char._remove(); expect( parent.getChildIndex( char ) ).to.equal( -1 ); } ); it( 'uses parent._removeChildren method', () => { - const char = new Text( 'a' ); - const parent = new Element( 'p', null, [ char ] ); + const char = new Text( document, 'a' ); + const parent = new Element( document, 'p', null, [ char ] ); const _removeChildrenSpy = sinon.spy( parent, '_removeChildren' ); const index = char.index; char._remove(); @@ -396,15 +396,18 @@ describe( 'Node', () => { describe( 'toJSON()', () => { it( 'should prevent circular reference when stringifying a node', () => { - const char = new Text( 'a' ); - const parent = new Element( 'p', null ); + const char = new Text( document, 'a' ); + const parent = new Element( document, 'p', null ); parent._appendChild( char ); + sinon.stub( char, 'document' ).value( 'view.Document()' ); + const json = JSON.stringify( char ); const parsed = JSON.parse( json ); expect( parsed ).to.deep.equal( { - _textData: 'a' + _textData: 'a', + document: 'view.Document()' } ); } ); } ); @@ -417,10 +420,10 @@ describe( 'Node', () => { } ); beforeEach( () => { - text = new Text( 'foo' ); - img = new Element( 'img', { 'src': 'img.png' } ); + text = new Text( document, 'foo' ); + img = new Element( document, 'img', { 'src': 'img.png' } ); - root = new Element( 'p', { renderer: { markToSync: rootChangeSpy } } ); + root = new Element( document, 'p', { renderer: { markToSync: rootChangeSpy } } ); root._appendChild( [ text, img ] ); root.on( 'change:children', ( evt, node ) => rootChangeSpy( 'children', node ) ); @@ -470,7 +473,7 @@ describe( 'Node', () => { describe( '_insertChild()', () => { it( 'should fire change event', () => { - root._insertChild( 1, new Element( 'img' ) ); + root._insertChild( 1, new Element( document, 'img' ) ); sinon.assert.calledOnce( rootChangeSpy ); sinon.assert.calledWith( rootChangeSpy, 'children', root ); @@ -479,7 +482,7 @@ describe( 'Node', () => { describe( '_appendChild()', () => { it( 'should fire change event', () => { - root._appendChild( new Element( 'img' ) ); + root._appendChild( new Element( document, 'img' ) ); sinon.assert.calledOnce( rootChangeSpy ); sinon.assert.calledWith( rootChangeSpy, 'children', root ); diff --git a/tests/view/observer/clickobserver.js b/tests/view/observer/clickobserver.js index a79b2c718..baf7a18d0 100644 --- a/tests/view/observer/clickobserver.js +++ b/tests/view/observer/clickobserver.js @@ -7,12 +7,13 @@ import ClickObserver from '../../../src/view/observer/clickobserver'; import View from '../../../src/view/view'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'ClickObserver', () => { let view, viewDocument, observer; beforeEach( () => { - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; observer = view.addObserver( ClickObserver ); } ); diff --git a/tests/view/observer/compositionobserver.js b/tests/view/observer/compositionobserver.js index 16f2a3bb0..1d2ed1e2f 100644 --- a/tests/view/observer/compositionobserver.js +++ b/tests/view/observer/compositionobserver.js @@ -6,12 +6,13 @@ /* globals document */ import CompositionObserver from '../../../src/view/observer/compositionobserver'; import View from '../../../src/view/view'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'CompositionObserver', () => { let view, viewDocument, observer; beforeEach( () => { - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; observer = view.getObserver( CompositionObserver ); } ); diff --git a/tests/view/observer/domeventdata.js b/tests/view/observer/domeventdata.js index 735fbe2ea..7b7f2a390 100644 --- a/tests/view/observer/domeventdata.js +++ b/tests/view/observer/domeventdata.js @@ -7,12 +7,13 @@ import DomEventData from '../../../src/view/observer/domeventdata'; import View from '../../../src/view/view'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'DomEventData', () => { let view, viewDocument, viewBody, domRoot; beforeEach( () => { - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; domRoot = document.createElement( 'div' ); diff --git a/tests/view/observer/domeventobserver.js b/tests/view/observer/domeventobserver.js index 946cda0d4..a7c05bbe4 100644 --- a/tests/view/observer/domeventobserver.js +++ b/tests/view/observer/domeventobserver.js @@ -10,6 +10,7 @@ import Observer from '../../../src/view/observer/observer'; import View from '../../../src/view/view'; import UIElement from '../../../src/view/uielement'; import createViewRoot from '../_utils/createroot'; +import { StylesProcessor } from '../../../src/view/stylesmap'; class ClickObserver extends DomEventObserver { constructor( view ) { @@ -47,7 +48,7 @@ describe( 'DomEventObserver', () => { let view, viewDocument; beforeEach( () => { - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; } ); @@ -165,7 +166,7 @@ describe( 'DomEventObserver', () => { let domRoot, domEvent, evtSpy, uiElement; function createUIElement( name ) { - const element = new UIElement( name ); + const element = new UIElement( viewDocument, name ); element.render = function( domDocument ) { const root = this.toDomElement( domDocument ); diff --git a/tests/view/observer/fakeselectionobserver.js b/tests/view/observer/fakeselectionobserver.js index 1b42d821e..333703938 100644 --- a/tests/view/observer/fakeselectionobserver.js +++ b/tests/view/observer/fakeselectionobserver.js @@ -13,6 +13,7 @@ import createViewRoot from '../_utils/createroot'; import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard'; import { setData, stringify } from '../../../src/dev-utils/view'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'FakeSelectionObserver', () => { let observer, view, viewDocument, root, domRoot; @@ -30,7 +31,7 @@ describe( 'FakeSelectionObserver', () => { } ); beforeEach( () => { - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; root = createViewRoot( viewDocument ); view.attachDomRoot( domRoot ); diff --git a/tests/view/observer/focusobserver.js b/tests/view/observer/focusobserver.js index 3ac9a3de6..62c81d77e 100644 --- a/tests/view/observer/focusobserver.js +++ b/tests/view/observer/focusobserver.js @@ -8,12 +8,13 @@ import FocusObserver from '../../../src/view/observer/focusobserver'; import View from '../../../src/view/view'; import createViewRoot from '../_utils/createroot'; import { setData } from '../../../src/dev-utils/view'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'FocusObserver', () => { let view, viewDocument, observer; beforeEach( () => { - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; observer = view.getObserver( FocusObserver ); } ); @@ -157,7 +158,7 @@ describe( 'FocusObserver', () => { domRoot = document.createElement( 'div' ); document.body.appendChild( domRoot ); - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; createViewRoot( viewDocument ); view.attachDomRoot( domRoot ); diff --git a/tests/view/observer/inputobserver.js b/tests/view/observer/inputobserver.js index 5e56c76c2..f007a811e 100644 --- a/tests/view/observer/inputobserver.js +++ b/tests/view/observer/inputobserver.js @@ -6,17 +6,19 @@ import InputObserver from '../../../src/view/observer/inputobserver'; import View from '../../../src/view/view'; import env from '@ckeditor/ckeditor5-utils/src/env'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'InputObserver', () => { - let view, viewDocument, observer; const oldEnvIsAndroid = env.isAndroid; + let view, viewDocument, observer; + before( () => { env.isAndroid = true; } ); beforeEach( () => { - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; observer = view.getObserver( InputObserver ); } ); diff --git a/tests/view/observer/keyobserver.js b/tests/view/observer/keyobserver.js index 45a73e8f6..a564e43a8 100644 --- a/tests/view/observer/keyobserver.js +++ b/tests/view/observer/keyobserver.js @@ -8,12 +8,13 @@ import KeyObserver from '../../../src/view/observer/keyobserver'; import View from '../../../src/view/view'; import { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'KeyObserver', () => { let view, viewDocument, observer; beforeEach( () => { - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; observer = view.getObserver( KeyObserver ); } ); diff --git a/tests/view/observer/mouseobserver.js b/tests/view/observer/mouseobserver.js index 6d25325b1..9db6d4516 100644 --- a/tests/view/observer/mouseobserver.js +++ b/tests/view/observer/mouseobserver.js @@ -7,12 +7,13 @@ import MouseObserver from '../../../src/view/observer/mouseobserver'; import View from '../../../src/view/view'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'MouseObserver', () => { let view, viewDocument, observer; beforeEach( () => { - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; observer = view.addObserver( MouseObserver ); } ); diff --git a/tests/view/observer/mutationobserver.js b/tests/view/observer/mutationobserver.js index ccbddce74..e5df359b0 100644 --- a/tests/view/observer/mutationobserver.js +++ b/tests/view/observer/mutationobserver.js @@ -10,6 +10,7 @@ import MutationObserver from '../../../src/view/observer/mutationobserver'; import UIElement from '../../../src/view/uielement'; import createViewRoot from '../_utils/createroot'; import { parse } from '../../../src/dev-utils/view'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'MutationObserver', () => { let view, domEditor, viewDocument, viewRoot, mutationObserver, lastMutations, domRoot; @@ -19,7 +20,7 @@ describe( 'MutationObserver', () => { domRoot.innerHTML = '
'; document.body.appendChild( domRoot ); - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; domEditor = document.getElementById( 'main' ); lastMutations = null; @@ -225,7 +226,9 @@ describe( 'MutationObserver', () => { } ); it( 'should fire children mutation if the mutation occurred in the inline filler', () => { - const { view: viewContainer, selection } = parse( 'foo[]bar' ); + const { view: viewContainer, selection } = parse( + 'foo[]bar' + ); view.change( writer => { viewRoot._appendChild( viewContainer ); @@ -243,7 +246,9 @@ describe( 'MutationObserver', () => { } ); it( 'should have no inline filler in mutation', () => { - const { view: viewContainer, selection } = parse( 'foo[]bar' ); + const { view: viewContainer, selection } = parse( + 'foo[]bar' + ); view.change( writer => { viewRoot._appendChild( viewContainer ); diff --git a/tests/view/observer/observer.js b/tests/view/observer/observer.js index 6ec3fbd1f..234347600 100644 --- a/tests/view/observer/observer.js +++ b/tests/view/observer/observer.js @@ -5,11 +5,12 @@ import Observer from '../../../src/view/observer/observer'; import View from '../../../src/view/view'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'Observer', () => { describe( 'constructor()', () => { it( 'should create Observer with properties', () => { - const view = new View(); + const view = new View( new StylesProcessor() ); const observer = new Observer( view ); expect( observer ).to.be.an.instanceof( Observer ); diff --git a/tests/view/observer/selectionobserver.js b/tests/view/observer/selectionobserver.js index b9a7110ee..d049607b0 100644 --- a/tests/view/observer/selectionobserver.js +++ b/tests/view/observer/selectionobserver.js @@ -13,6 +13,7 @@ import SelectionObserver from '../../../src/view/observer/selectionobserver'; import FocusObserver from '../../../src/view/observer/focusobserver'; import createViewRoot from '../_utils/createroot'; import { parse } from '../../../src/dev-utils/view'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'SelectionObserver', () => { let view, viewDocument, viewRoot, selectionObserver, domRoot, domMain, domDocument; @@ -24,7 +25,7 @@ describe( 'SelectionObserver', () => { domMain = domRoot.childNodes[ 0 ]; domDocument.body.appendChild( domRoot ); - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; createViewRoot( viewDocument ); view.attachDomRoot( domMain ); diff --git a/tests/view/placeholder.js b/tests/view/placeholder.js index 051124e02..f02781999 100644 --- a/tests/view/placeholder.js +++ b/tests/view/placeholder.js @@ -14,12 +14,13 @@ import createViewRoot from './_utils/createroot'; import View from '../../src/view/view'; import ViewRange from '../../src/view/range'; import { setData } from '../../src/dev-utils/view'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'placeholder', () => { let view, viewDocument, viewRoot; beforeEach( () => { - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; viewRoot = createViewRoot( viewDocument ); viewDocument.isFocused = true; @@ -172,7 +173,7 @@ describe( 'placeholder', () => { setData( view, '
{another div}
' ); const element = viewRoot.getChild( 0 ); - const secondView = new View(); + const secondView = new View( new StylesProcessor() ); const secondDocument = secondView.document; secondDocument.isFocused = true; const secondRoot = createViewRoot( secondDocument ); diff --git a/tests/view/position.js b/tests/view/position.js index 72b70bc11..1bd715959 100644 --- a/tests/view/position.js +++ b/tests/view/position.js @@ -18,9 +18,15 @@ import createViewRoot from './_utils/createroot'; import AttributeElement from '../../src/view/attributeelement'; import ContainerElement from '../../src/view/containerelement'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'Position', () => { const parentMock = {}; + let document; + + before( () => { + document = new Document( new StylesProcessor() ); + } ); describe( 'constructor()', () => { it( 'should create element without attributes', () => { @@ -60,23 +66,23 @@ describe( 'Position', () => { describe( 'nodeBefore', () => { it( 'should equal to node that is before position', () => { - const b1 = new Element( 'b' ); - const el = new Element( 'p', null, [ b1 ] ); + const b1 = new Element( document, 'b' ); + const el = new Element( document, 'p', null, [ b1 ] ); const position = new Position( el, 1 ); expect( position.nodeBefore ).to.equal( b1 ); } ); it( 'should equal null if there is no node before', () => { - const b1 = new Element( 'b' ); - const el = new Element( 'p', null, [ b1 ] ); + const b1 = new Element( document, 'b' ); + const el = new Element( document, 'p', null, [ b1 ] ); const position = new Position( el, 0 ); expect( position.nodeBefore ).to.be.null; } ); it( 'should equal null if position is located inside text node', () => { - const text = new Text( 'foobar' ); + const text = new Text( document, 'foobar' ); const position = new Position( text, 3 ); expect( position.nodeBefore ).to.be.null; @@ -85,23 +91,23 @@ describe( 'Position', () => { describe( 'nodeAfter', () => { it( 'should equal to node that is after position', () => { - const b1 = new Element( 'b' ); - const el = new Element( 'p', null, [ b1 ] ); + const b1 = new Element( document, 'b' ); + const el = new Element( document, 'p', null, [ b1 ] ); const position = new Position( el, 0 ); expect( position.nodeAfter ).to.equal( b1 ); } ); it( 'should equal null if there is no node before', () => { - const b1 = new Element( 'b' ); - const el = new Element( 'p', null, [ b1 ] ); + const b1 = new Element( document, 'b' ); + const el = new Element( document, 'p', null, [ b1 ] ); const position = new Position( el, 1 ); expect( position.nodeAfter ).to.be.null; } ); it( 'should equal null if position is located inside text node', () => { - const text = new Text( 'foobar' ); + const text = new Text( document, 'foobar' ); const position = new Position( text, 3 ); expect( position.nodeAfter ).to.be.null; @@ -151,13 +157,13 @@ describe( 'Position', () => { describe( 'getRoot', () => { it( 'should return it\'s parent root', () => { - const foo = new Text( 'foo' ); - const docFrag = new DocumentFragment( foo ); + const foo = new Text( document, 'foo' ); + const docFrag = new DocumentFragment( document, foo ); expect( new Position( foo, 1 ).root ).to.equal( docFrag ); - const bar = new Text( 'bar' ); - const p = new Element( 'p', null, bar ); + const bar = new Text( document, 'bar' ); + const p = new Element( document, 'p', null, bar ); expect( new Position( bar, 2 ).root ).to.equal( p ); expect( new Position( p, 0 ).root ).to.equal( p ); @@ -166,16 +172,16 @@ describe( 'Position', () => { describe( 'getAncestors', () => { it( 'should return it\'s parent and all it\'s ancestors', () => { - const foo = new Text( 'foo' ); - const p = new Element( 'p', null, foo ); - const div = new Element( 'div', null, p ); - const docFrag = new DocumentFragment( div ); + const foo = new Text( document, 'foo' ); + const p = new Element( document, 'p', null, foo ); + const div = new Element( document, 'div', null, p ); + const docFrag = new DocumentFragment( document, div ); expect( new Position( foo, 1 ).getAncestors() ).to.deep.equal( [ docFrag, div, p, foo ] ); } ); it( 'should return DocumentFragment if position is directly in document fragment', () => { - const docFrag = new DocumentFragment(); + const docFrag = new DocumentFragment( document ); expect( new Position( docFrag, 0 ).getAncestors() ).to.deep.equal( [ docFrag ] ); } ); @@ -220,10 +226,10 @@ describe( 'Position', () => { } ); it( 'should return false if no common ancestor is found', () => { - const t1 = new Text( 'foo' ); - const t2 = new Text( 'bar' ); - const e1 = new Element( 'p', null, [ t1 ] ); - const e2 = new Element( 'p', null, [ t2 ] ); + const t1 = new Text( document, 'foo' ); + const t2 = new Text( document, 'bar' ); + const e1 = new Element( document, 'p', null, [ t1 ] ); + const e2 = new Element( document, 'p', null, [ t2 ] ); const position1 = new Position( e1, 0 ); const position2 = new Position( e2, 1 ); @@ -241,9 +247,9 @@ describe( 'Position', () => { } ); it( 'should compare positions that have common parent', () => { - const t1 = new Text( 'foo' ); - const t2 = new Text( 'bar' ); - const root = new Element( 'p', null, [ t1, t2 ] ); + const t1 = new Text( document, 'foo' ); + const t2 = new Text( document, 'bar' ); + const root = new Element( document, 'p', null, [ t1, t2 ] ); const position1 = new Position( t1, 2 ); const position2 = new Position( t2, 0 ); const position3 = new Position( root, 0 ); @@ -278,10 +284,10 @@ describe( 'Position', () => { } ); it( 'should return false if no common ancestor is found', () => { - const t1 = new Text( 'foo' ); - const t2 = new Text( 'bar' ); - const e1 = new Element( 'p', null, [ t1 ] ); - const e2 = new Element( 'p', null, [ t2 ] ); + const t1 = new Text( document, 'foo' ); + const t2 = new Text( document, 'bar' ); + const e1 = new Element( document, 'p', null, [ t1 ] ); + const e2 = new Element( document, 'p', null, [ t2 ] ); const position1 = new Position( e1, 0 ); const position2 = new Position( e2, 1 ); @@ -299,9 +305,9 @@ describe( 'Position', () => { } ); it( 'should compare positions that have common parent', () => { - const t1 = new Text( 'foo' ); - const t2 = new Text( 'bar' ); - const root = new Element( 'p', null, [ t1, t2 ] ); + const t1 = new Text( document, 'foo' ); + const t2 = new Text( document, 'bar' ); + const root = new Element( document, 'p', null, [ t1, t2 ] ); const position1 = new Position( t1, 2 ); const position2 = new Position( t2, 0 ); const position3 = new Position( root, 0 ); @@ -325,13 +331,13 @@ describe( 'Position', () => { describe( 'isAtStart', () => { it( 'should return true if it is at the start of it\'s parent', () => { - const foo = new Text( 'foo' ); + const foo = new Text( document, 'foo' ); const position = new Position( foo, 0 ); expect( position.isAtStart ).to.be.true; } ); it( 'should return false if it is not at the start of it\'s parent', () => { - const foo = new Text( 'foo' ); + const foo = new Text( document, 'foo' ); const position = new Position( foo, 1 ); expect( position.isAtStart ).to.be.false; } ); @@ -339,16 +345,16 @@ describe( 'Position', () => { describe( 'isAtEnd', () => { it( 'should return true if it is at the end of it\'s parent', () => { - const foo = new Text( 'foo' ); - const p = new Element( 'p', null, foo ); + const foo = new Text( document, 'foo' ); + const p = new Element( document, 'p', null, foo ); expect( new Position( foo, 3 ).isAtEnd ).to.be.true; expect( new Position( p, 1 ).isAtEnd ).to.be.true; } ); it( 'should return false if it is not at the end of it\'s parent', () => { - const foo = new Text( 'foo' ); - const p = new Element( 'p', null, foo ); + const foo = new Text( document, 'foo' ); + const p = new Element( document, 'p', null, foo ); expect( new Position( foo, 2 ).isAtEnd ).to.be.false; expect( new Position( p, 0 ).isAtEnd ).to.be.false; @@ -357,7 +363,7 @@ describe( 'Position', () => { describe( 'compareWith', () => { it( 'should return same if positions are same', () => { - const root = new Element(); + const root = new Element( document ); const position = new Position( root, 0 ); const compared = new Position( root, 0 ); @@ -365,7 +371,7 @@ describe( 'Position', () => { } ); it( 'should return before if the position is before compared one', () => { - const root = new Element(); + const root = new Element( document ); const position = new Position( root, 0 ); const compared = new Position( root, 1 ); @@ -373,7 +379,7 @@ describe( 'Position', () => { } ); it( 'should return after if the position is after compared one', () => { - const root = new Element(); + const root = new Element( document ); const position = new Position( root, 4 ); const compared = new Position( root, 1 ); @@ -381,8 +387,8 @@ describe( 'Position', () => { } ); it( 'should return different if positions are in different roots', () => { - const root1 = new Element(); - const root2 = new Element(); + const root1 = new Element( document ); + const root2 = new Element( document ); const position = new Position( root1, 4 ); const compared = new Position( root2, 1 ); @@ -390,8 +396,8 @@ describe( 'Position', () => { } ); it( 'should return correct results if position is in document fragment', () => { - const node = new Element( 'name' ); - const docFrag = new DocumentFragment( [ node ] ); + const node = new Element( document, 'name' ); + const docFrag = new DocumentFragment( document, [ node ] ); const position = new Position( docFrag, 0 ); const compared = new Position( docFrag, 1 ); const posInNode = new Position( node, 0 ); @@ -407,7 +413,7 @@ describe( 'Position', () => { describe( 'static creators', () => { describe( '_createAt()', () => { it( 'should throw if no offset is passed', () => { - const element = new Element( 'p' ); + const element = new Element( document, 'p' ); expectToThrowCKEditorError( () => { Position._createAt( element ); @@ -415,7 +421,7 @@ describe( 'Position', () => { } ); it( 'should create positions from positions', () => { - const p = new Element( 'p' ); + const p = new Element( document, 'p' ); const position = new Position( p, 0 ); const created = Position._createAt( position, 0 ); @@ -424,8 +430,8 @@ describe( 'Position', () => { } ); it( 'should create positions from node and offset', () => { - const foo = new Text( 'foo' ); - const p = new Element( 'p', null, foo ); + const foo = new Text( document, 'foo' ); + const p = new Element( document, 'p', null, foo ); expect( Position._createAt( foo, 0 ).parent ).to.equal( foo ); expect( Position._createAt( foo, 0 ).offset ).to.equal( 0 ); @@ -438,8 +444,8 @@ describe( 'Position', () => { } ); it( 'should create positions from node and flag', () => { - const foo = new Text( 'foo' ); - const p = new Element( 'p', null, foo ); + const foo = new Text( document, 'foo' ); + const p = new Element( document, 'p', null, foo ); const fooEnd = Position._createAt( foo, 'end' ); const fooBefore = Position._createAt( foo, 'before' ); @@ -462,8 +468,8 @@ describe( 'Position', () => { } ); it( 'should create positions in document fragment', () => { - const foo = new Text( 'foo' ); - const docFrag = new DocumentFragment( [ foo ] ); + const foo = new Text( document, 'foo' ); + const docFrag = new DocumentFragment( document, [ foo ] ); const pStart = Position._createAt( docFrag, 0 ); const pEnd = Position._createAt( docFrag, 'end' ); @@ -493,7 +499,7 @@ describe( 'Position', () => { } ); it( 'should create positions before `TextProxy`', () => { - const text = new Text( 'abc' ); + const text = new Text( document, 'abc' ); const textProxy = new TextProxy( text, 1, 1 ); const position = new Position( text, 1 ); @@ -520,7 +526,7 @@ describe( 'Position', () => { } ); it( 'should create positions after `TextProxy`', () => { - const text = new Text( 'abcd' ); + const text = new Text( document, 'abcd' ); const textProxy = new TextProxy( text, 1, 2 ); const position = new Position( text, 3 ); @@ -532,16 +538,14 @@ describe( 'Position', () => { describe( 'getEditableElement', () => { it( 'should return null if position is not inside EditableElement', () => { - const position = new Position( new Element( 'p' ), 0 ); + const position = new Position( new Element( document, 'p' ), 0 ); expect( position.editableElement ).to.be.null; } ); it( 'should return EditableElement when position is placed inside', () => { - const document = new Document(); - const p = new Element( 'p' ); - const editable = new EditableElement( 'div', null, p ); - editable._document = document; + const p = new Element( document, 'p' ); + const editable = new EditableElement( document, 'div', null, p ); const position = new Position( p, 0 ); expect( position.editableElement ).to.equal( editable ); @@ -570,28 +574,28 @@ describe( 'Position', () => { beforeEach( () => { texts = { - foz: new Text( 'foz' ), - bar: new Text( 'bar' ), - lorem: new Text( 'Lorem ipsum dolor sit amet.' ), - mauris: new Text( 'Mauris tincidunt tincidunt leo ac rutrum.' ), - maecenas: new Text( 'Maecenas accumsan tellus.' ), - sed: new Text( 'Sed id libero at libero tristique.' ) + foz: new Text( document, 'foz' ), + bar: new Text( document, 'bar' ), + lorem: new Text( document, 'Lorem ipsum dolor sit amet.' ), + mauris: new Text( document, 'Mauris tincidunt tincidunt leo ac rutrum.' ), + maecenas: new Text( document, 'Maecenas accumsan tellus.' ), + sed: new Text( document, 'Sed id libero at libero tristique.' ) }; - liUl1 = new Element( 'li', null, texts.foz ); - liUl2 = new Element( 'li', null, texts.bar ); - ul = new Element( 'ul', null, [ liUl1, liUl2 ] ); + liUl1 = new Element( document, 'li', null, texts.foz ); + liUl2 = new Element( document, 'li', null, texts.bar ); + ul = new Element( document, 'ul', null, [ liUl1, liUl2 ] ); - liOl1 = new Element( 'li', null, texts.lorem ); - liOl2 = new Element( 'li', null, texts.mauris ); - ol = new Element( 'ol', null, [ liOl1, liOl2 ] ); + liOl1 = new Element( document, 'li', null, texts.lorem ); + liOl2 = new Element( document, 'li', null, texts.mauris ); + ol = new Element( document, 'ol', null, [ liOl1, liOl2 ] ); - p = new Element( 'p', null, texts.maecenas ); + p = new Element( document, 'p', null, texts.maecenas ); - article = new Element( 'article', null, [ ol, p ] ); - section = new Element( 'section', null, [ texts.sed, article ] ); + article = new Element( document, 'article', null, [ ol, p ] ); + section = new Element( document, 'section', null, [ texts.sed, article ] ); - div = new Element( 'div', null, [ ul, section ] ); + div = new Element( document, 'div', null, [ ul, section ] ); } ); it( 'for two the same positions returns the parent element', () => { @@ -623,7 +627,7 @@ describe( 'Position', () => { } ); it( 'for two positions in different trees returns null', () => { - const div = new Element( 'div' ); + const div = new Element( document, 'div' ); const posInDiv = new Position( div, 0 ); const firstPosition = new Position( liOl2, 10 ); @@ -640,15 +644,15 @@ describe( 'Position', () => { let root; beforeEach( () => { - const doc = new Document(); + const doc = new Document( new StylesProcessor() ); root = createViewRoot( doc ); - const textAbcd = new Text( 'abcd' ); - const bold = new AttributeElement( 'b', null, [ textAbcd ] ); + const textAbcd = new Text( document, 'abcd' ); + const bold = new AttributeElement( document, 'b', null, [ textAbcd ] ); - const paragraph = new ContainerElement( 'p', null, [ bold ] ); - const img = new ContainerElement( 'img' ); + const paragraph = new ContainerElement( document, 'p', null, [ bold ] ); + const img = new ContainerElement( document, 'img' ); root._insertChild( 0, [ img, paragraph ] ); } ); diff --git a/tests/view/range.js b/tests/view/range.js index 13e6a216d..66decaf53 100644 --- a/tests/view/range.js +++ b/tests/view/range.js @@ -10,7 +10,9 @@ import DocumentFragment from '../../src/view/documentfragment'; import Text from '../../src/view/text'; import TextProxy from '../../src/view/textproxy'; import TreeWalker from '../../src/view/treewalker'; +import Document from '../../src/view/document'; import { parse, stringify } from '../../src/dev-utils/view'; +import { StylesProcessor } from '../../src/view/stylesmap'; function getRange( view, options = {} ) { const { selection } = parse( view, options ); @@ -19,6 +21,12 @@ function getRange( view, options = {} ) { } describe( 'Range', () => { + let document; + + beforeEach( () => { + document = new Document( new StylesProcessor() ); + } ); + describe( 'constructor()', () => { it( 'creates range from provided positions', () => { const start = new Position( {}, 1 ); @@ -101,7 +109,7 @@ describe( 'Range', () => { describe( 'getRoot', () => { it( 'should return root element in which range is created', () => { - const viewRoot = new Element( 'div' ); + const viewRoot = new Element( document, 'div' ); const range = getRange( '

f{oo

ba}r

', { rootElement: viewRoot } ); expect( range.root ).to.equal( viewRoot ); @@ -297,7 +305,7 @@ describe( 'Range', () => { let viewRoot, range; beforeEach( () => { - viewRoot = new Element( 'div' ); + viewRoot = new Element( document, 'div' ); range = getRange( '

fo{o

bar

xy}z

', { rootElement: viewRoot } ); } ); @@ -324,7 +332,7 @@ describe( 'Range', () => { let viewRoot, range, beforeF, afterF, beforeB, afterX; beforeEach( () => { - viewRoot = new Element( 'div' ); + viewRoot = new Element( document, 'div' ); range = getRange( '

fo{o

bar

xy}z

', { rootElement: viewRoot } ); beforeF = new Position( viewRoot.getChild( 0 ).getChild( 0 ), 0 ); @@ -395,12 +403,12 @@ describe( 'Range', () => { // t1 t2 t3 beforeEach( () => { - t1 = new Text( 'foo' ); - t2 = new Text( 'bar' ); - t3 = new Text( 'baz' ); - p1 = new Element( 'p', null, [ t1, t2 ] ); - p2 = new Element( 'p', null, t3 ); - root = new Element( 'div', null, [ p1, p2 ] ); + t1 = new Text( document, 'foo' ); + t2 = new Text( document, 'bar' ); + t3 = new Text( document, 'baz' ); + p1 = new Element( document, 'p', null, [ t1, t2 ] ); + p2 = new Element( document, 'p', null, t3 ); + root = new Element( document, 'div', null, [ p1, p2 ] ); } ); describe( 'isIntersecting', () => { @@ -445,7 +453,7 @@ describe( 'Range', () => { it( 'should return false if ranges are in different roots', () => { const range = Range._createFromParentsAndOffsets( t1, 0, t2, 3 ); - const otherRange = Range._createFromParentsAndOffsets( new Element( 'div' ), 1, t3, 0 ); + const otherRange = Range._createFromParentsAndOffsets( new Element( document, 'div' ), 1, t3, 0 ); expect( range.isIntersecting( otherRange ) ).to.be.false; expect( otherRange.isIntersecting( range ) ).to.be.false; @@ -677,9 +685,9 @@ describe( 'Range', () => { let div, p, foz; beforeEach( () => { - foz = new Text( 'foz' ); - p = new Element( 'p', null, foz ); - div = new Element( 'div', null, p ); + foz = new Text( document, 'foz' ); + p = new Element( document, 'p', null, foz ); + div = new Element( document, 'div', null, p ); } ); describe( '_createIn', () => { @@ -704,7 +712,7 @@ describe( 'Range', () => { } ); it( 'should create a proper range on a text proxy', () => { - const text = new Text( 'foobar' ); + const text = new Text( document, 'foobar' ); const textProxy = new TextProxy( text, 2, 3 ); const range = Range._createOn( textProxy ); @@ -751,13 +759,13 @@ describe( 'Range', () => { describe( 'getCommonAncestor()', () => { it( 'should return common ancestor for positions from Range', () => { - const foz = new Text( 'foz' ); - const bar = new Text( 'bar' ); + const foz = new Text( document, 'foz' ); + const bar = new Text( document, 'bar' ); - const li1 = new Element( 'li', null, foz ); - const li2 = new Element( 'li', null, bar ); + const li1 = new Element( document, 'li', null, foz ); + const li2 = new Element( document, 'li', null, bar ); - const ul = new Element( 'ul', null, [ li1, li2 ] ); + const ul = new Element( document, 'ul', null, [ li1, li2 ] ); const range = new Range( new Position( li1, 0 ), new Position( li2, 2 ) ); diff --git a/tests/view/renderer.js b/tests/view/renderer.js index 66996946f..241303383 100644 --- a/tests/view/renderer.js +++ b/tests/view/renderer.js @@ -18,6 +18,7 @@ import DocumentSelection from '../../src/view/documentselection'; import DomConverter from '../../src/view/domconverter'; import Renderer from '../../src/view/renderer'; import DocumentFragment from '../../src/view/documentfragment'; +import ViewDocument from '../../src/view/document'; import DowncastWriter from '../../src/view/downcastwriter'; import { parse, stringify, setData as setViewData, getData as getViewData } from '../../src/dev-utils/view'; @@ -28,15 +29,17 @@ import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; import normalizeHtml from '@ckeditor/ckeditor5-utils/tests/_utils/normalizehtml'; import env from '@ckeditor/ckeditor5-utils/src/env'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'Renderer', () => { - let selection, domConverter, renderer; + let selection, domConverter, renderer, viewDocument; testUtils.createSinonSandbox(); beforeEach( () => { + viewDocument = new ViewDocument( new StylesProcessor() ); selection = new DocumentSelection(); - domConverter = new DomConverter(); + domConverter = new DomConverter( viewDocument ); renderer = new Renderer( domConverter, selection ); renderer.domDocuments.add( document ); } ); @@ -45,11 +48,11 @@ describe( 'Renderer', () => { let viewRoot; beforeEach( () => { - viewRoot = new ViewElement( 'p' ); + viewRoot = new ViewElement( viewDocument, 'p' ); const domRoot = document.createElement( 'p' ); domConverter.bindElements( domRoot, viewRoot ); - viewRoot._appendChild( new ViewText( 'foo' ) ); + viewRoot._appendChild( new ViewText( viewDocument, 'foo' ) ); renderer.markedTexts.clear(); renderer.markedAttributes.clear(); @@ -65,7 +68,7 @@ describe( 'Renderer', () => { } ); it( 'should mark children which need update', () => { - viewRoot._appendChild( new ViewText( 'foo' ) ); + viewRoot._appendChild( new ViewText( viewDocument, 'foo' ) ); renderer.markToSync( 'children', viewRoot ); @@ -74,9 +77,9 @@ describe( 'Renderer', () => { it( 'should not mark children if element has no corresponding node', () => { // Overwrite viewRoot with node without coresponding DOM node. - viewRoot = new ViewElement( 'p' ); + viewRoot = new ViewElement( viewDocument, 'p' ); - viewRoot._appendChild( new ViewText( 'foo' ) ); + viewRoot._appendChild( new ViewText( viewDocument, 'foo' ) ); renderer.markToSync( 'children', viewRoot ); @@ -84,7 +87,7 @@ describe( 'Renderer', () => { } ); it( 'should mark text which need update', () => { - const viewText = new ViewText( 'foo' ); + const viewText = new ViewText( viewDocument, 'foo' ); viewRoot._appendChild( viewText ); viewText._data = 'bar'; @@ -94,9 +97,9 @@ describe( 'Renderer', () => { } ); it( 'should not mark text if parent has no corresponding node', () => { - const viewText = new ViewText( 'foo' ); + const viewText = new ViewText( viewDocument, 'foo' ); // Overwrite viewRoot with node without coresponding DOM node. - viewRoot = new ViewElement( 'p' ); + viewRoot = new ViewElement( viewDocument, 'p' ); viewRoot._appendChild( viewText ); viewText._data = 'bar'; @@ -117,7 +120,7 @@ describe( 'Renderer', () => { let viewRoot, domRoot; beforeEach( () => { - viewRoot = new ViewEditableElement( 'div' ); + viewRoot = new ViewEditableElement( viewDocument, 'div' ); viewRoot.getFillerOffset = () => null; domRoot = document.createElement( 'div' ); @@ -164,7 +167,7 @@ describe( 'Renderer', () => { } ); it( 'should add children', () => { - viewRoot._appendChild( new ViewText( 'foo' ) ); + viewRoot._appendChild( new ViewText( viewDocument, 'foo' ) ); renderer.markToSync( 'children', viewRoot ); renderer.render(); @@ -176,7 +179,7 @@ describe( 'Renderer', () => { } ); it( 'should remove children', () => { - viewRoot._appendChild( new ViewText( 'foo' ) ); + viewRoot._appendChild( new ViewText( viewDocument, 'foo' ) ); renderer.markToSync( 'children', viewRoot ); renderer.render(); @@ -195,7 +198,7 @@ describe( 'Renderer', () => { } ); it( 'should update text', () => { - const viewText = new ViewText( 'foo' ); + const viewText = new ViewText( viewDocument, 'foo' ); viewRoot._appendChild( viewText ); renderer.markToSync( 'children', viewRoot ); @@ -216,7 +219,7 @@ describe( 'Renderer', () => { } ); it( 'should not update same text', () => { - const viewText = new ViewText( 'foo' ); + const viewText = new ViewText( viewDocument, 'foo' ); viewRoot._appendChild( viewText ); renderer.markToSync( 'children', viewRoot ); @@ -238,8 +241,8 @@ describe( 'Renderer', () => { } ); it( 'should not update text parent child list changed', () => { - const viewImg = new ViewElement( 'img' ); - const viewText = new ViewText( 'foo' ); + const viewImg = new ViewElement( viewDocument, 'img' ); + const viewText = new ViewText( viewDocument, 'foo' ); viewRoot._appendChild( [ viewImg, viewText ] ); renderer.markToSync( 'children', viewRoot ); @@ -252,7 +255,7 @@ describe( 'Renderer', () => { } ); it( 'should not change text if it is the same during text rendering', () => { - const viewText = new ViewText( 'foo' ); + const viewText = new ViewText( viewDocument, 'foo' ); viewRoot._appendChild( viewText ); renderer.markToSync( 'children', viewRoot ); @@ -269,7 +272,7 @@ describe( 'Renderer', () => { } ); it( 'should not change text if it is the same during children rendering', () => { - const viewText = new ViewText( 'foo' ); + const viewText = new ViewText( viewDocument, 'foo' ); viewRoot._appendChild( viewText ); renderer.markToSync( 'children', viewRoot ); @@ -286,7 +289,7 @@ describe( 'Renderer', () => { } ); it( 'should not change element if it is the same', () => { - const viewImg = new ViewElement( 'img' ); + const viewImg = new ViewElement( viewDocument, 'img' ); viewRoot._appendChild( viewImg ); // This should not be changed during the render. @@ -303,13 +306,13 @@ describe( 'Renderer', () => { } ); it( 'should change element if it is different', () => { - const viewImg = new ViewElement( 'img' ); + const viewImg = new ViewElement( viewDocument, 'img' ); viewRoot._appendChild( viewImg ); renderer.markToSync( 'children', viewRoot ); renderer.render(); - const viewP = new ViewElement( 'p' ); + const viewP = new ViewElement( viewDocument, 'p' ); viewRoot._removeChildren( 0, 1 ); viewRoot._appendChild( viewP ); @@ -321,9 +324,9 @@ describe( 'Renderer', () => { } ); it( 'should update removed item when it is reinserted', () => { - const viewFoo = new ViewText( 'foo' ); - const viewP = new ViewElement( 'p', null, viewFoo ); - const viewDiv = new ViewElement( 'div', null, viewP ); + const viewFoo = new ViewText( viewDocument, 'foo' ); + const viewP = new ViewElement( viewDocument, 'p', null, viewFoo ); + const viewDiv = new ViewElement( viewDocument, 'div', null, viewP ); viewRoot._appendChild( viewDiv ); @@ -355,9 +358,9 @@ describe( 'Renderer', () => { it( 'should update removed item when it is reinserted #2', () => { // Prepare view: root -> div "outer" -> div "inner" -> p. - const viewP = new ViewElement( 'p' ); - const viewDivInner = new ViewElement( 'div', null, viewP ); - const viewDivOuter = new ViewElement( 'div', null, viewDivInner ); + const viewP = new ViewElement( viewDocument, 'p' ); + const viewDivInner = new ViewElement( viewDocument, 'div', null, viewP ); + const viewDivOuter = new ViewElement( viewDocument, 'div', null, viewDivInner ); viewRoot._appendChild( viewDivOuter ); // Render view tree to DOM. @@ -393,9 +396,9 @@ describe( 'Renderer', () => { } ); it( 'should not throw when trying to update children of view element that got removed and lost its binding', () => { - const viewFoo = new ViewText( 'foo' ); - const viewP = new ViewElement( 'p', null, viewFoo ); - const viewDiv = new ViewElement( 'div', null, viewP ); + const viewFoo = new ViewText( viewDocument, 'foo' ); + const viewP = new ViewElement( viewDocument, 'p', null, viewFoo ); + const viewDiv = new ViewElement( viewDocument, 'div', null, viewP ); viewRoot._appendChild( viewDiv ); @@ -420,7 +423,7 @@ describe( 'Renderer', () => { const { view: viewP, selection: newSelection } = parse( 'foo[]bar' ); - const viewRoot = new ViewElement( 'p' ); + const viewRoot = new ViewElement( viewDocument, 'p' ); viewRoot._appendChild( viewP ); selection._setTo( newSelection ); @@ -720,7 +723,7 @@ describe( 'Renderer', () => { expect( domP.childNodes[ 1 ].childNodes[ 0 ].data ).to.equal( INLINE_FILLER ); // Step 2: Add text node. - const viewText = new ViewText( 'x' ); + const viewText = new ViewText( viewDocument, 'x' ); viewB._appendChild( viewText ); selection._setTo( ViewRange._createFromParentsAndOffsets( viewText, 1, viewText, 1 ) ); @@ -903,7 +906,7 @@ describe( 'Renderer', () => { domRange.collapse( true ); domSelection.addRange( domRange ); - const viewText = new ViewText( 'x' ); + const viewText = new ViewText( viewDocument, 'x' ); viewP._appendChild( viewText ); selection._setTo( ViewRange._createFromParentsAndOffsets( viewText, 1, viewText, 1 ) ); @@ -933,7 +936,7 @@ describe( 'Renderer', () => { expect( domSelection.getRangeAt( 0 ).collapsed ).to.be.true; // Add text node only in View

x{}

- const viewText = new ViewText( 'x' ); + const viewText = new ViewText( viewDocument, 'x' ); viewP._appendChild( viewText ); selection._setTo( ViewRange._createFromParentsAndOffsets( viewText, 1, viewText, 1 ) ); @@ -1031,7 +1034,7 @@ describe( 'Renderer', () => { domRange.collapse( true ); domSelection.addRange( domRange ); - const viewText = new ViewText( 'x' ); + const viewText = new ViewText( viewDocument, 'x' ); viewB._appendChild( viewText ); selection._setTo( ViewRange._createFromParentsAndOffsets( viewText, 1, viewText, 1 ) ); @@ -1074,7 +1077,7 @@ describe( 'Renderer', () => { domSelection.removeAllRanges(); // 3. Add text node only to the view:

x{}foo

. - const viewText = new ViewText( 'x' ); + const viewText = new ViewText( viewDocument, 'x' ); viewB._appendChild( viewText ); selection._setTo( ViewRange._createFromParentsAndOffsets( viewText, 1, viewText, 1 ) ); @@ -1137,7 +1140,7 @@ describe( 'Renderer', () => { // 3. Add text node only to the view:

x{}foo

. - const viewText = new ViewText( 'x' ); + const viewText = new ViewText( viewDocument, 'x' ); viewB._appendChild( viewText ); selection._setTo( ViewRange._createFromParentsAndOffsets( viewText, 1, viewText, 1 ) ); @@ -1195,7 +1198,7 @@ describe( 'Renderer', () => { domSelection.removeAllRanges(); domSelection.collapse( domDiv, 0 ); - const viewDiv = new ViewElement( 'div' ); + const viewDiv = new ViewElement( viewDocument, 'div' ); const { view: viewP, selection: newSelection } = parse( 'fo{o}' ); viewDiv._appendChild( viewP ); @@ -1329,7 +1332,7 @@ describe( 'Renderer', () => { // 3. Move the inline filler parent to a newly created element. const viewLi = view.getChild( 0 ); const viewLiIndented = view._removeChildren( 1, 1 ); // Array with one element. - const viewUl = new ViewContainerElement( 'ul', null, viewLiIndented ); + const viewUl = new ViewContainerElement( viewDocument, 'ul', null, viewLiIndented ); viewLi._appendChild( viewUl ); // 4. Mark changed items and render the view. @@ -1391,7 +1394,7 @@ describe( 'Renderer', () => { // Insert space resulting in '

x y

'. const viewB = viewP.getChild( 1 ); viewB._removeChildren( 0 ); - viewB._appendChild( new ViewText( ' y' ) ); + viewB._appendChild( new ViewText( viewDocument, ' y' ) ); renderer.markToSync( 'children', viewP ); renderer.render(); @@ -1469,7 +1472,7 @@ describe( 'Renderer', () => { // Insert space resulting in '

x y

'. viewP._removeChildren( 0 ); - viewP._insertChild( 0, new ViewText( 'x ' ) ); + viewP._insertChild( 0, new ViewText( viewDocument, 'x ' ) ); renderer.markToSync( 'children', viewP ); renderer.render(); @@ -1498,7 +1501,7 @@ describe( 'Renderer', () => { // Insert space resulting in '

x y

'. const viewB = viewP.getChild( 0 ); viewB._removeChildren( 0 ); - viewB._insertChild( 0, new ViewText( 'x ' ) ); + viewB._insertChild( 0, new ViewText( viewDocument, 'x ' ) ); renderer.markToSync( 'children', viewP ); renderer.render(); @@ -1528,7 +1531,7 @@ describe( 'Renderer', () => { // Insert space resulting in '

x y

'. const viewB = viewP.getChild( 0 ); viewB._removeChildren( 0 ); - viewB._insertChild( 0, new ViewText( 'x ' ) ); + viewB._insertChild( 0, new ViewText( viewDocument, 'x ' ) ); renderer.markToSync( 'children', viewP ); renderer.render(); @@ -1580,7 +1583,7 @@ describe( 'Renderer', () => { // '

Heading 1

' -> '

Heading 2

' const viewHeading = viewRoot.getChild( 0 ); viewHeading._removeChildren( 0, viewHeading.childCount ); - viewHeading._insertChild( 0, new ViewText( 'Heading 2' ) ); + viewHeading._insertChild( 0, new ViewText( viewDocument, 'Heading 2' ) ); // Usually whole subtree is marked to sync so we mark root, changed element and all its direct children. renderer.markToSync( 'children', viewRoot ); @@ -1697,7 +1700,7 @@ describe( 'Renderer', () => { const viewLi = view.getChild( 0 ); const viewLiIndented = view._removeChildren( 1, 1 ); // Array with one element. viewLiIndented[ 0 ]._appendChild( parse( 'Baz' ) ); - const viewUl = new ViewContainerElement( 'ul', null, viewLiIndented ); + const viewUl = new ViewContainerElement( viewDocument, 'ul', null, viewLiIndented ); viewLi._appendChild( viewUl ); renderer.markToSync( 'children', view ); @@ -1986,7 +1989,7 @@ describe( 'Renderer', () => { } ); it( 'should move fake selection container between editables', () => { - const viewEditable = new ViewEditableElement( 'div' ); + const viewEditable = new ViewEditableElement( viewDocument, 'div' ); viewEditable._appendChild( parse( 'abc xyz' ) ); const domEditable = document.createElement( 'div' ); @@ -3162,7 +3165,7 @@ describe( 'Renderer', () => { it( 'should handle uiElement rendering', () => { function createUIElement( id, text ) { - const element = new UIElement( 'span' ); + const element = new UIElement( viewDocument, 'span' ); element.render = function( domDocument ) { const domElement = this.toDomElement( domDocument ); domElement.innerText = `${ text }`; @@ -3174,7 +3177,11 @@ describe( 'Renderer', () => { const ui1 = createUIElement( 'id1', 'UI1' ); const ui2 = createUIElement( 'id2', 'UI2' ); - const viewP = new ViewContainerElement( 'p', null, [ new ViewText( 'Foo ' ), ui1, new ViewText( 'Bar' ) ] ); + const viewP = new ViewContainerElement( viewDocument, 'p', null, [ + new ViewText( viewDocument, 'Foo ' ), + ui1, + new ViewText( viewDocument, 'Bar' ) + ] ); viewRoot._appendChild( viewP ); renderer.markToSync( 'children', viewRoot ); @@ -3184,7 +3191,7 @@ describe( 'Renderer', () => { '

Foo UI1Bar

' ) ); viewP._removeChildren( 0, viewP.childCount ); - viewP._insertChild( 0, [ new ViewText( 'Foo' ), ui2, new ViewText( ' Bar' ) ] ); + viewP._insertChild( 0, [ new ViewText( viewDocument, 'Foo' ), ui2, new ViewText( viewDocument, ' Bar' ) ] ); renderer.markToSync( 'children', viewRoot ); renderer.markToSync( 'children', viewP ); @@ -3206,7 +3213,10 @@ describe( 'Renderer', () => { // While linking, the existing DOM children are moved to a new `a` element during binding // inside the `domConverter.viewToDom()` method. It happens because of a modified view structure // where view elements were moved to a newly created link view element. - const viewA = new ViewAttributeElement( 'a', { href: '#href' }, [ new ViewText( 'Foo' ), viewP.getChild( 1 ) ] ); + const viewA = new ViewAttributeElement( viewDocument, 'a', { href: '#href' }, [ + new ViewText( viewDocument, 'Foo' ), + viewP.getChild( 1 ) + ] ); viewP._removeChildren( 0, viewP.childCount ); viewP._insertChild( 0, viewA ); @@ -3517,7 +3527,7 @@ describe( 'Renderer', () => { // #1560 describe( 'attributes manipulation on replaced element', () => { it( 'should rerender element if it was removed after having its attributes removed (attribute)', () => { - const writer = new DowncastWriter(); + const writer = new DowncastWriter( viewDocument ); // 1. Setup initial view/DOM. viewRoot._appendChild( parse( '1' ) ); @@ -3546,7 +3556,7 @@ describe( 'Renderer', () => { } ); it( 'should rerender element if it was removed after having its attributes removed (classes)', () => { - const writer = new DowncastWriter(); + const writer = new DowncastWriter( viewDocument ); // 1. Setup initial view/DOM. viewRoot._appendChild( parse( 'h1p' ) ); @@ -3576,7 +3586,7 @@ describe( 'Renderer', () => { } ); it( 'should rerender element if it was removed and have its attributes removed after', () => { - const writer = new DowncastWriter(); + const writer = new DowncastWriter( viewDocument ); // 1. Setup initial view/DOM. viewRoot._appendChild( parse( '1' ) ); @@ -3714,7 +3724,7 @@ describe( 'Renderer', () => { let view, viewDoc, viewRoot, domRoot, converter; beforeEach( () => { - view = new View(); + view = new View( new StylesProcessor() ); viewDoc = view.document; domRoot = document.createElement( 'div' ); document.body.appendChild( domRoot ); @@ -3743,7 +3753,7 @@ describe( 'Renderer', () => { // Unwrap italic attribute element. view.change( writer => { - writer.unwrap( viewDoc.selection.getFirstRange(), new ViewAttributeElement( 'italic' ) ); + writer.unwrap( viewDoc.selection.getFirstRange(), new ViewAttributeElement( viewDocument, 'italic' ) ); } ); expect( getViewData( view ) ).to.equal( '

[foo]

' ); @@ -3769,7 +3779,7 @@ describe( 'Renderer', () => { // Unwrap italic attribute element and change text inside. view.change( writer => { - writer.unwrap( viewDoc.selection.getFirstRange(), new ViewAttributeElement( 'italic' ) ); + writer.unwrap( viewDoc.selection.getFirstRange(), new ViewAttributeElement( viewDocument, 'italic' ) ); } ); viewRoot.getChild( 0 ).getChild( 0 ).getChild( 0 )._data = 'bar'; @@ -3796,7 +3806,7 @@ describe( 'Renderer', () => { textNode._data = 'foobar'; view.change( writer => { - writer.insert( ViewPosition._createAfter( textNode ), new ViewAttributeElement( 'img' ) ); + writer.insert( ViewPosition._createAfter( textNode ), new ViewAttributeElement( viewDocument, 'img' ) ); } ); expect( getViewData( view ) ).to.equal( '

foobar

' ); @@ -3822,7 +3832,7 @@ describe( 'Renderer', () => { textNode._data = 'foobar'; view.change( writer => { - writer.insert( ViewPosition._createBefore( textNode ), new ViewAttributeElement( 'img' ) ); + writer.insert( ViewPosition._createBefore( textNode ), new ViewAttributeElement( viewDocument, 'img' ) ); } ); expect( getViewData( view ) ).to.equal( '

foobar

' ); @@ -3886,7 +3896,7 @@ describe( 'Renderer', () => { let viewRoot; beforeEach( () => { - viewRoot = new ViewElement( 'div' ); + viewRoot = new ViewElement( viewDocument, 'div' ); renderer.markedTexts.clear(); renderer.markedAttributes.clear(); @@ -3953,7 +3963,7 @@ describe( 'Renderer', () => { let viewRoot, domRoot; beforeEach( () => { - viewRoot = new ViewElement( 'div' ); + viewRoot = new ViewElement( viewDocument, 'div' ); domRoot = document.createElement( 'div' ); document.body.appendChild( domRoot ); @@ -3971,7 +3981,7 @@ describe( 'Renderer', () => { } ); it( 'should update text - change on end', () => { - const viewText = new ViewText( 'foo' ); + const viewText = new ViewText( viewDocument, 'foo' ); viewRoot._appendChild( viewText ); renderer.markToSync( 'children', viewRoot ); @@ -3989,7 +3999,7 @@ describe( 'Renderer', () => { } ); it( 'should update text - change on start', () => { - const viewText = new ViewText( 'foo' ); + const viewText = new ViewText( viewDocument, 'foo' ); viewRoot._appendChild( viewText ); renderer.markToSync( 'children', viewRoot ); @@ -4007,7 +4017,7 @@ describe( 'Renderer', () => { } ); it( 'should update text - change in the middle', () => { - const viewText = new ViewText( 'foobar' ); + const viewText = new ViewText( viewDocument, 'foobar' ); viewRoot._appendChild( viewText ); renderer.markToSync( 'children', viewRoot ); @@ -4025,7 +4035,7 @@ describe( 'Renderer', () => { } ); it( 'should update text - empty expected', () => { - const viewText = new ViewText( 'foo' ); + const viewText = new ViewText( viewDocument, 'foo' ); viewRoot._appendChild( viewText ); renderer.markToSync( 'children', viewRoot ); @@ -4043,7 +4053,7 @@ describe( 'Renderer', () => { } ); it( 'should update text - empty actual', () => { - const viewText = new ViewText( '' ); + const viewText = new ViewText( viewDocument, '' ); viewRoot._appendChild( viewText ); renderer.markToSync( 'children', viewRoot ); @@ -4061,7 +4071,7 @@ describe( 'Renderer', () => { } ); it( 'should handle filler during text modifications', () => { - const viewText = new ViewText( 'foo' ); + const viewText = new ViewText( viewDocument, 'foo' ); viewRoot._appendChild( viewText ); renderer.markToSync( 'children', viewRoot ); @@ -4102,7 +4112,7 @@ describe( 'Renderer', () => { } ); it( 'should handle filler during text modifications - empty text', () => { - const viewText = new ViewText( '' ); + const viewText = new ViewText( viewDocument, '' ); viewRoot._appendChild( viewText ); renderer.markToSync( 'children', viewRoot ); @@ -4145,8 +4155,8 @@ describe( 'Renderer', () => { } ); it( 'should handle filler during text modifications inside inline element', () => { - const viewB = new ViewElement( 'b' ); - const viewText = new ViewText( 'foo' ); + const viewB = new ViewElement( viewDocument, 'b' ); + const viewText = new ViewText( viewDocument, 'foo' ); viewB._appendChild( viewText ); viewRoot._appendChild( viewB ); diff --git a/tests/view/rooteditableelement.js b/tests/view/rooteditableelement.js index ea671c616..c8d849d99 100644 --- a/tests/view/rooteditableelement.js +++ b/tests/view/rooteditableelement.js @@ -10,10 +10,15 @@ import RootEditableElement from '../../src/view/rooteditableelement'; import createDocumentMock from '../../tests/view/_utils/createdocumentmock'; describe( 'RootEditableElement', () => { + let document; + + beforeEach( () => { + document = createDocumentMock(); + } ); + describe( 'constructor()', () => { it( 'should create an element with default root name', () => { - const root = new RootEditableElement( 'div' ); - root._document = createDocumentMock(); + const root = new RootEditableElement( document, 'div' ); expect( root ).to.be.instanceof( EditableElement ); expect( root ).to.be.instanceof( ContainerElement ); @@ -26,8 +31,7 @@ describe( 'RootEditableElement', () => { } ); it( 'should create an element with custom root name', () => { - const root = new RootEditableElement( 'h1' ); - root._document = createDocumentMock(); + const root = new RootEditableElement( document, 'h1' ); root.rootName = 'header'; expect( root.rootName ).to.equal( 'header' ); @@ -42,7 +46,7 @@ describe( 'RootEditableElement', () => { let el; before( () => { - el = new RootEditableElement( 'div' ); + el = new RootEditableElement( document, 'div' ); } ); it( 'should return true for rootElement/containerElement/editable/element, also with correct name and element name', () => { @@ -88,7 +92,7 @@ describe( 'RootEditableElement', () => { describe( '_name', () => { it( 'should set new name to element', () => { - const el = new RootEditableElement( '$root' ); + const el = new RootEditableElement( document, '$root' ); expect( el.name ).to.equal( '$root' ); @@ -99,13 +103,12 @@ describe( 'RootEditableElement', () => { } ); it( 'should be cloned properly', () => { - const root = new RootEditableElement( 'h1' ); - root._document = createDocumentMock(); + const root = new RootEditableElement( document, 'h1' ); root.rootName = 'header'; const newRoot = root._clone(); - expect( newRoot._document ).to.equal( root._document ); + expect( newRoot.document ).to.equal( root.document ); expect( newRoot.rootName ).to.equal( root.rootName ); } ); } ); diff --git a/tests/view/selection.js b/tests/view/selection.js index fe09a0aa1..a0fd243cf 100644 --- a/tests/view/selection.js +++ b/tests/view/selection.js @@ -16,15 +16,18 @@ import createViewRoot from './_utils/createroot'; import { parse } from '../../src/dev-utils/view'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'Selection', () => { - let selection, el, range1, range2, range3; + let selection, el, range1, range2, range3, viewDocument; testUtils.createSinonSandbox(); beforeEach( () => { - const text = new Text( 'xxxxxxxxxxxxxxxxxxxx' ); - el = new Element( 'p', null, text ); + viewDocument = new Document( new StylesProcessor() ); + + const text = new Text( viewDocument, 'xxxxxxxxxxxxxxxxxxxx' ); + el = new Element( viewDocument, 'p', null, text ); selection = new Selection(); @@ -714,8 +717,8 @@ describe( 'Selection', () => { } ); it( 'should collapse selection at node and offset', () => { - const foo = new Text( 'foo' ); - const p = new Element( 'p', null, foo ); + const foo = new Text( viewDocument, 'foo' ); + const p = new Element( viewDocument, 'p', null, foo ); selection.setTo( foo, 0 ); let range = selection.getFirstRange(); @@ -733,7 +736,7 @@ describe( 'Selection', () => { } ); it( 'should throw an error when the second parameter is not passed and first is an item', () => { - const foo = new Text( 'foo' ); + const foo = new Text( viewDocument, 'foo' ); expectToThrowCKEditorError( () => { selection.setTo( foo ); @@ -741,8 +744,8 @@ describe( 'Selection', () => { } ); it( 'should collapse selection at node and flag', () => { - const foo = new Text( 'foo' ); - const p = new Element( 'p', null, foo ); + const foo = new Text( viewDocument, 'foo' ); + const p = new Element( viewDocument, 'p', null, foo ); selection.setTo( foo, 'end' ); let range = selection.getFirstRange(); @@ -898,10 +901,10 @@ describe( 'Selection', () => { } ); it( 'should allow setting selection on an item', () => { - const textNode1 = new Text( 'foo' ); - const textNode2 = new Text( 'bar' ); - const textNode3 = new Text( 'baz' ); - const element = new Element( 'p', null, [ textNode1, textNode2, textNode3 ] ); + const textNode1 = new Text( viewDocument, 'foo' ); + const textNode2 = new Text( viewDocument, 'bar' ); + const textNode3 = new Text( viewDocument, 'baz' ); + const element = new Element( viewDocument, 'p', null, [ textNode1, textNode2, textNode3 ] ); selection.setTo( textNode2, 'on' ); @@ -914,7 +917,7 @@ describe( 'Selection', () => { } ); it( 'should allow setting selection inside an element', () => { - const element = new Element( 'p', null, [ new Text( 'foo' ), new Text( 'bar' ) ] ); + const element = new Element( viewDocument, 'p', null, [ new Text( viewDocument, 'foo' ), new Text( viewDocument, 'bar' ) ] ); selection.setTo( element, 'in' ); @@ -927,7 +930,7 @@ describe( 'Selection', () => { } ); it( 'should allow setting backward selection inside an element', () => { - const element = new Element( 'p', null, [ new Text( 'foo' ), new Text( 'bar' ) ] ); + const element = new Element( viewDocument, 'p', null, [ new Text( viewDocument, 'foo' ), new Text( viewDocument, 'bar' ) ] ); selection.setTo( element, 'in', { backward: true } ); @@ -953,10 +956,9 @@ describe( 'Selection', () => { } ); it( 'should return EditableElement when selection is placed inside', () => { - const viewDocument = new Document(); selection.setTo( viewDocument.selection ); const root = createViewRoot( viewDocument, 'div', 'main' ); - const element = new Element( 'p' ); + const element = new Element( viewDocument, 'p' ); root._appendChild( element ); selection.setTo( Range._createFromParentsAndOffsets( element, 0, element, 0 ) ); diff --git a/tests/view/styles/background.js b/tests/view/styles/background.js index e10c680b6..db956e1ba 100644 --- a/tests/view/styles/background.js +++ b/tests/view/styles/background.js @@ -9,14 +9,10 @@ import { addBackgroundRules } from '../../../src/view/styles/background'; describe( 'Background styles normalization', () => { let styles; - before( () => { + beforeEach( () => { const stylesProcessor = new StylesProcessor(); - StylesMap._setProcessor( stylesProcessor ); addBackgroundRules( stylesProcessor ); - } ); - - beforeEach( () => { - styles = new StylesMap(); + styles = new StylesMap( stylesProcessor ); } ); it( 'should normalize background', () => { diff --git a/tests/view/styles/border.js b/tests/view/styles/border.js index cbab88c8f..6b11453da 100644 --- a/tests/view/styles/border.js +++ b/tests/view/styles/border.js @@ -9,14 +9,10 @@ import { addBorderRules } from '../../../src/view/styles/border'; describe( 'Border styles normalization', () => { let styles; - before( () => { + beforeEach( () => { const stylesProcessor = new StylesProcessor(); - StylesMap._setProcessor( stylesProcessor ); addBorderRules( stylesProcessor ); - } ); - - beforeEach( () => { - styles = new StylesMap(); + styles = new StylesMap( stylesProcessor ); } ); it( 'should parse border shorthand', () => { diff --git a/tests/view/styles/margin.js b/tests/view/styles/margin.js index d21d56374..8bce19f17 100644 --- a/tests/view/styles/margin.js +++ b/tests/view/styles/margin.js @@ -9,14 +9,10 @@ import { addMarginRules } from '../../../src/view/styles/margin'; describe( 'Margin styles normalizer', () => { let styles; - before( () => { + beforeEach( () => { const stylesProcessor = new StylesProcessor(); - StylesMap._setProcessor( stylesProcessor ); addMarginRules( stylesProcessor ); - } ); - - beforeEach( () => { - styles = new StylesMap(); + styles = new StylesMap( stylesProcessor ); } ); it( 'should set all margins (1 value defined)', () => { diff --git a/tests/view/styles/padding.js b/tests/view/styles/padding.js index a1e8fd228..ccea8f3c6 100644 --- a/tests/view/styles/padding.js +++ b/tests/view/styles/padding.js @@ -9,14 +9,10 @@ import { addPaddingRules } from '../../../src/view/styles/padding'; describe( 'Padding styles normalization', () => { let styles; - before( () => { + beforeEach( () => { const stylesProcessor = new StylesProcessor(); - StylesMap._setProcessor( stylesProcessor ); addPaddingRules( stylesProcessor ); - } ); - - beforeEach( () => { - styles = new StylesMap(); + styles = new StylesMap( stylesProcessor ); } ); it( 'should set all padding values (1 value defined)', () => { diff --git a/tests/view/stylesmap.js b/tests/view/stylesmap.js index 25a7726d3..10f661d5d 100644 --- a/tests/view/stylesmap.js +++ b/tests/view/stylesmap.js @@ -9,10 +9,10 @@ import { addMarginRules } from '../../src/view/styles/margin'; import { getBoxSidesValueReducer } from '../../src/view/styles/utils'; describe( 'StylesMap', () => { - let stylesMap, stylesProcessor; + let stylesMap; beforeEach( () => { - stylesProcessor = new StylesProcessor(); + const stylesProcessor = new StylesProcessor(); // Define simple "foo" shorthand normalizers, similar to the "margin" shorthand normalizers, for testing purposes. stylesProcessor.setNormalizer( 'foo', value => ( { @@ -26,8 +26,7 @@ describe( 'StylesMap', () => { stylesProcessor.setReducer( 'foo', getBoxSidesValueReducer( 'foo' ) ); addMarginRules( stylesProcessor ); - StylesMap._setProcessor( stylesProcessor ); - stylesMap = new StylesMap(); + stylesMap = new StylesMap( stylesProcessor ); } ); describe( 'size getter', () => { @@ -272,18 +271,4 @@ describe( 'StylesMap', () => { expect( stylesMap.getStyleNames() ).to.deep.equal( [ 'foo' ] ); } ); } ); - - describe( 'static _styleProcessor getter', () => { - it( 'should return StyleProcessor instance', () => { - // Set undefined to reset field value for code coverage. - StylesMap._setProcessor( undefined ); - expect( StylesMap._styleProcessor ).to.be.instanceOf( StylesProcessor ); - } ); - - it( 'should return the same StyleProcessor instance on consecutive calls', () => { - const stylesProcessor = StylesMap._styleProcessor; - - expect( StylesMap._styleProcessor ).to.equal( stylesProcessor ); - } ); - } ); } ); diff --git a/tests/view/text.js b/tests/view/text.js index 8d76c6f3d..f6f19d748 100644 --- a/tests/view/text.js +++ b/tests/view/text.js @@ -5,11 +5,19 @@ import Node from '../../src/view/node'; import Text from '../../src/view/text'; +import Document from '../../src/view/document'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'Text', () => { + let document; + + beforeEach( () => { + document = new Document( new StylesProcessor() ); + } ); + describe( 'constructor()', () => { it( 'should create element without attributes', () => { - const text = new Text( 'foo' ); + const text = new Text( document, 'foo' ); expect( text ).to.be.an.instanceof( Node ); expect( text.data ).to.equal( 'foo' ); @@ -21,7 +29,7 @@ describe( 'Text', () => { let text; before( () => { - text = new Text( 'foo' ); + text = new Text( document, 'foo' ); } ); it( 'should return true for node, text', () => { @@ -49,7 +57,7 @@ describe( 'Text', () => { describe( '_clone()', () => { it( 'should return new text with same data', () => { - const text = new Text( 'foo bar' ); + const text = new Text( document, 'foo bar' ); const clone = text._clone(); expect( clone ).to.not.equal( text ); @@ -58,7 +66,7 @@ describe( 'Text', () => { } ); describe( 'isSimilar', () => { - const text = new Text( 'foo' ); + const text = new Text( document, 'foo' ); it( 'should return false when comparing to non-text', () => { expect( text.isSimilar( null ) ).to.be.false; @@ -70,7 +78,7 @@ describe( 'Text', () => { } ); it( 'should return true when data is the same', () => { - const other = new Text( 'foo' ); + const other = new Text( document, 'foo' ); expect( text.isSimilar( other ) ).to.be.true; } ); @@ -85,15 +93,15 @@ describe( 'Text', () => { describe( 'setText', () => { it( 'should change the text', () => { - const text = new Text( 'foo' ); + const text = new Text( document, 'foo' ); text._data = 'bar'; expect( text.data ).to.equal( 'bar' ); } ); it( 'works when using addition assignment operator (+=)', () => { - const foo = new Text( 'foo' ); - const bar = new Text( 'bar' ); + const foo = new Text( document, 'foo' ); + const bar = new Text( document, 'bar' ); foo._data += bar.data; expect( foo.data ).to.equal( 'foobar' ); diff --git a/tests/view/textproxy.js b/tests/view/textproxy.js index e403d49f2..9d78fe6b1 100644 --- a/tests/view/textproxy.js +++ b/tests/view/textproxy.js @@ -11,14 +11,17 @@ import RootEditableElement from '../../src/view/rooteditableelement'; import createDocumentMock from '../../tests/view/_utils/createdocumentmock'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import Document from '../../src/view/document'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'TextProxy', () => { - let text, parent, wrapper, textProxy; + let text, parent, wrapper, textProxy, document; beforeEach( () => { - text = new Text( 'abcdefgh' ); - parent = new ContainerElement( 'p', [], [ text ] ); - wrapper = new ContainerElement( 'div', [], parent ); + document = new Document( new StylesProcessor() ); + text = new Text( document, 'abcdefgh' ); + parent = new ContainerElement( document, 'p', [], [ text ] ); + wrapper = new ContainerElement( document, 'div', [], parent ); textProxy = new TextProxy( text, 2, 3 ); } ); @@ -90,31 +93,25 @@ describe( 'TextProxy', () => { } ); describe( 'getDocument', () => { - it( 'should return null if any parent has not set Document', () => { - expect( textProxy.document ).to.be.null; - } ); - it( 'should return Document attached to the parent element', () => { - const docMock = createDocumentMock(); - const root = new RootEditableElement( 'div' ); - root._document = docMock; + const root = new RootEditableElement( document, 'div' ); wrapper.parent = root; - expect( textProxy.document ).to.equal( docMock ); + expect( textProxy.document ).to.equal( document ); } ); - it( 'should return null if element is inside DocumentFragment', () => { - new DocumentFragment( [ wrapper ] ); // eslint-disable-line no-new + it( 'should return Document if element is inside DocumentFragment', () => { + new DocumentFragment( document, [ wrapper ] ); // eslint-disable-line no-new - expect( textProxy.document ).to.be.null; + expect( textProxy.document ).to.equal( document ); } ); } ); describe( 'getRoot', () => { it( 'should return root element', () => { - const root = new RootEditableElement( 'div' ); - root._document = createDocumentMock(); + const docMock = createDocumentMock(); + const root = new RootEditableElement( docMock, 'div' ); wrapper.parent = root; diff --git a/tests/view/treewalker.js b/tests/view/treewalker.js index 3a99ba5d8..b9ae249e6 100644 --- a/tests/view/treewalker.js +++ b/tests/view/treewalker.js @@ -13,12 +13,13 @@ import Position from '../../src/view/position'; import Range from '../../src/view/range'; import createViewRoot from './_utils/createroot'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'TreeWalker', () => { let doc, root, img1, paragraph, bold, textAbcd, charY, img2, charX, rootBeginning, rootEnding; before( () => { - doc = new Document(); + doc = new Document( new StylesProcessor() ); root = createViewRoot( doc ); // root @@ -33,14 +34,14 @@ describe( 'TreeWalker', () => { // | // |- X - textAbcd = new Text( 'abcd' ); - bold = new AttributeElement( 'b', null, [ textAbcd ] ); - charY = new Text( 'y' ); - img2 = new ContainerElement( 'img2' ); - charX = new Text( 'x' ); + textAbcd = new Text( doc, 'abcd' ); + bold = new AttributeElement( doc, 'b', null, [ textAbcd ] ); + charY = new Text( doc, 'y' ); + img2 = new ContainerElement( doc, 'img2' ); + charX = new Text( doc, 'x' ); - paragraph = new ContainerElement( 'p', null, [ bold, charY, img2, charX ] ); - img1 = new ContainerElement( 'img1' ); + paragraph = new ContainerElement( doc, 'p', null, [ bold, charY, img2, charX ] ); + img1 = new ContainerElement( doc, 'img1' ); root._insertChild( 0, [ img1, paragraph ] ); @@ -994,11 +995,11 @@ describe( 'TreeWalker', () => { } ); it( 'should iterate over document fragment', () => { - const foo = new Text( 'foo' ); - const bar = new Text( 'bar' ); - const p = new ContainerElement( 'p', null, foo ); - const b = new AttributeElement( 'b', null, bar ); - const docFrag = new DocumentFragment( [ p, b ] ); + const foo = new Text( doc, 'foo' ); + const bar = new Text( doc, 'bar' ); + const p = new ContainerElement( doc, 'p', null, foo ); + const b = new AttributeElement( doc, 'b', null, bar ); + const docFrag = new DocumentFragment( doc, [ p, b ] ); const expected = [ { diff --git a/tests/view/uielement.js b/tests/view/uielement.js index 2f22f61ee..7bb4439f8 100644 --- a/tests/view/uielement.js +++ b/tests/view/uielement.js @@ -7,13 +7,17 @@ import UIElement from '../../src/view/uielement'; import Element from '../../src/view/element'; +import Document from '../../src/view/document'; import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'UIElement', () => { - let uiElement; + let uiElement, doc; beforeEach( () => { - uiElement = new UIElement( 'span', { + doc = new Document( new StylesProcessor() ); + + uiElement = new UIElement( doc, 'span', { foo: 'bar', style: 'margin-top: 2em;color: white;', class: 'foo bar' @@ -32,7 +36,7 @@ describe( 'UIElement', () => { it( 'should throw if child elements are passed to constructor', () => { expectToThrowCKEditorError( () => { - new UIElement( 'img', null, [ new Element( 'i' ) ] ); // eslint-disable-line no-new + new UIElement( doc, 'img', null, [ new Element( doc, 'i' ) ] ); // eslint-disable-line no-new }, 'view-uielement-cannot-add: Cannot add child nodes to UIElement instance.' ); } ); } ); @@ -41,7 +45,7 @@ describe( 'UIElement', () => { let el; before( () => { - el = new UIElement( 'span' ); + el = new UIElement( doc, 'span' ); } ); it( 'should return true for uiElement/element, also with correct name and element name', () => { @@ -82,7 +86,7 @@ describe( 'UIElement', () => { describe( '_appendChild()', () => { it( 'should throw when try to append new child element', () => { expectToThrowCKEditorError( () => { - uiElement._appendChild( new Element( 'i' ) ); + uiElement._appendChild( new Element( doc, 'i' ) ); }, 'view-uielement-cannot-add: Cannot add child nodes to UIElement instance.' ); } ); } ); @@ -90,7 +94,7 @@ describe( 'UIElement', () => { describe( '_insertChild()', () => { it( 'should throw when try to insert new child element', () => { expectToThrowCKEditorError( () => { - uiElement._insertChild( 0, new Element( 'i' ) ); + uiElement._insertChild( 0, new Element( doc, 'i' ) ); }, 'view-uielement-cannot-add: Cannot add child nodes to UIElement instance.' ); } ); } ); diff --git a/tests/view/upcastwriter.js b/tests/view/upcastwriter.js index 73c082b66..1d19e1106 100644 --- a/tests/view/upcastwriter.js +++ b/tests/view/upcastwriter.js @@ -11,16 +11,17 @@ import HtmlDataProcessor from '../../src/dataprocessor/htmldataprocessor'; import ViewPosition from '../../src/view/position'; import ViewRange from '../../src/view/range'; import ViewSelection from '../../src/view/selection'; +import Document from '../../src/view/document'; +import { StylesProcessor } from '../../src/view/stylesmap'; describe( 'UpcastWriter', () => { - let writer, view, dataprocessor; - - before( () => { - writer = new UpcastWriter(); - dataprocessor = new HtmlDataProcessor(); - } ); + let writer, view, dataprocessor, document; beforeEach( () => { + document = new Document( new StylesProcessor() ); + writer = new UpcastWriter( document ); + dataprocessor = new HtmlDataProcessor( document ); + const html = '' + '

Heading 1

' + '

Foo Bar Bold

' + @@ -350,7 +351,7 @@ describe( 'UpcastWriter', () => { } ); it( 'should do nothing for elements without parent', () => { - const element = new Element( 'p', null, 'foo' ); + const element = new Element( document, 'p', null, 'foo' ); writer.unwrapElement( element ); @@ -382,7 +383,7 @@ describe( 'UpcastWriter', () => { } ); it( 'should have no effect on detached element', () => { - const el = new Element( 'h2' ); + const el = new Element( document, 'h2' ); const renamed = writer.rename( 'h3', el ); @@ -581,41 +582,41 @@ describe( 'UpcastWriter', () => { describe( 'createPositionAt()', () => { it( 'should return instance of Position', () => { - const span = new Element( 'span' ); + const span = new Element( document, 'span' ); expect( writer.createPositionAt( span, 0 ) ).to.be.instanceof( ViewPosition ); } ); } ); describe( 'createPositionAfter()', () => { it( 'should return instance of Position', () => { - const span = new Element( 'span', undefined, new Element( 'span' ) ); + const span = new Element( document, 'span', undefined, new Element( document, 'span' ) ); expect( writer.createPositionAfter( span.getChild( 0 ) ) ).to.be.instanceof( ViewPosition ); } ); } ); describe( 'createPositionBefore()', () => { it( 'should return instance of Position', () => { - const span = new Element( 'span', undefined, new Element( 'span' ) ); + const span = new Element( document, 'span', undefined, new Element( document, 'span' ) ); expect( writer.createPositionBefore( span.getChild( 0 ) ) ).to.be.instanceof( ViewPosition ); } ); } ); describe( 'createRange()', () => { it( 'should return instance of Range', () => { - expect( writer.createRange( writer.createPositionAt( new Element( 'span' ), 0 ) ) ).to.be.instanceof( ViewRange ); + expect( writer.createRange( writer.createPositionAt( new Element( document, 'span' ), 0 ) ) ).to.be.instanceof( ViewRange ); } ); } ); describe( 'createRangeIn()', () => { it( 'should return instance of Range', () => { - const span = new Element( 'span', undefined, new Element( 'span' ) ); + const span = new Element( document, 'span', undefined, new Element( document, 'span' ) ); expect( writer.createRangeIn( span.getChild( 0 ) ) ).to.be.instanceof( ViewRange ); } ); } ); describe( 'createRangeOn()', () => { it( 'should return instance of Range', () => { - const span = new Element( 'span', undefined, new Element( 'span' ) ); + const span = new Element( document, 'span', undefined, new Element( document, 'span' ) ); expect( writer.createRangeOn( span.getChild( 0 ) ) ).to.be.instanceof( ViewRange ); } ); } ); diff --git a/tests/view/utils-tests/createroot.js b/tests/view/utils-tests/createroot.js index ddb26986e..2e98efbd0 100644 --- a/tests/view/utils-tests/createroot.js +++ b/tests/view/utils-tests/createroot.js @@ -6,12 +6,13 @@ import Document from '../../../src/view/document.js'; import RootAttributeElement from '../../../src/view/rooteditableelement.js'; import createRoot from '../_utils/createroot.js'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'createRoot', () => { let viewDoc; beforeEach( () => { - viewDoc = new Document(); + viewDoc = new Document( new StylesProcessor() ); } ); it( 'should create view root element with given data', () => { diff --git a/tests/view/view/jumpoverinlinefiller.js b/tests/view/view/jumpoverinlinefiller.js index 670965339..f82d2d941 100644 --- a/tests/view/view/jumpoverinlinefiller.js +++ b/tests/view/view/jumpoverinlinefiller.js @@ -13,6 +13,7 @@ import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard'; import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; import { parse, setData } from '../../../src/dev-utils/view'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'View', () => { let view, viewDocument, domRoot; @@ -23,7 +24,7 @@ describe( 'View', () => { } ); document.body.appendChild( domRoot ); - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; createViewRoot( viewDocument ); view.attachDomRoot( domRoot ); diff --git a/tests/view/view/jumpoveruielement.js b/tests/view/view/jumpoveruielement.js index 74d72a61b..2218a5d6a 100644 --- a/tests/view/view/jumpoveruielement.js +++ b/tests/view/view/jumpoveruielement.js @@ -16,12 +16,13 @@ import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; import createViewRoot from '../_utils/createroot'; import { setData as setViewData } from '../../../src/dev-utils/view'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; +import { StylesProcessor } from '../../../src/view/stylesmap'; describe( 'View', () => { let view, viewDocument, domRoot, domSelection, viewRoot, foo, bar, ui, ui2; function createUIElement( name, contents ) { - const element = new UIElement( name ); + const element = new UIElement( viewDocument, name ); element.render = function( domDocument ) { const domElement = this.toDomElement( domDocument ); @@ -39,7 +40,7 @@ describe( 'View', () => { } ); document.body.appendChild( domRoot ); - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; viewRoot = createViewRoot( viewDocument ); view.attachDomRoot( domRoot ); @@ -49,8 +50,8 @@ describe( 'View', () => { viewDocument.isFocused = true; - foo = new ViewText( 'foo' ); - bar = new ViewText( 'bar' ); + foo = new ViewText( viewDocument, 'foo' ); + bar = new ViewText( viewDocument, 'bar' ); ui = createUIElement( 'span', 'xxx' ); ui2 = createUIElement( 'span', 'yyy' ); } ); @@ -88,7 +89,7 @@ describe( 'View', () => { describe( 'collapsed selection', () => { it( 'do nothing when another key is pressed', () => { // fooxxx{}bar - const p = new ViewContainerElement( 'p', null, [ foo, ui, bar ] ); + const p = new ViewContainerElement( viewDocument, 'p', null, [ foo, ui, bar ] ); viewRoot._appendChild( p ); view.change( writer => { @@ -106,7 +107,7 @@ describe( 'View', () => { it( 'jump over ui element when right arrow is pressed before ui element - directly before ui element', () => { // foo[]xxxbar - const p = new ViewContainerElement( 'p', null, [ foo, ui, bar ] ); + const p = new ViewContainerElement( viewDocument, 'p', null, [ foo, ui, bar ] ); viewRoot._appendChild( p ); view.change( writer => { @@ -126,7 +127,7 @@ describe( 'View', () => { it( 'jump over ui element when right arrow is pressed before ui element - not directly before ui element', () => { // foo{}xxxbar - const p = new ViewContainerElement( 'p', null, [ foo, ui, bar ] ); + const p = new ViewContainerElement( viewDocument, 'p', null, [ foo, ui, bar ] ); viewRoot._appendChild( p ); view.change( writer => { @@ -146,7 +147,7 @@ describe( 'View', () => { it( 'jump over multiple ui elements when right arrow is pressed before ui element', () => { // foo{}xxxyyybar' - const p = new ViewContainerElement( 'p', null, [ foo, ui, ui2, bar ] ); + const p = new ViewContainerElement( viewDocument, 'p', null, [ foo, ui, ui2, bar ] ); viewRoot._appendChild( p ); view.change( writer => { @@ -166,8 +167,8 @@ describe( 'View', () => { it( 'jump over ui elements at the end of container element', () => { // foo{}xxxyyy - const p = new ViewContainerElement( 'p', null, [ foo, ui, ui2 ] ); - const div = new ViewContainerElement( 'div' ); + const p = new ViewContainerElement( viewDocument, 'p', null, [ foo, ui, ui2 ] ); + const div = new ViewContainerElement( viewDocument, 'div' ); view.change( writer => { viewRoot._appendChild( p ); @@ -188,8 +189,8 @@ describe( 'View', () => { it( 'jump over ui element if selection is in attribute element - case 1', () => { // foo{}xxxbar - const b = new ViewAttribtueElement( 'b', null, foo ); - const p = new ViewContainerElement( 'p', null, [ b, ui, bar ] ); + const b = new ViewAttribtueElement( viewDocument, 'b', null, foo ); + const p = new ViewContainerElement( viewDocument, 'p', null, [ b, ui, bar ] ); viewRoot._appendChild( p ); view.change( writer => { @@ -209,8 +210,8 @@ describe( 'View', () => { it( 'jump over ui element if selection is in attribute element - case 2', () => { // foo[]xxxbar - const b = new ViewAttribtueElement( 'b', null, foo ); - const p = new ViewContainerElement( 'p', null, [ b, ui, bar ] ); + const b = new ViewAttribtueElement( viewDocument, 'b', null, foo ); + const p = new ViewContainerElement( viewDocument, 'p', null, [ b, ui, bar ] ); viewRoot._appendChild( p ); view.change( writer => { @@ -238,9 +239,9 @@ describe( 'View', () => { // // bar // - const b = new ViewAttribtueElement( 'b', null, foo ); - const i = new ViewAttribtueElement( 'i', null, b ); - const p = new ViewContainerElement( 'p', null, [ i, ui, bar ] ); + const b = new ViewAttribtueElement( viewDocument, 'b', null, foo ); + const i = new ViewAttribtueElement( viewDocument, 'i', null, b ); + const p = new ViewContainerElement( viewDocument, 'p', null, [ i, ui, bar ] ); viewRoot._appendChild( p ); @@ -268,9 +269,9 @@ describe( 'View', () => { // // bar // - const b1 = new ViewAttribtueElement( 'b' ); - const b2 = new ViewAttribtueElement( 'b' ); - const p = new ViewContainerElement( 'p', null, [ foo, b1, ui, ui2, b2, bar ] ); + const b1 = new ViewAttribtueElement( viewDocument, 'b' ); + const b2 = new ViewAttribtueElement( viewDocument, 'b' ); + const p = new ViewContainerElement( viewDocument, 'p', null, [ foo, b1, ui, ui2, b2, bar ] ); viewRoot._appendChild( p ); @@ -299,9 +300,9 @@ describe( 'View', () => { // bar // - const b1 = new ViewAttribtueElement( 'b' ); - const b2 = new ViewAttribtueElement( 'b' ); - const p = new ViewContainerElement( 'p', null, [ foo, b1, ui, ui2, b2, bar ] ); + const b1 = new ViewAttribtueElement( viewDocument, 'b' ); + const b2 = new ViewAttribtueElement( viewDocument, 'b' ); + const p = new ViewContainerElement( viewDocument, 'p', null, [ foo, b1, ui, ui2, b2, bar ] ); viewRoot._appendChild( p ); @@ -380,7 +381,7 @@ describe( 'View', () => { it( 'jump over ui element if shift key is pressed', () => { // fo{o}xxxbar - const p = new ViewContainerElement( 'p', null, [ foo, ui, bar ] ); + const p = new ViewContainerElement( viewDocument, 'p', null, [ foo, ui, bar ] ); viewRoot._appendChild( p ); @@ -407,9 +408,9 @@ describe( 'View', () => { // xxx // bar // - const b = new ViewAttribtueElement( 'b', null, foo ); - const i = new ViewAttribtueElement( 'i', null, b ); - const p = new ViewContainerElement( 'p', null, [ i, ui, bar ] ); + const b = new ViewAttribtueElement( viewDocument, 'b', null, foo ); + const i = new ViewAttribtueElement( viewDocument, 'i', null, b ); + const p = new ViewContainerElement( viewDocument, 'p', null, [ i, ui, bar ] ); viewRoot._appendChild( p ); view.change( writer => { @@ -436,9 +437,9 @@ describe( 'View', () => { // // bar // - const b1 = new ViewAttribtueElement( 'b' ); - const b2 = new ViewAttribtueElement( 'b' ); - const p = new ViewContainerElement( 'p', null, [ foo, b1, ui, ui2, b2, bar ] ); + const b1 = new ViewAttribtueElement( viewDocument, 'b' ); + const b2 = new ViewAttribtueElement( viewDocument, 'b' ); + const p = new ViewContainerElement( viewDocument, 'p', null, [ foo, b1, ui, ui2, b2, bar ] ); viewRoot._appendChild( p ); view.change( writer => { diff --git a/tests/view/view/view.js b/tests/view/view/view.js index 7f42ff235..c2a28d534 100644 --- a/tests/view/view/view.js +++ b/tests/view/view/view.js @@ -18,6 +18,7 @@ import ViewRange from '../../../src/view/range'; import ViewElement from '../../../src/view/element'; import ViewPosition from '../../../src/view/position'; import ViewSelection from '../../../src/view/selection'; +import { StylesProcessor } from '../../../src/view/stylesmap'; import count from '@ckeditor/ckeditor5-utils/src/count'; import global from '@ckeditor/ckeditor5-utils/src/dom/global'; @@ -39,7 +40,7 @@ describe( 'view', () => { document.body.appendChild( domRoot ); - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; ObserverMock = class extends Observer { @@ -90,7 +91,7 @@ describe( 'view', () => { const oldEnvIsAndroid = env.isAndroid; env.isAndroid = true; - const newView = new View(); + const newView = new View( new StylesProcessor() ); expect( newView.getObserver( InputObserver ) ).to.be.instanceof( InputObserver ); env.isAndroid = oldEnvIsAndroid; @@ -159,7 +160,7 @@ describe( 'view', () => { // The variable will be overwritten. view.destroy(); - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; view._renderer.render = sinon.spy(); @@ -269,7 +270,7 @@ describe( 'view', () => { // The variable will be overwritten. view.destroy(); - view = new View(); + view = new View( new StylesProcessor() ); viewDocument = view.document; view._renderer.render = sinon.spy(); } ); @@ -558,7 +559,7 @@ describe( 'view', () => { createElement( document, 'p' ) ] ); - const view = new View(); + const view = new View( new StylesProcessor() ); const viewDocument = view.document; createViewRoot( viewDocument, 'div', 'main' ); @@ -575,12 +576,12 @@ describe( 'view', () => { it( 'should render changes in the Document', () => { const domDiv = document.createElement( 'div' ); - const view = new View(); + const view = new View( new StylesProcessor() ); const viewDocument = view.document; createViewRoot( viewDocument, 'div', 'main' ); view.attachDomRoot( domDiv ); - viewDocument.getRoot()._appendChild( new ViewElement( 'p' ) ); + viewDocument.getRoot()._appendChild( new ViewElement( viewDocument, 'p' ) ); view.forceRender(); expect( domDiv.childNodes.length ).to.equal( 1 ); @@ -592,13 +593,13 @@ describe( 'view', () => { it( 'should render attribute changes', () => { const domRoot = document.createElement( 'div' ); - const view = new View(); + const view = new View( new StylesProcessor() ); const viewDocument = view.document; const viewRoot = createViewRoot( viewDocument, 'div', 'main' ); view.attachDomRoot( domRoot ); - const viewP = new ViewElement( 'p', { class: 'foo' } ); + const viewP = new ViewElement( viewDocument, 'p', { class: 'foo' } ); viewRoot._appendChild( viewP ); view.forceRender();