diff --git a/src/dev-utils/enableenginedebug.js b/src/dev-utils/enableenginedebug.js deleted file mode 100644 index a2215e80d..000000000 --- a/src/dev-utils/enableenginedebug.js +++ /dev/null @@ -1,588 +0,0 @@ -/** - * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - -/** - * @module engine/dev-utils/enableenginedebug - */ - -/* global console */ - -import OperationReplayer from './operationreplayer'; - -import ModelPosition from '../model/position'; -import ModelRange from '../model/range'; -import ModelText from '../model/text'; -import ModelTextProxy from '../model/textproxy'; -import ModelElement from '../model/element'; -import Operation from '../model/operation/operation'; -import AttributeOperation from '../model/operation/attributeoperation'; -import DetachOperation from '../model/operation/detachoperation'; -import InsertOperation from '../model/operation/insertoperation'; -import MarkerOperation from '../model/operation/markeroperation'; -import MoveOperation from '../model/operation/moveoperation'; -import NoOperation from '../model/operation/nooperation'; -import RenameOperation from '../model/operation/renameoperation'; -import RootAttributeOperation from '../model/operation/rootattributeoperation'; -import SplitOperation from '../model/operation/splitoperation'; -import MergeOperation from '../model/operation/mergeoperation'; -import Model from '../model/model'; -import ModelDocument from '../model/document'; -import ModelDocumentFragment from '../model/documentfragment'; -import ModelRootElement from '../model/rootelement'; - -import ViewDocument from '../view/document'; -import ViewElement from '../view/element'; -import ViewText from '../view/text'; -import ViewTextProxy from '../view/textproxy'; -import ViewDocumentFragment from '../view/documentfragment'; - -import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; -import Editor from '@ckeditor/ckeditor5-core/src/editor/editor'; - -// Sandbox class allows creating mocks of the functions and restoring these mocks to the original values. -class Sandbox { - constructor() { - // An array that contains functions which restore the original values of mocked objects. - // @private - // @type {Array.} - this._restores = []; - } - - // Creates a new mock. - // - // @param {Object} object Object to mock. - // @param {String} methodName Function to mock. - // @param {Function} fakeMethod Function that will be executed. - mock( object, methodName, fakeMethod ) { - const originalMethod = object[ methodName ]; - - object[ methodName ] = fakeMethod; - - this._restores.unshift( () => { - if ( originalMethod ) { - object[ methodName ] = originalMethod; - } else { - delete object[ methodName ]; - } - } ); - } - - // Restores all mocked functions. - restore() { - for ( const restore of this._restores ) { - restore(); - } - - this._restores = []; - } -} - -const sandbox = new Sandbox(); - -const treeDump = Symbol( '_treeDump' ); - -// Maximum number of stored states of model and view document. -const maxTreeDumpLength = 20; - -// Separator used to separate stringified operations. -const LOG_SEPARATOR = '-------'; - -// Specified whether debug tools were already enabled. -let enabled = false; - -// Logging function used to log debug messages. -let logger = console; - -/** - * Enhances model classes with logging methods. Returns a plugin that should be loaded in the editor to - * enable debugging features. - * - * Every operation applied on {@link module:engine/model/document~Document model.Document} is logged. - * - * The following classes are expanded with `log` and meaningful `toString` methods: - * * {@link module:engine/model/position~Position model.Position}, - * * {@link module:engine/model/range~Range model.Range}, - * * {@link module:engine/model/text~Text model.Text}, - * * {@link module:engine/model/element~Element model.Element}, - * * {@link module:engine/model/rootelement~RootElement model.RootElement}, - * * {@link module:engine/model/documentfragment~DocumentFragment model.DocumentFragment}, - * * {@link module:engine/model/document~Document model.Document}, - * * all {@link module:engine/model/operation/operation~Operation operations} - * * {@link module:engine/view/element~Element view.Element}, - * * {@link module:engine/view/documentfragment~DocumentFragment view.DocumentFragment}, - * * {@link module:engine/view/document~Document view.Document}. - * - * Additionally, the following logging utility methods are added: - * * {@link module:engine/model/text~Text model.Text} `logExtended`, - * * {@link module:engine/model/element~Element model.Element} `logExtended`, - * * {@link module:engine/model/element~Element model.Element} `logAll`. - * - * Additionally, the following classes are expanded with `logTree` and `printTree` methods: - * * {@link module:engine/model/element~Element model.Element}, - * * {@link module:engine/model/documentfragment~DocumentFragment model.DocumentFragment}, - * * {@link module:engine/view/element~Element view.Element}, - * * {@link module:engine/view/documentfragment~DocumentFragment view.DocumentFragment}. - * - * Finally, the following methods are added to {@link module:core/editor/editor~Editor}: `logModel`, `logView`, `logDocuments`. - * All those methods take one parameter, which is the version of the {@link module:engine/model/document~Document model document} - * for which the model or view document state should be logged. - * - * @param {Object} [_logger] An object with functions used to log messages and errors. By default messages are logged to the console. - * If specified, it is expected to have `log()` and `error()` methods. - * @returns {module:engine/dev-utils/enableenginedebug~DebugPlugin} The plugin to be loaded into the editor. - */ -export default function enableEngineDebug( _logger = console ) { - logger = _logger; - - if ( !enabled ) { - enabled = true; - - enableLoggingTools(); - enableDocumentTools(); - enableReplayerTools(); - } - - return DebugPlugin; -} - -/** - * Restores all methods that have been overwritten. - */ -export function disableEngineDebug() { - sandbox.restore(); - enabled = false; -} - -function enableLoggingTools() { - sandbox.mock( ModelPosition.prototype, 'toString', function() { - return `${ this.root } [ ${ this.path.join( ', ' ) } ]`; - } ); - - sandbox.mock( ModelPosition.prototype, 'log', function() { - logger.log( 'ModelPosition: ' + this ); - } ); - - sandbox.mock( ModelRange.prototype, 'toString', function() { - return `${ this.root } [ ${ this.start.path.join( ', ' ) } ] - [ ${ this.end.path.join( ', ' ) } ]`; - } ); - - sandbox.mock( ModelRange.prototype, 'log', function() { - logger.log( 'ModelRange: ' + this ); - } ); - - sandbox.mock( ModelText.prototype, 'toString', function() { - return `#${ this.data }`; - } ); - - sandbox.mock( ModelText.prototype, 'logExtended', function() { - logger.log( `ModelText: ${ this }, attrs: ${ mapString( this.getAttributes() ) }` ); - } ); - - sandbox.mock( ModelText.prototype, 'log', function() { - logger.log( 'ModelText: ' + this ); - } ); - - sandbox.mock( ModelTextProxy.prototype, 'toString', function() { - return `#${ this.data }`; - } ); - - sandbox.mock( ModelTextProxy.prototype, 'logExtended', function() { - logger.log( `ModelTextProxy: ${ this }, attrs: ${ mapString( this.getAttributes() ) }` ); - } ); - - sandbox.mock( ModelTextProxy.prototype, 'log', function() { - logger.log( 'ModelTextProxy: ' + this ); - } ); - - sandbox.mock( ModelElement.prototype, 'toString', function() { - return `<${ this.rootName || this.name }>`; - } ); - - sandbox.mock( ModelElement.prototype, 'log', function() { - logger.log( 'ModelElement: ' + this ); - } ); - - sandbox.mock( ModelElement.prototype, 'logExtended', function() { - logger.log( `ModelElement: ${ this }, ${ this.childCount } children, attrs: ${ mapString( this.getAttributes() ) }` ); - } ); - - sandbox.mock( ModelElement.prototype, 'logAll', function() { - logger.log( '--------------------' ); - - this.logExtended(); - logger.log( 'List of children:' ); - - for ( const child of this.getChildren() ) { - child.log(); - } - } ); - - sandbox.mock( ModelElement.prototype, 'printTree', function( level = 0 ) { - let string = ''; - - string += '\t'.repeat( level ) + `<${ this.rootName || this.name }${ mapToTags( this.getAttributes() ) }>`; - - for ( const child of this.getChildren() ) { - string += '\n'; - - if ( child.is( 'text' ) ) { - const textAttrs = mapToTags( child._attrs ); - - string += '\t'.repeat( level + 1 ); - - if ( textAttrs !== '' ) { - string += `<$text${ textAttrs }>` + child.data + ''; - } else { - string += child.data; - } - } else { - string += child.printTree( level + 1 ); - } - } - - if ( this.childCount ) { - string += '\n' + '\t'.repeat( level ); - } - - string += ``; - - return string; - } ); - - sandbox.mock( ModelElement.prototype, 'logTree', function() { - logger.log( this.printTree() ); - } ); - - sandbox.mock( ModelRootElement.prototype, 'toString', function() { - return this.rootName; - } ); - - sandbox.mock( ModelRootElement.prototype, 'log', function() { - logger.log( 'ModelRootElement: ' + this ); - } ); - - sandbox.mock( ModelDocumentFragment.prototype, 'toString', function() { - return 'documentFragment'; - } ); - - sandbox.mock( ModelDocumentFragment.prototype, 'log', function() { - logger.log( 'ModelDocumentFragment: ' + this ); - } ); - - sandbox.mock( ModelDocumentFragment.prototype, 'printTree', function() { - let string = 'ModelDocumentFragment: ['; - - for ( const child of this.getChildren() ) { - string += '\n'; - - if ( child.is( 'text' ) ) { - const textAttrs = mapToTags( child._attrs ); - - string += '\t'.repeat( 1 ); - - if ( textAttrs !== '' ) { - string += `<$text${ textAttrs }>` + child.data + ''; - } else { - string += child.data; - } - } else { - string += child.printTree( 1 ); - } - } - - string += '\n]'; - - return string; - } ); - - sandbox.mock( ModelDocumentFragment.prototype, 'logTree', function() { - logger.log( this.printTree() ); - } ); - - sandbox.mock( Operation.prototype, 'log', function() { - logger.log( this.toString() ); - } ); - - sandbox.mock( AttributeOperation.prototype, 'toString', function() { - return getClassName( this ) + `( ${ this.baseVersion } ): ` + - `"${ this.key }": ${ JSON.stringify( this.oldValue ) } -> ${ JSON.stringify( this.newValue ) }, ${ this.range }`; - } ); - - sandbox.mock( DetachOperation.prototype, 'toString', function() { - const range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany ); - const nodes = Array.from( range.getItems() ); - const nodeString = nodes.length > 1 ? `[ ${ nodes.length } ]` : nodes[ 0 ]; - - return getClassName( this ) + `( ${ this.baseVersion } ): ${ nodeString } -> ${ range }`; - } ); - - sandbox.mock( InsertOperation.prototype, 'toString', function() { - const nodeString = this.nodes.length > 1 ? `[ ${ this.nodes.length } ]` : this.nodes.getNode( 0 ); - - return getClassName( this ) + `( ${ this.baseVersion } ): ${ nodeString } -> ${ this.position }`; - } ); - - sandbox.mock( MarkerOperation.prototype, 'toString', function() { - return getClassName( this ) + `( ${ this.baseVersion } ): ` + - `"${ this.name }": ${ this.oldRange } -> ${ this.newRange }`; - } ); - - sandbox.mock( MoveOperation.prototype, 'toString', function() { - const range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany ); - - return getClassName( this ) + `( ${ this.baseVersion } ): ${ range } -> ${ this.targetPosition }`; - } ); - - sandbox.mock( NoOperation.prototype, 'toString', function() { - return `NoOperation( ${ this.baseVersion } )`; - } ); - - sandbox.mock( RenameOperation.prototype, 'toString', function() { - return getClassName( this ) + `( ${ this.baseVersion } ): ` + - `${ this.position }: "${ this.oldName }" -> "${ this.newName }"`; - } ); - - sandbox.mock( RootAttributeOperation.prototype, 'toString', function() { - return getClassName( this ) + `( ${ this.baseVersion } ): ` + - `"${ this.key }": ${ JSON.stringify( this.oldValue ) } -> ${ JSON.stringify( this.newValue ) }, ${ this.root.rootName }`; - } ); - - sandbox.mock( MergeOperation.prototype, 'toString', function() { - return getClassName( this ) + `( ${ this.baseVersion } ): ` + - `${ this.sourcePosition } -> ${ this.targetPosition } ( ${ this.howMany } ), ${ this.graveyardPosition }`; - } ); - - sandbox.mock( SplitOperation.prototype, 'toString', function() { - return getClassName( this ) + `( ${ this.baseVersion } ): ${ this.splitPosition } ` + - `( ${ this.howMany } ) -> ${ this.insertionPosition }${ this.graveyardPosition ? ' with ' + this.graveyardPosition : '' }`; - } ); - - sandbox.mock( ViewText.prototype, 'toString', function() { - return `#${ this.data }`; - } ); - - sandbox.mock( ViewText.prototype, 'logExtended', function() { - logger.log( 'ViewText: ' + this ); - } ); - - sandbox.mock( ViewText.prototype, 'log', function() { - logger.log( 'ViewText: ' + this ); - } ); - - sandbox.mock( ViewTextProxy.prototype, 'toString', function() { - return `#${ this.data }`; - } ); - - sandbox.mock( ViewTextProxy.prototype, 'logExtended', function() { - logger.log( 'ViewTextProxy: ' + this ); - } ); - - sandbox.mock( ViewTextProxy.prototype, 'log', function() { - logger.log( 'ViewTextProxy: ' + this ); - } ); - - sandbox.mock( ViewElement.prototype, 'printTree', function( level = 0 ) { - let string = ''; - - string += '\t'.repeat( level ) + `<${ this.name }${ mapToTags( this.getAttributes() ) }>`; - - for ( const child of this.getChildren() ) { - if ( child.is( 'text' ) ) { - string += '\n' + '\t'.repeat( level + 1 ) + child.data; - } else { - string += '\n' + child.printTree( level + 1 ); - } - } - - if ( this.childCount ) { - string += '\n' + '\t'.repeat( level ); - } - - string += ``; - - return string; - } ); - - sandbox.mock( ViewElement.prototype, 'logTree', function() { - logger.log( this.printTree() ); - } ); - - sandbox.mock( ViewDocumentFragment.prototype, 'printTree', function() { - let string = 'ViewDocumentFragment: ['; - - for ( const child of this.getChildren() ) { - if ( child.is( 'text' ) ) { - string += '\n' + '\t'.repeat( 1 ) + child.data; - } else { - string += '\n' + child.printTree( 1 ); - } - } - - string += '\n]'; - - return string; - } ); - - sandbox.mock( ViewDocumentFragment.prototype, 'logTree', function() { - logger.log( this.printTree() ); - } ); -} - -function enableReplayerTools() { - const _modelApplyOperation = Model.prototype.applyOperation; - - sandbox.mock( Model.prototype, 'applyOperation', function( operation ) { - if ( !this._appliedOperations ) { - this._appliedOperations = []; - } - - this._appliedOperations.push( operation ); - - return _modelApplyOperation.call( this, operation ); - } ); - - sandbox.mock( Model.prototype, 'getAppliedOperations', function() { - if ( !this._appliedOperations ) { - return ''; - } - - return this._appliedOperations.map( JSON.stringify ).join( LOG_SEPARATOR ); - } ); - - sandbox.mock( Model.prototype, 'createReplayer', function( stringifiedOperations ) { - return new OperationReplayer( this, LOG_SEPARATOR, stringifiedOperations ); - } ); -} - -function enableDocumentTools() { - const _modelApplyOperation = Model.prototype.applyOperation; - - sandbox.mock( Model.prototype, 'applyOperation', function( operation ) { - logger.log( 'Applying ' + operation ); - - if ( !this._operationLogs ) { - this._operationLogs = []; - } - - this._operationLogs.push( JSON.stringify( operation ) ); - - return _modelApplyOperation.call( this, operation ); - } ); - - sandbox.mock( ModelDocument.prototype, 'log', function( version = null ) { - version = version === null ? this.version : version; - - logDocument( this, version ); - } ); - - sandbox.mock( ViewDocument.prototype, 'log', function( version ) { - logDocument( this, version ); - } ); - - sandbox.mock( Editor.prototype, 'logModel', function( version = null ) { - version = version === null ? this.model.document.version : version; - - this.model.document.log( version ); - } ); - - sandbox.mock( Editor.prototype, 'logView', function( version ) { - this.editing.view.document.log( version ); - } ); - - sandbox.mock( Editor.prototype, 'logDocuments', function( version = null ) { - version = version === null ? this.model.document.version : version; - - this.logModel( version ); - this.logView( version ); - } ); - - function logDocument( document, version ) { - logger.log( '--------------------' ); - - if ( document[ treeDump ][ version ] ) { - logger.log( document[ treeDump ][ version ] ); - } else { - logger.log( 'Tree log unavailable for given version: ' + version ); - } - } -} - -/** - * Plugin that enables debugging features on the editor's model and view documents. - */ -class DebugPlugin extends Plugin { - constructor( editor ) { - super( editor ); - - const model = this.editor.model; - const modelDocument = model.document; - const view = this.editor.editing.view; - const viewDocument = view.document; - - modelDocument[ treeDump ] = []; - viewDocument[ treeDump ] = []; - - dumpTrees( modelDocument, modelDocument.version ); - dumpTrees( viewDocument, modelDocument.version ); - - model.on( 'applyOperation', () => { - dumpTrees( modelDocument, modelDocument.version ); - }, { priority: 'lowest' } ); - - model.document.on( 'change', () => { - dumpTrees( viewDocument, modelDocument.version ); - }, { priority: 'lowest' } ); - } -} - -// Helper function, stores the `document` state for a given `version` as a string in a private property. -function dumpTrees( document, version ) { - let string = ''; - - for ( const root of document.roots ) { - string += root.printTree() + '\n'; - } - - document[ treeDump ][ version ] = string.substr( 0, string.length - 1 ); // Remove the last "\n". - - const overflow = document[ treeDump ].length - maxTreeDumpLength; - - if ( overflow > 0 ) { - document[ treeDump ][ overflow - 1 ] = null; - } -} - -// Helper function, returns the class name of a given `Operation`. -// @param {module:engine/model/operation/operation~Operation} -// @returns {String} Class name. -function getClassName( obj ) { - return obj.constructor.className; -} - -// Helper function, converts a map to the {"key1":"value1","key2":"value2"} format. -// @param {Map} map Map to convert. -// @returns {String} Converted map. -function mapString( map ) { - const obj = {}; - - for ( const entry of map ) { - obj[ entry[ 0 ] ] = entry[ 1 ]; - } - - return JSON.stringify( obj ); -} - -// Helper function, converts a map to the key1="value1" key2="value1" format. -// @param {Map} map Map to convert. -// @returns {String} Converted map. -function mapToTags( map ) { - let string = ''; - - for ( const entry of map ) { - string += ` ${ entry[ 0 ] }=${ JSON.stringify( entry[ 1 ] ) }`; - } - - return string; -} diff --git a/src/dev-utils/utils.js b/src/dev-utils/utils.js new file mode 100644 index 000000000..fc556eab4 --- /dev/null +++ b/src/dev-utils/utils.js @@ -0,0 +1,96 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module engine/dev-utils/utils + */ + +/* globals console */ + +/** + * Helper function, converts a map to the 'key1="value1" key2="value1"' format. + * + * @private + * @param {Map} map Map to convert. + * @returns {String} Converted map. + */ +export function convertMapToTags( map ) { + let string = ''; + + for ( const entry of map ) { + string += ` ${ entry[ 0 ] }=${ JSON.stringify( entry[ 1 ] ) }`; + } + + return string; +} + +/** + * Helper function, converts a map to the '{"key1":"value1","key2":"value2"}' format. + * + * @private + * @param {Map} map Map to convert. + * @returns {String} Converted map. + */ +export function convertMapToStringifiedObject( map ) { + const obj = {}; + + for ( const entry of map ) { + obj[ entry[ 0 ] ] = entry[ 1 ]; + } + + return JSON.stringify( obj ); +} + +/** + * @private + */ +export const treeDump = Symbol( '_treeDump' ); +const maxTreeDumpLength = 20; + +/** + * Helper function, stores the `document` state for a given `version` as a string in a private property. + * + * @private + * @param {*} document + * @param {*} version + */ +export function dumpTrees( document, version ) { + console.log( document, version ); + + let string = ''; + + for ( const root of document.roots ) { + string += root.printTree() + '\n'; + } + + document[ treeDump ][ version ] = string.substr( 0, string.length - 1 ); // Remove the last "\n". + + const overflow = document[ treeDump ].length - maxTreeDumpLength; + + if ( overflow > 0 ) { + document[ treeDump ][ overflow - 1 ] = null; + } +} + +export function initDocumentDumping( document ) { + document[ treeDump ] = []; +} + +/** + * Helper function that dumps document for the given version. + * + * @private + * @param {*} document + * @param {*} version + */ +export function logDocument( document, version ) { + console.log( '--------------------' ); + + if ( document[ treeDump ][ version ] ) { + console.log( document[ treeDump ][ version ] ); + } else { + console.log( 'Tree log unavailable for given version: ' + version ); + } +} diff --git a/src/model/document.js b/src/model/document.js index 9f0d646c9..c85b9d3f7 100644 --- a/src/model/document.js +++ b/src/model/document.js @@ -18,6 +18,8 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix'; import { isInsideSurrogatePair, isInsideCombinedSymbol } from '@ckeditor/ckeditor5-utils/src/unicode'; import { clone } from 'lodash-es'; +// @if CK_DEBUG_ENGINE // const { logDocument } = require( '../dev-utils/utils' ); + const graveyardName = '$graveyard'; /** @@ -465,6 +467,11 @@ export default class Document { * @event change:data * @param {module:engine/model/batch~Batch} batch The batch that was used in the executed changes block. */ + + // @if CK_DEBUG_ENGINE // log( version = null ) { + // @if CK_DEBUG_ENGINE // version = version === null ? this.version : version; + // @if CK_DEBUG_ENGINE // logDocument( this, version ); + // @if CK_DEBUG_ENGINE // } } mix( Document, EmitterMixin ); diff --git a/src/model/documentfragment.js b/src/model/documentfragment.js index bf9c5ce2a..13f29eeee 100644 --- a/src/model/documentfragment.js +++ b/src/model/documentfragment.js @@ -13,6 +13,8 @@ import Text from './text'; import TextProxy from './textproxy'; import isIterable from '@ckeditor/ckeditor5-utils/src/isiterable'; +// @if CK_DEBUG_ENGINE // const { stringifyMap } = require( '../dev-utils/utils' ); + /** * DocumentFragment represents a part of model which does not have a common root but it's top-level nodes * can be seen as siblings. In other words, it is a detached part of model tree, without a root. @@ -318,6 +320,44 @@ export default class DocumentFragment { return nodes; } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return 'documentFragment'; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // log() { + // @if CK_DEBUG_ENGINE // console.log( 'ModelDocumentFragment: ' + this ); + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // printTree() { + // @if CK_DEBUG_ENGINE // let string = 'ModelDocumentFragment: ['; + + // @if CK_DEBUG_ENGINE // for ( const child of this.getChildren() ) { + // @if CK_DEBUG_ENGINE // string += '\n'; + + // @if CK_DEBUG_ENGINE // if ( child.is( 'text' ) ) { + // @if CK_DEBUG_ENGINE // const textAttrs = stringifyMap( child._attrs ); + + // @if CK_DEBUG_ENGINE // string += '\t'.repeat( 1 ); + + // @if CK_DEBUG_ENGINE // if ( textAttrs !== '' ) { + // @if CK_DEBUG_ENGINE // string += `<$text${ textAttrs }>` + child.data + ''; + // @if CK_DEBUG_ENGINE // } else { + // @if CK_DEBUG_ENGINE // string += child.data; + // @if CK_DEBUG_ENGINE // } + // @if CK_DEBUG_ENGINE // } else { + // @if CK_DEBUG_ENGINE // string += child.printTree( 1 ); + // @if CK_DEBUG_ENGINE // } + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // string += '\n]'; + + // @if CK_DEBUG_ENGINE // return string; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // logTree() { + // @if CK_DEBUG_ENGINE // console.log( this.printTree() ); + // @if CK_DEBUG_ENGINE // } } // Converts strings to Text and non-iterables to arrays. diff --git a/src/model/element.js b/src/model/element.js index 6058a8d05..30a385545 100644 --- a/src/model/element.js +++ b/src/model/element.js @@ -13,6 +13,8 @@ import Text from './text'; import TextProxy from './textproxy'; import isIterable from '@ckeditor/ckeditor5-utils/src/isiterable'; +// @if CK_DEBUG_ENGINE // const { stringifyMap, convertMapToStringifiedObject, convertMapToTags } = require( '../dev-utils/utils' ); + /** * Model element. Type of {@link module:engine/model/node~Node node} that has a {@link module:engine/model/element~Element#name name} and * {@link module:engine/model/element~Element#getChildren child nodes}. @@ -322,6 +324,67 @@ export default class Element extends Node { return new Element( json.name, json.attributes, children ); } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `<${ this.rootName || this.name }>`; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // log() { + // @if CK_DEBUG_ENGINE // console.log( 'ModelElement: ' + this ); + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // logExtended() { + // @if CK_DEBUG_ENGINE // console.log( `ModelElement: ${ this }, ${ this.childCount } children, + // @if CK_DEBUG_ENGINE // attrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` ); + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // logAll() { + // @if CK_DEBUG_ENGINE // console.log( '--------------------' ); + // @if CK_DEBUG_ENGINE // + // @if CK_DEBUG_ENGINE // this.logExtended(); + // @if CK_DEBUG_ENGINE // console.log( 'List of children:' ); + // @if CK_DEBUG_ENGINE // + // @if CK_DEBUG_ENGINE // for ( const child of this.getChildren() ) { + // @if CK_DEBUG_ENGINE // child.log(); + // @if CK_DEBUG_ENGINE // } + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // printTree( level = 0) { + // @if CK_DEBUG_ENGINE // let string = ''; + + // @if CK_DEBUG_ENGINE // string += '\t'.repeat( level ); + // @if CK_DEBUG_ENGINE // string += `<${ this.rootName || this.name }${ convertMapToTags( this.getAttributes() ) }>`; + + // @if CK_DEBUG_ENGINE // for ( const child of this.getChildren() ) { + // @if CK_DEBUG_ENGINE // string += '\n'; + + // @if CK_DEBUG_ENGINE // if ( child.is( 'text' ) ) { + // @if CK_DEBUG_ENGINE // const textAttrs = convertMapToTags( child._attrs ); + + // @if CK_DEBUG_ENGINE // string += '\t'.repeat( level + 1 ); + + // @if CK_DEBUG_ENGINE // if ( textAttrs !== '' ) { + // @if CK_DEBUG_ENGINE // string += `<$text${ textAttrs }>` + child.data + ''; + // @if CK_DEBUG_ENGINE // } else { + // @if CK_DEBUG_ENGINE // string += child.data; + // @if CK_DEBUG_ENGINE // } + // @if CK_DEBUG_ENGINE // } else { + // @if CK_DEBUG_ENGINE // string += child.printTree( level + 1 ); + // @if CK_DEBUG_ENGINE // } + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // if ( this.childCount ) { + // @if CK_DEBUG_ENGINE // string += '\n' + '\t'.repeat( level ); + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // string += ``; + + // @if CK_DEBUG_ENGINE // return string; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // logTree() { + // @if CK_DEBUG_ENGINE // console.log( this.printTree() ); + // @if CK_DEBUG_ENGINE // } } // Converts strings to Text and non-iterables to arrays. diff --git a/src/model/model.js b/src/model/model.js index b8fcb071f..2931545f6 100644 --- a/src/model/model.js +++ b/src/model/model.js @@ -26,6 +26,9 @@ import getSelectedContent from './utils/getselectedcontent'; import { injectSelectionPostFixer } from './utils/selection-post-fixer'; import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; +// @if CK_DEBUG_ENGINE // const { dumpTrees } = require( '../dev-utils/utils' ); +// @if CK_DEBUG_ENGINE // const { OperationReplayer } = require( '../dev-utils/operationreplayer' ).default; + /** * Editor's data model. Read about the model in the * {@glink framework/guides/architecture/editing-engine engine architecture guide}. @@ -116,6 +119,10 @@ export default class Model { } ); injectSelectionPostFixer( this ); + + // @if CK_DEBUG_ENGINE // this.on( 'applyOperation', () => { + // @if CK_DEBUG_ENGINE // dumpTrees( this.document, this.document.version ); + // @if CK_DEBUG_ENGINE // }, { priority: 'lowest' } ); } /** @@ -233,9 +240,35 @@ export default class Model { * @param {module:engine/model/operation/operation~Operation} operation The operation to apply. */ applyOperation( operation ) { + // @if CK_DEBUG_ENGINE // console.log( 'Applying ' + operation ); + + // @if CK_DEBUG_ENGINE // if ( !this._operationLogs ) { + // @if CK_DEBUG_ENGINE // this._operationLogs = []; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // this._operationLogs.push( JSON.stringify( operation ) ); + + // @if CK_DEBUG_ENGINE //if ( !this._appliedOperations ) { + // @if CK_DEBUG_ENGINE // this._appliedOperations = []; + // @if CK_DEBUG_ENGINE //} + + // @if CK_DEBUG_ENGINE //this._appliedOperations.push( operation ); + operation._execute(); } + // @if CK_DEBUG_ENGINE // getAppliedOperation() { + // @if CK_DEBUG_ENGINE // if ( !this._appliedOperations ) { + // @if CK_DEBUG_ENGINE // return ''; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // return this._appliedOperations.map( JSON.stringify ).join( '-------' ); + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // createReplayer( stringifiedOperations ) { + // @if CK_DEBUG_ENGINE // return new OperationReplayer( this, '-------', stringifiedOperations ); + // @if CK_DEBUG_ENGINE // } + /** * Inserts content at the position in the editor specified by the selection, as one would expect the paste * functionality to work. diff --git a/src/model/operation/attributeoperation.js b/src/model/operation/attributeoperation.js index 2cc283c8f..af2c404cb 100644 --- a/src/model/operation/attributeoperation.js +++ b/src/model/operation/attributeoperation.js @@ -194,4 +194,10 @@ export default class AttributeOperation extends Operation { static fromJSON( json, document ) { return new AttributeOperation( Range.fromJSON( json.range, document ), json.key, json.oldValue, json.newValue, json.baseVersion ); } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `AttributeOperation( ${ this.baseVersion } ): ` + + // @if CK_DEBUG_ENGINE // `"${ this.key }": ${ JSON.stringify( this.oldValue ) }` + + // @if CK_DEBUG_ENGINE // ` -> ${ JSON.stringify( this.newValue ) }, ${ this.range }`; + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/operation/detachoperation.js b/src/model/operation/detachoperation.js index f4a311421..78fe47208 100644 --- a/src/model/operation/detachoperation.js +++ b/src/model/operation/detachoperation.js @@ -12,6 +12,8 @@ import Range from '../range'; import { _remove } from './utils'; import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; +// @if CK_DEBUG_ENGINE // const ModelRange = require( '../range' ).default; + /** * Operation to permanently remove node from detached root. * Note this operation is only a local operation and won't be send to the other clients. @@ -90,4 +92,12 @@ export default class DetachOperation extends Operation { static get className() { return 'DetachOperation'; } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // const range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany ); + // @if CK_DEBUG_ENGINE // const nodes = Array.from( range.getItems() ); + // @if CK_DEBUG_ENGINE // const nodeString = nodes.length > 1 ? `[ ${ nodes.length } ]` : nodes[ 0 ]; + + // @if CK_DEBUG_ENGINE // return `DetachOperation( ${ this.baseVersion } ): ${ nodeString } -> ${ range }`; + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/operation/insertoperation.js b/src/model/operation/insertoperation.js index 1ea873cfa..751e07d48 100644 --- a/src/model/operation/insertoperation.js +++ b/src/model/operation/insertoperation.js @@ -179,4 +179,10 @@ export default class InsertOperation extends Operation { return insert; } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // const nodeString = this.nodes.length > 1 ? `[ ${ this.nodes.length } ]` : this.nodes.getNode( 0 ); + + // @if CK_DEBUG_ENGINE // return `InsertOperation( ${ this.baseVersion } ): ${ nodeString } -> ${ this.position }`; + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/operation/markeroperation.js b/src/model/operation/markeroperation.js index ace0bebe3..db27db612 100644 --- a/src/model/operation/markeroperation.js +++ b/src/model/operation/markeroperation.js @@ -146,4 +146,9 @@ export default class MarkerOperation extends Operation { json.baseVersion ); } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `MarkerOperation( ${ this.baseVersion } ): ` + + // @if CK_DEBUG_ENGINE // `"${ this.name }": ${ this.oldRange } -> ${ this.newRange }`; + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/operation/mergeoperation.js b/src/model/operation/mergeoperation.js index c20eafd26..472ea26f1 100644 --- a/src/model/operation/mergeoperation.js +++ b/src/model/operation/mergeoperation.js @@ -210,4 +210,10 @@ export default class MergeOperation extends Operation { return new this( sourcePosition, json.howMany, targetPosition, graveyardPosition, json.baseVersion ); } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `MergeOperation( ${ this.baseVersion } ): ` + + // @if CK_DEBUG_ENGINE // `${ this.sourcePosition } -> ${ this.targetPosition }` + + // @if CK_DEBUG_ENGINE // ` ( ${ this.howMany } ), ${ this.graveyardPosition }`; + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/operation/moveoperation.js b/src/model/operation/moveoperation.js index 98114db2e..498219e91 100644 --- a/src/model/operation/moveoperation.js +++ b/src/model/operation/moveoperation.js @@ -14,6 +14,8 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; import compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays'; import { _move } from './utils'; +// @if CK_DEBUG_ENGINE // const ModelRange = require( '../range' ).default; + /** * Operation to move a range of {@link module:engine/model/item~Item model items} * to given {@link module:engine/model/position~Position target position}. @@ -198,4 +200,10 @@ export default class MoveOperation extends Operation { return new this( sourcePosition, json.howMany, targetPosition, json.baseVersion ); } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // const range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany ); + + // @if CK_DEBUG_ENGINE // return `MoveOperation( ${ this.baseVersion } ): ${ range } -> ${ this.targetPosition }`; + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/operation/nooperation.js b/src/model/operation/nooperation.js index f2e0a2ede..afe986730 100644 --- a/src/model/operation/nooperation.js +++ b/src/model/operation/nooperation.js @@ -51,4 +51,8 @@ export default class NoOperation extends Operation { static get className() { return 'NoOperation'; } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `NoOperation( ${ this.baseVersion } )`; + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/operation/operation.js b/src/model/operation/operation.js index 06ca9753c..19648d903 100644 --- a/src/model/operation/operation.js +++ b/src/model/operation/operation.js @@ -132,4 +132,8 @@ export default class Operation { static fromJSON( json ) { return new this( json.baseVersion ); } + + // @if CK_DEBUG_ENGINE // log() { + // @if CK_DEBUG_ENGINE // console.log( this.toString() ); + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/operation/renameoperation.js b/src/model/operation/renameoperation.js index 12d874f84..35681f6e0 100644 --- a/src/model/operation/renameoperation.js +++ b/src/model/operation/renameoperation.js @@ -147,4 +147,9 @@ export default class RenameOperation extends Operation { static fromJSON( json, document ) { return new RenameOperation( Position.fromJSON( json.position, document ), json.oldName, json.newName, json.baseVersion ); } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `RenameOperation( ${ this.baseVersion } ): ` + + // @if CK_DEBUG_ENGINE // `${ this.position }: "${ this.oldName }" -> "${ this.newName }"`; + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/operation/rootattributeoperation.js b/src/model/operation/rootattributeoperation.js index 2af7597ba..68c085243 100644 --- a/src/model/operation/rootattributeoperation.js +++ b/src/model/operation/rootattributeoperation.js @@ -207,4 +207,10 @@ export default class RootAttributeOperation extends Operation { return new RootAttributeOperation( document.getRoot( json.root ), json.key, json.oldValue, json.newValue, json.baseVersion ); } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `RootAttributeOperation( ${ this.baseVersion } ): ` + + // @if CK_DEBUG_ENGINE // `"${ this.key }": ${ JSON.stringify( this.oldValue ) }` + + // @if CK_DEBUG_ENGINE // ` -> ${ JSON.stringify( this.newValue ) }, ${ this.root.rootName }`; + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/operation/splitoperation.js b/src/model/operation/splitoperation.js index fd215a91d..fa5ab629e 100644 --- a/src/model/operation/splitoperation.js +++ b/src/model/operation/splitoperation.js @@ -250,4 +250,10 @@ export default class SplitOperation extends Operation { return split; } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `SplitOperation( ${ this.baseVersion } ): ${ this.splitPosition } ` + + // @if CK_DEBUG_ENGINE // `( ${ this.howMany } ) -> ${ this.insertionPosition }` + + // @if CK_DEBUG_ENGINE // `${ this.graveyardPosition ? ' with ' + this.graveyardPosition : '' }`; + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/position.js b/src/model/position.js index 89ca090e9..aaa842b4b 100644 --- a/src/model/position.js +++ b/src/model/position.js @@ -1014,6 +1014,14 @@ export default class Position { return new Position( doc.getRoot( json.root ), json.path, json.stickiness ); } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `${ this.root } [ ${ this.path.join( ', ' ) } ]`; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // log() { + // @if CK_DEBUG_ENGINE // console.log( 'ModelPosition: ' + this ); + // @if CK_DEBUG_ENGINE // } } /** diff --git a/src/model/range.js b/src/model/range.js index bd4390743..b2fba83cd 100644 --- a/src/model/range.js +++ b/src/model/range.js @@ -958,4 +958,12 @@ export default class Range { static fromJSON( json, doc ) { return new this( Position.fromJSON( json.start, doc ), Position.fromJSON( json.end, doc ) ); } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `${ this.root } [ ${ this.start.path.join( ', ' ) } ] - [ ${ this.end.path.join( ', ' ) } ]`; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // log() { + // @if CK_DEBUG_ENGINE // console.log( 'ModelPosition: ' + this ); + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/rootelement.js b/src/model/rootelement.js index 5d97fe006..89e9de865 100644 --- a/src/model/rootelement.js +++ b/src/model/rootelement.js @@ -98,4 +98,12 @@ export default class RootElement extends Element { toJSON() { return this.rootName; } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return this.rootName; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // log() { + // @if CK_DEBUG_ENGINE // console.log( 'ModelRootElement: ' + this ); + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/text.js b/src/model/text.js index 1af57c3de..959b7e35e 100644 --- a/src/model/text.js +++ b/src/model/text.js @@ -9,6 +9,8 @@ import Node from './node'; +// @if CK_DEBUG_ENGINE // const { convertMapToStringifiedObject } = require( '../dev-utils/utils' ); + /** * Model text node. Type of {@link module:engine/model/node~Node node} that contains {@link module:engine/model/text~Text#data text data}. * @@ -115,4 +117,16 @@ export default class Text extends Node { static fromJSON( json ) { return new Text( json.data, json.attributes ); } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `#${ this.data }`; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // logExtended() { + // @if CK_DEBUG_ENGINE // console.log( `ModelText: ${ this }, attrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` ); + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // log() { + // @if CK_DEBUG_ENGINE // console.log( 'ModelText: ' + this ); + // @if CK_DEBUG_ENGINE // } } diff --git a/src/model/textproxy.js b/src/model/textproxy.js index f52051f35..c8b5ad4fc 100644 --- a/src/model/textproxy.js +++ b/src/model/textproxy.js @@ -9,6 +9,8 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; +// @if CK_DEBUG_ENGINE // const { convertMapToStringifiedObject } = require( '../dev-utils/utils' ); + /** * `TextProxy` represents a part of {@link module:engine/model/text~Text text node}. * @@ -267,4 +269,17 @@ export default class TextProxy { getAttributeKeys() { return this.textNode.getAttributeKeys(); } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `#${ this.data }`; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // log() { + // @if CK_DEBUG_ENGINE // console.log( 'ModelTextProxy: ' + this ); + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // logExtended() { + // @if CK_DEBUG_ENGINE // console.log( `ModelTextProxy: ${ this }, ` + + // @if CK_DEBUG_ENGINE // `attrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` ); + // @if CK_DEBUG_ENGINE // } } diff --git a/src/view/document.js b/src/view/document.js index c7d0eec3a..81884386b 100644 --- a/src/view/document.js +++ b/src/view/document.js @@ -12,6 +12,8 @@ import Collection from '@ckeditor/ckeditor5-utils/src/collection'; import mix from '@ckeditor/ckeditor5-utils/src/mix'; import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin'; +// @if CK_DEBUG_ENGINE // const { logDocument } = require( '../dev-utils/utils' ); + /** * Document class creates an abstract layer over the content editable area, contains a tree of view elements and * {@link module:engine/view/documentselection~DocumentSelection view selection} associated with this document. @@ -185,6 +187,10 @@ export default class Document { * * @event layoutChanged */ + + // @if CK_DEBUG_ENGINE // log( version ) { + // @if CK_DEBUG_ENGINE // logDocument( this, version ); + // @if CK_DEBUG_ENGINE // } } mix( Document, ObservableMixin ); diff --git a/src/view/documentfragment.js b/src/view/documentfragment.js index bbb7044a3..1a90024f9 100644 --- a/src/view/documentfragment.js +++ b/src/view/documentfragment.js @@ -210,6 +210,26 @@ export default class DocumentFragment { _fireChange( type, node ) { this.fire( 'change:' + type, node ); } + + // @if CK_DEBUG_ENGINE // printTree() { + // @if CK_DEBUG_ENGINE // let string = 'ViewDocumentFragment: ['; + + // @if CK_DEBUG_ENGINE // for ( const child of this.getChildren() ) { + // @if CK_DEBUG_ENGINE // if ( child.is( 'text' ) ) { + // @if CK_DEBUG_ENGINE // string += '\n' + '\t'.repeat( 1 ) + child.data; + // @if CK_DEBUG_ENGINE // } else { + // @if CK_DEBUG_ENGINE // string += '\n' + child.printTree( 1 ); + // @if CK_DEBUG_ENGINE // } + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // string += '\n]'; + + // @if CK_DEBUG_ENGINE // return string; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // logTree() { + // @if CK_DEBUG_ENGINE // console.log( this.printTree() ); + // @if CK_DEBUG_ENGINE // } } mix( DocumentFragment, EmitterMixin ); diff --git a/src/view/element.js b/src/view/element.js index d31d70ff7..6c71c4f87 100644 --- a/src/view/element.js +++ b/src/view/element.js @@ -15,6 +15,8 @@ import isIterable from '@ckeditor/ckeditor5-utils/src/isiterable'; import Matcher from './matcher'; import { isPlainObject } from 'lodash-es'; +// @if CK_DEBUG_ENGINE // const { convertMapToTags } = require( '../dev-utils/utils' ); + /** * View element. * @@ -772,6 +774,32 @@ export default class Element extends Node { * @abstract * @method module:engine/view/element~Element#getFillerOffset */ + + // @if CK_DEBUG_ENGINE // printTree( level = 0) { + // @if CK_DEBUG_ENGINE // let string = ''; + + // @if CK_DEBUG_ENGINE // string += '\t'.repeat( level ) + `<${ this.name }${ convertMapToTags( this.getAttributes() ) }>`; + + // @if CK_DEBUG_ENGINE // for ( const child of this.getChildren() ) { + // @if CK_DEBUG_ENGINE // if ( child.is( 'text' ) ) { + // @if CK_DEBUG_ENGINE // string += '\n' + '\t'.repeat( level + 1 ) + child.data; + // @if CK_DEBUG_ENGINE // } else { + // @if CK_DEBUG_ENGINE // string += '\n' + child.printTree( level + 1 ); + // @if CK_DEBUG_ENGINE // } + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // if ( this.childCount ) { + // @if CK_DEBUG_ENGINE // string += '\n' + '\t'.repeat( level ); + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // string += ``; + + // @if CK_DEBUG_ENGINE // return string; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // logTree() { + // @if CK_DEBUG_ENGINE // console.log( this.printTree() ); + // @if CK_DEBUG_ENGINE // } } // Parses attributes provided to the element constructor before they are applied to an element. If attributes are passed diff --git a/src/view/text.js b/src/view/text.js index 615641d45..c049ceed3 100644 --- a/src/view/text.js +++ b/src/view/text.js @@ -127,4 +127,16 @@ export default class Text extends Node { _clone() { return new Text( this.data ); } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `#${ this.data }`; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // log() { + // @if CK_DEBUG_ENGINE // console.log( 'ViewText: ' + this ); + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // logExtended() { + // @if CK_DEBUG_ENGINE // console.log( 'ViewText: ' + this ); + // @if CK_DEBUG_ENGINE // } } diff --git a/src/view/textproxy.js b/src/view/textproxy.js index b8aef619d..f8869eba8 100644 --- a/src/view/textproxy.js +++ b/src/view/textproxy.js @@ -179,4 +179,16 @@ export default class TextProxy { return ancestors; } + + // @if CK_DEBUG_ENGINE // toString() { + // @if CK_DEBUG_ENGINE // return `#${ this.data }`; + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // log() { + // @if CK_DEBUG_ENGINE // console.log( 'ViewTextProxy: ' + this ); + // @if CK_DEBUG_ENGINE // } + + // @if CK_DEBUG_ENGINE // logExtended() { + // @if CK_DEBUG_ENGINE // console.log( 'ViewTextProxy: ' + this ); + // @if CK_DEBUG_ENGINE // } } diff --git a/tests/dev-utils/enableenginedebug.js b/tests/dev-utils/enableenginedebug.js deleted file mode 100644 index 44e242710..000000000 --- a/tests/dev-utils/enableenginedebug.js +++ /dev/null @@ -1,709 +0,0 @@ -/** - * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - -import { default as enableEngineDebug, disableEngineDebug } from '../../src/dev-utils/enableenginedebug'; -import Editor from '@ckeditor/ckeditor5-core/src/editor/editor'; -import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor'; -import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; - -import ModelPosition from '../../src/model/position'; -import ModelRange from '../../src/model/range'; -import ModelText from '../../src/model/text'; -import ModelTextProxy from '../../src/model/textproxy'; -import ModelElement from '../../src/model/element'; -import AttributeOperation from '../../src/model/operation/attributeoperation'; -import DetachOperation from '../../src/model/operation/detachoperation'; -import InsertOperation from '../../src/model/operation/insertoperation'; -import MarkerOperation from '../../src/model/operation/markeroperation'; -import MoveOperation from '../../src/model/operation/moveoperation'; -import NoOperation from '../../src/model/operation/nooperation'; -import RenameOperation from '../../src/model/operation/renameoperation'; -import RootAttributeOperation from '../../src/model/operation/rootattributeoperation'; -import MergeOperation from '../../src/model/operation/mergeoperation'; -import SplitOperation from '../../src/model/operation/splitoperation'; -import Model from '../../src/model/model'; -import ModelDocumentFragment from '../../src/model/documentfragment'; - -import ViewDocument from '../../src/view/document'; -import ViewAttributeElement from '../../src/view/attributeelement'; -import ViewContainerElement from '../../src/view/containerelement'; -import ViewText from '../../src/view/text'; -import ViewTextProxy from '../../src/view/textproxy'; -import ViewDocumentFragment from '../../src/view/documentfragment'; -import ViewElement from '../../src/view/element'; - -import createViewRoot from '../view/_utils/createroot'; -import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; - -describe( 'enableEngineDebug', () => { - testUtils.createSinonSandbox(); - - afterEach( () => { - disableEngineDebug(); - } ); - - it( 'should return plugin class', () => { - const result = enableEngineDebug(); - - expect( result.prototype ).to.be.instanceof( Plugin ); - } ); - - it( 'should not throw when called multiple times', () => { - enableEngineDebug(); - enableEngineDebug(); - const result = enableEngineDebug(); - - expect( result.prototype ).to.be.instanceof( Plugin ); - } ); -} ); - -describe( 'disableEngineDebug', () => { - testUtils.createSinonSandbox(); - - it( 'restores modified stubs', () => { - expect( ModelPosition.prototype.log ).to.equal( undefined, 'Initial value (model/position)' ); - expect( ModelElement.prototype.printTree ).to.equal( undefined, 'Initial value (model/element)' ); - expect( ViewElement.prototype.printTree ).to.equal( undefined, 'Initial value (view/element)' ); - expect( Model.prototype.createReplayer ).to.equal( undefined, 'Initial value (model/document)' ); - expect( Editor.prototype.logDocuments ).to.equal( undefined, 'Initial value (core~editor/editor)' ); - - enableEngineDebug(); - - expect( ModelPosition.prototype.log ).to.be.a( 'function', 'After enabling engine debug (model/position)' ); - expect( ModelElement.prototype.printTree ).to.be.a( 'function', 'After enabling engine debug (model/element)' ); - expect( ViewElement.prototype.printTree ).to.be.a( 'function', 'After enabling engine debug (view/element)' ); - expect( Model.prototype.createReplayer ).to.be.a( 'function', 'After enabling engine debug (model/document)' ); - expect( Editor.prototype.logDocuments ).to.be.a( 'function', 'After enabling engine debug (core~editor/editor)' ); - - disableEngineDebug(); - - expect( ModelPosition.prototype.log ).to.equal( undefined, 'After disabling engine debug (model/position)' ); - expect( ModelElement.prototype.printTree ).to.equal( undefined, 'After disabling engine debug (model/element)' ); - expect( ViewElement.prototype.printTree ).to.equal( undefined, 'After disabling engine debug (view/element)' ); - expect( Model.prototype.createReplayer ).to.equal( undefined, 'After disabling engine debug (model/document)' ); - expect( Editor.prototype.logDocuments ).to.equal( undefined, 'After disabling engine debug (core~editor/editor)' ); - } ); -} ); - -describe( 'debug tools', () => { - let DebugPlugin, log, error; - - testUtils.createSinonSandbox(); - - before( () => { - log = sinon.spy(); - error = sinon.spy(); - DebugPlugin = enableEngineDebug( { log, error } ); - } ); - - after( () => { - disableEngineDebug(); - } ); - - afterEach( () => { - log.resetHistory(); - } ); - - describe( 'should provide logging tools', () => { - let model, modelDoc, modelRoot, modelElement, modelDocFrag; - - beforeEach( () => { - model = new Model(); - modelDoc = model.document; - modelRoot = modelDoc.createRoot(); - modelElement = new ModelElement( 'paragraph', null, new ModelText( 'foo' ) ); - modelDocFrag = new ModelDocumentFragment( [ new ModelText( 'bar' ) ] ); - } ); - - it( 'for ModelText', () => { - const foo = new ModelText( 'foo', { foo: 'bar' } ); - - expect( foo.toString() ).to.equal( '#foo' ); - - foo.log(); - expect( log.calledWithExactly( 'ModelText: #foo' ) ).to.be.true; - - foo.logExtended(); - expect( log.calledWithExactly( 'ModelText: #foo, attrs: {"foo":"bar"}' ) ).to.be.true; - } ); - - it( 'for ModelTextProxy', () => { - const foo = new ModelText( 'foo', { foo: 'bar' } ); - const proxy = new ModelTextProxy( foo, 1, 1 ); - - expect( proxy.toString() ).to.equal( '#o' ); - - proxy.log(); - expect( log.calledWithExactly( 'ModelTextProxy: #o' ) ).to.be.true; - - proxy.logExtended(); - expect( log.calledWithExactly( 'ModelTextProxy: #o, attrs: {"foo":"bar"}' ) ).to.be.true; - } ); - - it( 'for ModelElement', () => { - const paragraph = new ModelElement( 'paragraph', { foo: 'bar' }, new ModelText( 'foo' ) ); - - expect( paragraph.toString() ).to.equal( '' ); - - paragraph.log(); - expectLog( 'ModelElement: ' ); - - paragraph.logExtended(); - expectLog( 'ModelElement: , 1 children, attrs: {"foo":"bar"}' ); - - sinon.spy( paragraph, 'logExtended' ); - paragraph.logAll(); - expect( paragraph.logExtended.called ).to.be.true; - expectLog( 'ModelText: #foo' ); - } ); - - it( 'for ModelRootElement', () => { - modelRoot.log(); - expectLog( 'ModelRootElement: main' ); - } ); - - it( 'for ModelDocumentFragment', () => { - modelDocFrag.log(); - expectLog( 'ModelDocumentFragment: documentFragment' ); - } ); - - it( 'for ModelPosition', () => { - const posInRoot = new ModelPosition( modelRoot, [ 0, 1, 0 ] ); - const posInElement = new ModelPosition( modelElement, [ 0 ] ); - const posInDocFrag = new ModelPosition( modelDocFrag, [ 2, 3 ] ); - - expect( posInRoot.toString() ).to.equal( 'main [ 0, 1, 0 ]' ); - expect( posInElement.toString() ).to.equal( ' [ 0 ]' ); - expect( posInDocFrag.toString() ).to.equal( 'documentFragment [ 2, 3 ]' ); - - posInRoot.log(); - expectLog( 'ModelPosition: main [ 0, 1, 0 ]' ); - } ); - - it( 'for ModelRange', () => { - const rangeInRoot = ModelRange._createIn( modelRoot ); - const rangeInElement = ModelRange._createIn( modelElement ); - const rangeInDocFrag = ModelRange._createIn( modelDocFrag ); - - expect( rangeInRoot.toString() ).to.equal( 'main [ 0 ] - [ 0 ]' ); - expect( rangeInElement.toString() ).to.equal( ' [ 0 ] - [ 3 ]' ); - expect( rangeInDocFrag.toString() ).to.equal( 'documentFragment [ 0 ] - [ 3 ]' ); - - rangeInRoot.log(); - expectLog( 'ModelRange: main [ 0 ] - [ 0 ]' ); - } ); - - it( 'for ViewText', () => { - const foo = new ViewText( 'foo' ); - - expect( foo.toString() ).to.equal( '#foo' ); - - foo.log(); - expect( log.calledWithExactly( 'ViewText: #foo' ) ).to.be.true; - - foo.logExtended(); - expect( log.calledWithExactly( 'ViewText: #foo' ) ).to.be.true; - } ); - - it( 'for ViewTextProxy', () => { - const foo = new ViewText( 'foo', { foo: 'bar' } ); - const proxy = new ViewTextProxy( foo, 1, 1 ); - - expect( proxy.toString() ).to.equal( '#o' ); - - proxy.log(); - expect( log.calledWithExactly( 'ViewTextProxy: #o' ) ).to.be.true; - - proxy.logExtended(); - expect( log.calledWithExactly( 'ViewTextProxy: #o' ) ).to.be.true; - } ); - - describe( 'for operations', () => { - beforeEach( () => { - modelRoot._appendChild( [ new ModelText( 'foobar' ) ] ); - } ); - - it( 'AttributeOperation', () => { - const op = new AttributeOperation( ModelRange._createIn( modelRoot ), 'key', null, { foo: 'bar' }, 0 ); - - expect( op.toString() ).to.equal( 'AttributeOperation( 0 ): "key": null -> {"foo":"bar"}, main [ 0 ] - [ 6 ]' ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'DetachOperation (text node)', () => { - const op = new DetachOperation( ModelPosition._createAt( modelRoot, 0 ), 3 ); - - expect( op.toString() ).to.equal( 'DetachOperation( null ): #foo -> main [ 0 ] - [ 3 ]' ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'DetachOperation (element)', () => { - const element = new ModelElement( 'element' ); - modelRoot._insertChild( 0, element ); - - const op = new DetachOperation( ModelPosition._createBefore( element ), 1 ); - - expect( op.toString() ).to.equal( 'DetachOperation( null ): -> main [ 0 ] - [ 1 ]' ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'DetachOperation (multiple nodes)', () => { - const element = new ModelElement( 'element' ); - modelRoot._insertChild( 0, element ); - - const op = new DetachOperation( ModelPosition._createBefore( element ), 2 ); - - expect( op.toString() ).to.equal( 'DetachOperation( null ): [ 2 ] -> main [ 0 ] - [ 2 ]' ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'InsertOperation (text node)', () => { - const op = new InsertOperation( ModelPosition._createAt( modelRoot, 3 ), [ new ModelText( 'abc' ) ], 0 ); - - expect( op.toString() ).to.equal( 'InsertOperation( 0 ): #abc -> main [ 3 ]' ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'InsertOperation (element)', () => { - const op = new InsertOperation( ModelPosition._createAt( modelRoot, 3 ), [ new ModelElement( 'paragraph' ) ], 0 ); - - expect( op.toString() ).to.equal( 'InsertOperation( 0 ): -> main [ 3 ]' ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'InsertOperation (multiple nodes)', () => { - const nodes = [ new ModelText( 'x' ), new ModelElement( 'y' ), new ModelText( 'z' ) ]; - const op = new InsertOperation( ModelPosition._createAt( modelRoot, 3 ), nodes, 0 ); - - expect( op.toString() ).to.equal( 'InsertOperation( 0 ): [ 3 ] -> main [ 3 ]' ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'MarkerOperation', () => { - const op = new MarkerOperation( 'marker', null, ModelRange._createIn( modelRoot ), modelDoc.markers, false, 0 ); - - expect( op.toString() ).to.equal( 'MarkerOperation( 0 ): "marker": null -> main [ 0 ] - [ 6 ]' ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'MoveOperation', () => { - const op = new MoveOperation( ModelPosition._createAt( modelRoot, 1 ), 2, ModelPosition._createAt( modelRoot, 6 ), 0 ); - - expect( op.toString() ).to.equal( 'MoveOperation( 0 ): main [ 1 ] - [ 3 ] -> main [ 6 ]' ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'NoOperation', () => { - const op = new NoOperation( 0 ); - - expect( op.toString() ).to.equal( 'NoOperation( 0 )' ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'RenameOperation', () => { - const op = new RenameOperation( ModelPosition._createAt( modelRoot, 1 ), 'old', 'new', 0 ); - - expect( op.toString() ).to.equal( 'RenameOperation( 0 ): main [ 1 ]: "old" -> "new"' ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'RootAttributeOperation', () => { - const op = new RootAttributeOperation( modelRoot, 'key', 'old', null, 0 ); - - expect( op.toString() ).to.equal( 'RootAttributeOperation( 0 ): "key": "old" -> null, main' ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'MergeOperation', () => { - const op = new MergeOperation( - new ModelPosition( modelRoot, [ 1, 0 ] ), - 2, - new ModelPosition( modelRoot, [ 0, 2 ] ), - new ModelPosition( modelDoc.graveyard, [ 0 ] ), - 0 - ); - - expect( op.toString() ).to.equal( - 'MergeOperation( 0 ): main [ 1, 0 ] -> main [ 0, 2 ] ( 2 ), $graveyard [ 0 ]' - ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'SplitOperation without graveyard position', () => { - const position = new ModelPosition( modelRoot, [ 1, 4 ] ); - const op = new SplitOperation( position, 6, null, 0 ); - - expect( op.toString() ).to.equal( - 'SplitOperation( 0 ): main [ 1, 4 ] ( 6 ) -> main [ 2 ]' - ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - - it( 'SplitOperation with graveyard position', () => { - const position = new ModelPosition( modelRoot, [ 1, 4 ] ); - const op = new SplitOperation( position, 6, new ModelPosition( modelDoc.graveyard, [ 0 ] ), 0 ); - - expect( op.toString() ).to.equal( - 'SplitOperation( 0 ): main [ 1, 4 ] ( 6 ) -> main [ 2 ] with $graveyard [ 0 ]' - ); - - op.log(); - expect( log.calledWithExactly( op.toString() ) ).to.be.true; - } ); - } ); - - it( 'for applied operations', () => { - const op = new InsertOperation( ModelPosition._createAt( modelRoot, 0 ), [ new ModelText( 'foo' ) ], 0 ); - - model.applyOperation( op ); - - expect( log.calledWithExactly( 'Applying InsertOperation( 0 ): #foo -> main [ 0 ]' ) ).to.be.true; - } ); - } ); - - describe( 'should provide tree printing tools', () => { - it( 'for model', () => { - const model = new Model(); - const modelDoc = model.document; - const modelRoot = modelDoc.createRoot(); - - modelRoot._appendChild( [ - new ModelElement( 'paragraph', { foo: 'bar' }, [ - new ModelText( 'This is ' ), new ModelText( 'bold', { bold: true } ), new ModelText( '.' ) - ] ), - new ModelElement( 'listItem', { listType: 'numbered', listIndent: 0 }, new ModelText( 'One.' ) ), - ] ); - - const modelRootTree = modelRoot.printTree(); - - expect( modelRootTree ).to.equal( - '
' + - '\n\t' + - '\n\t\tThis is ' + - '\n\t\t<$text bold=true>bold' + - '\n\t\t.' + - '\n\t' + - '\n\t' + - '\n\t\tOne.' + - '\n\t' + - '\n
' - ); - - modelRoot.logTree(); - expect( log.calledWithExactly( modelRootTree ) ).to.be.true; - - const modelParagraph = modelRoot.getChild( 0 ); - const modelParagraphTree = modelParagraph.printTree(); - expect( modelParagraphTree ).to.equal( - '' + - '\n\tThis is ' + - '\n\t<$text bold=true>bold' + - '\n\t.' + - '\n' - ); - - log.resetHistory(); - modelParagraph.logTree(); - expect( log.calledWithExactly( modelParagraphTree ) ).to.be.true; - - const modelDocFrag = new ModelDocumentFragment( [ - new ModelText( 'This is ' ), new ModelText( 'bold', { bold: true } ), new ModelText( '.' ), - new ModelElement( 'paragraph', { foo: 'bar' }, [ - new ModelText( 'This is ' ), new ModelText( 'bold', { bold: true } ), new ModelText( '.' ) - ] ) - ] ); - - const modelDocFragTree = modelDocFrag.printTree(); - expect( modelDocFragTree ).to.equal( - 'ModelDocumentFragment: [' + - '\n\tThis is ' + - '\n\t<$text bold=true>bold' + - '\n\t.' + - '\n\t' + - '\n\t\tThis is ' + - '\n\t\t<$text bold=true>bold' + - '\n\t\t.' + - '\n\t' + - '\n]' - ); - - log.resetHistory(); - modelDocFrag.logTree(); - expect( log.calledWithExactly( modelDocFragTree ) ).to.be.true; - } ); - - it( 'for view', () => { - const viewDoc = new ViewDocument(); - const viewRoot = createViewRoot( viewDoc ); - - viewRoot._appendChild( [ - new ViewContainerElement( 'p', { foo: 'bar' }, [ - new ViewText( 'This is ' ), new ViewAttributeElement( 'b', null, new ViewText( 'bold' ) ), new ViewText( '.' ) - ] ), - new ViewContainerElement( 'ol', null, [ - new ViewContainerElement( 'li', null, new ViewText( 'One.' ) ) - ] ) - ] ); - - const viewRootTree = viewRoot.printTree(); - - expect( viewRootTree ).to.equal( - '
' + - '\n\t

