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

Commit

Permalink
Merge branch 'master' into t/799
Browse files Browse the repository at this point in the history
  • Loading branch information
Piotr Jasiun committed Jun 14, 2017
2 parents 06ba63e + 9176877 commit 157ca15
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 181 deletions.
59 changes: 22 additions & 37 deletions src/controller/datacontroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import mix from '@ckeditor/ckeditor5-utils/src/mix';
import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';

import Mapper from '../conversion/mapper';

Expand Down Expand Up @@ -38,7 +38,7 @@ import getSelectedContent from './getselectedcontent';
* * {@link module:engine/conversion/modelconversiondispatcher~ModelConversionDispatcher model to view} and
* * {@link module:engine/conversion/viewconversiondispatcher~ViewConversionDispatcher view to model} converters.
*
* @mixes module:utils/emittermixin~EmitterMixin
* @mixes module:utils/emittermixin~ObservableMixin
*/
export default class DataController {
/**
Expand Down Expand Up @@ -117,12 +117,8 @@ export default class DataController {
this.viewToModel.on( 'element', convertToModelFragment(), { priority: 'lowest' } );
this.viewToModel.on( 'documentFragment', convertToModelFragment(), { priority: 'lowest' } );

this.on( 'insertContent', ( evt, data ) => insertContent( this, data.content, data.selection, data.batch ) );
this.on( 'deleteContent', ( evt, data ) => deleteContent( data.selection, data.batch, data.options ) );
this.on( 'modifySelection', ( evt, data ) => modifySelection( this, data.selection, data.options ) );
this.on( 'getSelectedContent', ( evt, data ) => {
data.content = getSelectedContent( data.selection );
} );
[ 'insertContent', 'deleteContent', 'modifySelection', 'getSelectedContent' ]
.forEach( methodName => this.decorate( methodName ) );
}

/**
Expand Down Expand Up @@ -257,7 +253,7 @@ export default class DataController {
* changes will be added to a new batch.
*/
insertContent( content, selection, batch ) {
this.fire( 'insertContent', { content, selection, batch } );
insertContent( this, content, selection, batch );
}

/**
Expand All @@ -277,7 +273,7 @@ export default class DataController {
* @param {Object} options See {@link module:engine/controller/deletecontent~deleteContent}'s options.
*/
deleteContent( selection, batch, options ) {
this.fire( 'deleteContent', { batch, selection, options } );
deleteContent( selection, batch, options );
}

/**
Expand All @@ -288,7 +284,7 @@ export default class DataController {
* @param {Object} options See {@link module:engine/controller/modifyselection~modifySelection}'s options.
*/
modifySelection( selection, options ) {
this.fire( 'modifySelection', { selection, options } );
modifySelection( this, selection, options );
}

/**
Expand All @@ -299,59 +295,48 @@ export default class DataController {
* @returns {module:engine/model/documentfragment~DocumentFragment} Document fragment holding the clone of the selected content.
*/
getSelectedContent( selection ) {
const evtData = { selection };

this.fire( 'getSelectedContent', evtData );

return evtData.content;
return getSelectedContent( selection );
}
}

mix( DataController, EmitterMixin );
mix( DataController, ObservableMixin );

/**
* Event fired when {@link #insertContent} method is called.
*
* The {@link #insertContent default action of that method} is implemented as a
* listener to this event so it can be fully customized by the features.
*
* @event insertContent
* @param {Object} data
* @param {module:engine/view/documentfragment~DocumentFragment|module:engine/model/item~Item} data.content The content to insert.
* @param {module:engine/model/selection~Selection} data.selection Selection into which the content should be inserted.
* @param {module:engine/model/batch~Batch} [data.batch] Batch to which deltas will be added.
* @param {Array} args The arguments passed to the original method.
*/

/**
* Event fired when {@link #deleteContent} method is called.
* The {@link module:engine/controller/deletecontent~deleteContent default action of that method} is implemented as a
*
* The {@link #deleteContent default action of that method} is implemented as a
* listener to this event so it can be fully customized by the features.
*
* @event deleteContent
* @param {Object} data
* @param {module:engine/model/batch~Batch} data.batch
* @param {module:engine/model/selection~Selection} data.selection
* @param {Object} data.options See {@link module:engine/controller/deletecontent~deleteContent}'s options.
* @param {Array} args The arguments passed to the original method.
*/

/**
* Event fired when {@link #modifySelection} method is called.
* The {@link module:engine/controller/modifyselection~modifySelection default action of that method} is implemented as a
*
* The {@link #modifySelection default action of that method} is implemented as a
* listener to this event so it can be fully customized by the features.
*
* @event modifySelection
* @param {Object} data
* @param {module:engine/model/selection~Selection} data.selection
* @param {Object} data.options See {@link module:engine/controller/modifyselection~modifySelection}'s options.
* @param {Array} args The arguments passed to the original method.
*/

/**
* Event fired when {@link module:engine/controller/datacontroller~DataController#getSelectedContent} method is called.
* The {@link module:engine/controller/getselectedcontent~getSelectedContent default action of that method} is implemented as a
* Event fired when {@link #getSelectedContent} method is called.
*
* The {@link #getSelectedContent default action of that method} is implemented as a
* listener to this event so it can be fully customized by the features.
*
* @event module:engine/controller/datacontroller~DataController#getSelectedContent
* @param {Object} data
* @param {module:engine/model/selection~Selection} data.selection
* @param {module:engine/model/documentfragment~DocumentFragment} data.content The document fragment to return
* (holding a clone of the selected content).
* @event getSelectedContent
* @param {Array} args The arguments passed to the original method.
*/
12 changes: 4 additions & 8 deletions src/view/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,7 @@ export default class Document {

injectQuirksHandling( this );

// Listens `render` event on default priority.
// This way we can attach other listeners before or after rendering execution.
this.on( 'render', () => {
this.disableObservers();
this.renderer.render();
this.enableObservers();
} );
this.decorate( 'render' );
}

/**
Expand Down Expand Up @@ -266,7 +260,9 @@ export default class Document {
* @fires render
*/
render() {
this.fire( 'render' );
this.disableObservers();
this.renderer.render();
this.enableObservers();
}