' + - '\n\t\tThis is ' + - '\n\t\t' + - '\n\t\t\tbold' + - '\n\t\t' + - '\n\t\t.' + - '\n\t

' + - '\n\t
    ' + - '\n\t\t
  1. ' + - '\n\t\t\tOne.' + - '\n\t\t
  2. ' + - '\n\t
' + - '\n
' - ); - - viewRoot.logTree(); - expect( log.calledWithExactly( viewRootTree ) ).to.be.true; - - const viewParagraph = viewRoot.getChild( 0 ); - const viewParagraphTree = viewParagraph.printTree(); - expect( viewParagraphTree ).to.equal( - '

' + - '\n\tThis is ' + - '\n\t' + - '\n\t\tbold' + - '\n\t' + - '\n\t.' + - '\n

' - ); - - log.resetHistory(); - viewParagraph.logTree(); - expect( log.calledWithExactly( viewParagraphTree ) ).to.be.true; - - const viewDocFrag = new ViewDocumentFragment( [ - new ViewText( 'Text.' ), - new ViewContainerElement( 'p', { foo: 'bar' }, [ - new ViewText( 'This is ' ), new ViewAttributeElement( 'b', null, new ViewText( 'bold' ) ), new ViewText( '.' ) - ] ) - ] ); - - const viewDocFragTree = viewDocFrag.printTree(); - expect( viewDocFragTree ).to.equal( - 'ViewDocumentFragment: [' + - '\n\tText.' + - '\n\t

' + - '\n\t\tThis is ' + - '\n\t\t' + - '\n\t\t\tbold' + - '\n\t\t' + - '\n\t\t.' + - '\n\t

' + - '\n]' - ); - - log.resetHistory(); - viewDocFrag.logTree(); - expect( log.calledWithExactly( viewDocFragTree ) ).to.be.true; - } ); - } ); - - describe( 'should store model and view trees state', () => { - let editor; - - beforeEach( () => { - return VirtualTestEditor.create( { - plugins: [ DebugPlugin ] - } ).then( _editor => { - editor = _editor; - } ); - } ); - - it( 'should store model and view state after each applied operation', () => { - const model = editor.model; - const modelDoc = model.document; - const modelRoot = modelDoc.getRoot(); - const view = editor.editing.view; - const viewDoc = view.document; - - // Reset model document version to ensure it will start at 0. - model.document.version = 0; - - model.change( () => { - const insert = new InsertOperation( ModelPosition._createAt( modelRoot, 0 ), new ModelText( 'foobar' ), 0 ); - model.applyOperation( insert ); - - const graveyard = modelDoc.graveyard; - const move = new MoveOperation( ModelPosition._createAt( modelRoot, 1 ), 2, ModelPosition._createAt( graveyard, 0 ), 1 ); - model.applyOperation( move ); - } ); - - log.resetHistory(); - - modelDoc.log( 0 ); - expectLog( - '<$graveyard>' + - '\n
' - ); - - modelDoc.log( 1 ); - expectLog( - '<$graveyard>' + - '\n
' + - '\n\tfoobar' + - '\n
' - ); - - modelDoc.log( 2 ); - expectLog( - '<$graveyard>' + - '\n\too' + - '\n' + - '\n
' + - '\n\tfbar' + - '\n
' - ); - - modelDoc.log(); - expectLog( - '<$graveyard>' + - '\n\too' + - '\n' + - '\n
' + - '\n\tfbar' + - '\n
' - ); - - viewDoc.log( 0 ); - expectLog( - '<$root>' - ); - - viewDoc.log( 2 ); - expectLog( - '<$root>' + - '\n\tfbar' + - '\n' - ); - - sinon.spy( modelDoc, 'log' ); - sinon.spy( viewDoc, 'log' ); - - editor.logModel( 1 ); - expect( modelDoc.log.calledWithExactly( 1 ), 1 ).to.be.true; - - editor.logView( 2 ); - expect( viewDoc.log.calledWithExactly( 2 ), 2 ).to.be.true; - - modelDoc.log.resetHistory(); - viewDoc.log.resetHistory(); - - editor.logModel(); - expect( modelDoc.log.calledWithExactly( 2 ), 3 ).to.be.true; - - modelDoc.log.resetHistory(); - viewDoc.log.resetHistory(); - - editor.logDocuments(); - expect( modelDoc.log.calledWithExactly( 2 ), 4 ).to.be.true; - expect( viewDoc.log.calledWithExactly( 2 ), 5 ).to.be.true; - - modelDoc.log.resetHistory(); - viewDoc.log.resetHistory(); - - editor.logDocuments( 1 ); - expect( modelDoc.log.calledWithExactly( 1 ), 6 ).to.be.true; - expect( viewDoc.log.calledWithExactly( 1 ), 7 ).to.be.true; - } ); - - it( 'should remove old states', () => { - const model = editor.model; - const modelDoc = model.document; - const modelRoot = model.document.getRoot(); - - for ( let i = 0; i < 25; i++ ) { - const insert = new InsertOperation( ModelPosition._createAt( modelRoot, 0 ), new ModelText( 'foobar' ), modelDoc.version ); - model.applyOperation( insert ); - } - - modelDoc.log( 0 ); - expectLog( 'Tree log unavailable for given version: 0' ); - } ); - } ); - - describe( 'should provide methods for operation replayer', () => { - it( 'getAppliedOperations()', () => { - const model = new Model(); - const modelDoc = model.document; - - expect( model.getAppliedOperations() ).to.equal( '' ); - - const otherRoot = modelDoc.createRoot( '$root', 'otherRoot' ); - const element = new ModelElement( 'paragraph' ); - - otherRoot._appendChild( element ); - - const insert = new InsertOperation( ModelPosition._createAt( element, 0 ), new ModelText( 'foo' ), 0 ); - model.applyOperation( insert ); - - const stringifiedOperations = model.getAppliedOperations(); - - expect( stringifiedOperations ).to.equal( JSON.stringify( insert ) ); - } ); - - it( 'createReplayer()', () => { - const model = new Model(); - const modelDoc = model.document; - - const otherRoot = modelDoc.createRoot( '$root', 'otherRoot' ); - const element = new ModelElement( 'paragraph' ); - - otherRoot._appendChild( element ); - - const insert = new InsertOperation( ModelPosition._createAt( element, 0 ), new ModelText( 'foo' ), 0 ); - model.applyOperation( insert ); - - const stringifiedOperations = model.getAppliedOperations(); - const operationReplayer = model.createReplayer( stringifiedOperations ); - - expect( operationReplayer.getOperationsToReplay() ).to.deep.equal( [ JSON.parse( stringifiedOperations ) ] ); - } ); - } ); - - function expectLog( expectedLogMsg ) { - expect( log.calledWithExactly( expectedLogMsg ) ).to.be.true; - log.resetHistory(); - } -} );