/**
Expand Down
180 changes: 59 additions & 121 deletions tests/controller/datacontroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,94 +42,6 @@ describe( 'DataController', () => {

expect( data.processor ).to.be.undefined;
} );

it( 'should add insertContent listener and inserts document fragment when event fires', () => {
const batch = modelDocument.batch();
const content = new ModelDocumentFragment( [ new ModelText( 'x' ) ] );

schema.registerItem( 'paragraph', '$block' );

setData( modelDocument, '<paragraph>a[]b</paragraph>' );

data.fire( 'insertContent', { content, selection: modelDocument.selection, batch } );

expect( getData( modelDocument ) ).to.equal( '<paragraph>ax[]b</paragraph>' );
expect( batch.deltas.length ).to.be.above( 0 );
} );

it( 'should add insertContent listener and inserts an item when event fires', () => {
const batch = modelDocument.batch();
const content = new ModelText( 'x' );

schema.registerItem( 'paragraph', '$block' );

setData( modelDocument, '<paragraph>a[]b</paragraph>' );

data.fire( 'insertContent', { content, selection: modelDocument.selection, batch } );

expect( getData( modelDocument ) ).to.equal( '<paragraph>ax[]b</paragraph>' );
expect( batch.deltas.length ).to.be.above( 0 );
} );

it( 'should add deleteContent listener', () => {
schema.registerItem( 'paragraph', '$block' );

setData( modelDocument, '<paragraph>f[oo</paragraph><paragraph>ba]r</paragraph>' );

const batch = modelDocument.batch();

data.fire( 'deleteContent', { batch, selection: modelDocument.selection } );

expect( getData( modelDocument ) ).to.equal( '<paragraph>f[]</paragraph><paragraph>r</paragraph>' );
expect( batch.deltas ).to.not.be.empty;
} );

it( 'should add deleteContent listener which passes ', () => {
schema.registerItem( 'paragraph', '$block' );

setData( modelDocument, '<paragraph>f[oo</paragraph><paragraph>ba]r</paragraph>' );

const batch = modelDocument.batch();

data.fire( 'deleteContent', {
batch,
selection: modelDocument.selection,
options: { merge: true }
} );

expect( getData( modelDocument ) ).to.equal( '<paragraph>f[]r</paragraph>' );
} );

it( 'should add modifySelection listener', () => {
schema.registerItem( 'paragraph', '$block' );

setData( modelDocument, '<paragraph>foo[]bar</paragraph>' );

data.fire( 'modifySelection', {
selection: modelDocument.selection,
options: {
direction: 'backward'
}
} );

expect( getData( modelDocument ) )
.to.equal( '<paragraph>fo[o]bar</paragraph>' );
expect( modelDocument.selection.isBackward ).to.true;
} );

it( 'should add getSelectedContent listener', () => {
schema.registerItem( 'paragraph', '$block' );

setData( modelDocument, '<paragraph>fo[ob]ar</paragraph>' );

const evtData = {
selection: modelDocument.selection
};

data.fire( 'getSelectedContent', evtData );

expect( stringify( evtData.content ) ).to.equal( 'ob' );
} );
} );

describe( 'parse', () => {
Expand Down Expand Up @@ -425,80 +337,106 @@ describe( 'DataController', () => {
} );

describe( 'insertContent', () => {
it( 'should fire the insertContent event', () => {
it( 'should be decorated', () => {
schema.allow( { name: '$text', inside: '$root' } ); // To surpress warnings.

const spy = sinon.spy();
const content = new ModelDocumentFragment( [ new ModelText( 'x' ) ] );
const batch = modelDocument.batch();
schema.allow( { name: '$text', inside: '$root' } );

data.on( 'insertContent', spy );

data.insertContent( content, modelDocument.selection, batch );
data.insertContent( new ModelText( 'a' ), modelDocument.selection );

expect( spy.calledOnce ).to.be.true;
} );

it( 'should insert content (item)', () => {
schema.registerItem( 'paragraph', '$block' );

setData( modelDocument, '<paragraph>fo[]ar</paragraph>' );

data.insertContent( new ModelText( 'ob' ), modelDocument.selection );

expect( getData( modelDocument ) ).to.equal( '<paragraph>foob[]ar</paragraph>' );
} );

it( 'should insert content (document fragment)', () => {
schema.registerItem( 'paragraph', '$block' );

setData( modelDocument, '<paragraph>fo[]ar</paragraph>' );

data.insertContent( new ModelDocumentFragment( [ new ModelText( 'ob' ) ] ), modelDocument.selection );

expect( spy.args[ 0 ][ 1 ] ).to.deep.equal( {
batch,
selection: modelDocument.selection,
content
} );
expect( getData( modelDocument ) ).to.equal( '<paragraph>foob[]ar</paragraph>' );
} );
} );

describe( 'deleteContent', () => {
it( 'should fire the deleteContent event', () => {
it( 'should be decorated', () => {
const spy = sinon.spy();
const batch = modelDocument.batch();

data.on( 'deleteContent', spy );

data.deleteContent( modelDocument.selection, batch );
data.deleteContent( modelDocument.selection );

const evtData = spy.args[ 0 ][ 1 ];
expect( spy.calledOnce ).to.be.true;
} );

expect( evtData.batch ).to.equal( batch );
expect( evtData.selection ).to.equal( modelDocument.selection );
it( 'should delete selected content', () => {
schema.registerItem( 'paragraph', '$block' );

setData( modelDocument, '<paragraph>fo[ob]ar</paragraph>' );

data.deleteContent( modelDocument.selection, modelDocument.batch() );

expect( getData( modelDocument ) ).to.equal( '<paragraph>fo[]ar</paragraph>' );
} );
} );

describe( 'modifySelection', () => {
it( 'should fire the deleteContent event', () => {
it( 'should be decorated', () => {
schema.registerItem( 'paragraph', '$block' );
setData( modelDocument, '<paragraph>fo[ob]ar</paragraph>' );

const spy = sinon.spy();
const opts = { direction: 'backward' };

data.on( 'modifySelection', spy );

data.modifySelection( modelDocument.selection, opts );
data.modifySelection( modelDocument.selection );

const evtData = spy.args[ 0 ][ 1 ];
expect( spy.calledOnce ).to.be.true;
} );

expect( evtData.selection ).to.equal( modelDocument.selection );
expect( evtData.options ).to.equal( opts );
it( 'should modify a selection', () => {
schema.registerItem( 'paragraph', '$block' );

setData( modelDocument, '<paragraph>fo[ob]ar</paragraph>' );

data.modifySelection( modelDocument.selection, { direction: 'backward' } );

expect( getData( modelDocument ) ).to.equal( '<paragraph>fo[o]bar</paragraph>' );
} );
} );

describe( 'getSelectedContent', () => {
it( 'should fire the getSelectedContent event', () => {
it( 'should be decorated', () => {
const spy = sinon.spy();
const sel = new ModelSelection();

data.on( 'getSelectedContent', spy );

data.getSelectedContent( sel );

const evtData = spy.args[ 0 ][ 1 ];

expect( evtData.selection ).to.equal( sel );
expect( spy.calledOnce ).to.be.true;
} );

it( 'should return the evtData.content of the getSelectedContent event', () => {
const frag = new ModelDocumentFragment();
it( 'should return selected content', () => {
schema.registerItem( 'paragraph', '$block' );

data.on( 'getSelectedContent', ( evt, data ) => {
data.content = frag;
setData( modelDocument, '<paragraph>fo[ob]ar</paragraph>' );

evt.stop();
}, { priority: 'high' } );
const content = data.getSelectedContent( modelDocument.selection );

expect( data.getSelectedContent() ).to.equal( frag );
expect( stringify( content ) ).to.equal( 'ob' );
} );
} );
} );
Loading

0 comments on commit 157ca15

Please sign in to comment.