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

Commit

Permalink
Merge 37a981f into 1c7ef68
Browse files Browse the repository at this point in the history
  • Loading branch information
jodator committed Jan 2, 2019
2 parents 1c7ef68 + 37a981f commit d59e9f7
Show file tree
Hide file tree
Showing 11 changed files with 906 additions and 984 deletions.
5 changes: 2 additions & 3 deletions src/controller/editingcontroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@ import RootEditableElement from '../view/rooteditableelement';
import View from '../view/view';
import Mapper from '../conversion/mapper';
import DowncastDispatcher from '../conversion/downcastdispatcher';
import { insertText, remove } from '../conversion/downcasthelpers';
import { convertSelectionChange } from '../conversion/upcast-selection-converters';
import { clearAttributes, convertCollapsedSelection, convertRangeSelection } from '../conversion/downcast-selection-converters';
import { clearAttributes, convertCollapsedSelection, convertRangeSelection, insertText, remove } from '../conversion/downcasthelpers';

import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
import mix from '@ckeditor/ckeditor5-utils/src/mix';
import { convertSelectionChange } from '../conversion/upcasthelpers';

/**
* Controller for the editing pipeline. The editing pipeline controls {@link ~EditingController#model model} rendering,
Expand Down
129 changes: 0 additions & 129 deletions src/conversion/downcast-selection-converters.js

This file was deleted.

117 changes: 117 additions & 0 deletions src/conversion/downcasthelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,123 @@ export function createViewElementFromHighlightDescriptor( descriptor ) {
return viewElement;
}

/**
* Function factory that creates a converter which converts a non-collapsed {@link module:engine/model/selection~Selection model selection}
* to a {@link module:engine/view/documentselection~DocumentSelection view selection}. The converter consumes appropriate
* value from the `consumable` object and maps model positions from the selection to view positions.
*
* modelDispatcher.on( 'selection', convertRangeSelection() );
*
* @returns {Function} Selection converter.
*/
export function convertRangeSelection() {
return ( evt, data, conversionApi ) => {
const selection = data.selection;

if ( selection.isCollapsed ) {
return;
}

if ( !conversionApi.consumable.consume( selection, 'selection' ) ) {
return;
}

const viewRanges = [];

for ( const range of selection.getRanges() ) {
const viewRange = conversionApi.mapper.toViewRange( range );
viewRanges.push( viewRange );
}

conversionApi.writer.setSelection( viewRanges, { backward: selection.isBackward } );
};
}

/**
* Function factory that creates a converter which converts a collapsed {@link module:engine/model/selection~Selection model selection} to
* a {@link module:engine/view/documentselection~DocumentSelection view selection}. The converter consumes appropriate
* value from the `consumable` object, maps the model selection position to the view position and breaks
* {@link module:engine/view/attributeelement~AttributeElement attribute elements} at the selection position.
*
* modelDispatcher.on( 'selection', convertCollapsedSelection() );
*
* An example of the view state before and after converting the collapsed selection:
*
* <p><strong>f^oo<strong>bar</p>
* -> <p><strong>f</strong>^<strong>oo</strong>bar</p>
*
* By breaking attribute elements like `<strong>`, the selection is in a correct element. Then, when the selection attribute is
* converted, broken attributes might be merged again, or the position where the selection is may be wrapped
* with different, appropriate attribute elements.
*
* See also {@link module:engine/conversion/downcasthelpers~clearAttributes} which does a clean-up
* by merging attributes.
*
* @returns {Function} Selection converter.
*/
export function convertCollapsedSelection() {
return ( evt, data, conversionApi ) => {
const selection = data.selection;

if ( !selection.isCollapsed ) {
return;
}

if ( !conversionApi.consumable.consume( selection, 'selection' ) ) {
return;
}

const viewWriter = conversionApi.writer;
const modelPosition = selection.getFirstPosition();
const viewPosition = conversionApi.mapper.toViewPosition( modelPosition );
const brokenPosition = viewWriter.breakAttributes( viewPosition );

viewWriter.setSelection( brokenPosition );
};
}

/**
* Function factory that creates a converter which clears artifacts after the previous
* {@link module:engine/model/selection~Selection model selection} conversion. It removes all empty
* {@link module:engine/view/attributeelement~AttributeElement view attribute elements} and merges sibling attributes at all start and end
* positions of all ranges.
*
* <p><strong>^</strong></p>
* -> <p>^</p>
*
* <p><strong>foo</strong>^<strong>bar</strong>bar</p>
* -> <p><strong>foo^bar<strong>bar</p>
*
* <p><strong>foo</strong><em>^</em><strong>bar</strong>bar</p>
* -> <p><strong>foo^bar<strong>bar</p>
*
* This listener should be assigned before any converter for the new selection:
*
* modelDispatcher.on( 'selection', clearAttributes() );
*
* See {@link module:engine/conversion/downcasthelpers~convertCollapsedSelection}
* which does the opposite by breaking attributes in the selection position.
*
* @returns {Function} Selection converter.
*/
export function clearAttributes() {
return ( evt, data, conversionApi ) => {
const viewWriter = conversionApi.writer;
const viewSelection = viewWriter.document.selection;

for ( const range of viewSelection.getRanges() ) {
// 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 ) {
conversionApi.writer.mergeAttributes( range.start );
}
}
}
viewWriter.setSelection( null );
};
}

/**
* Function factory that creates a converter which converts set/change/remove attribute changes from the model to the view.
* It can also be used to convert selection attributes. In that case, an empty attribute element will be created and the
Expand Down
2 changes: 1 addition & 1 deletion src/conversion/modelconsumable.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import TextProxy from '../model/textproxy';
* {@link module:engine/conversion/modelconsumable~ModelConsumable#add add method} directly.
* However, it is important to understand how consumable values can be
* {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed}.
* See {@link module:engine/conversion/downcast-selection-converters default downcast converters} for more information.
* See {@link module:engine/conversion/downcasthelpers default downcast converters} for more information.
*
* Keep in mind, that one conversion event may have multiple callbacks (converters) attached to it. Each of those is
* able to convert one or more parts of the model. However, when one of those callbacks actually converts
Expand Down
48 changes: 0 additions & 48 deletions src/conversion/upcast-selection-converters.js

This file was deleted.

36 changes: 36 additions & 0 deletions src/conversion/upcasthelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import ModelRange from '../model/range';
import { ConversionHelpers } from './conversion';

import { cloneDeep } from 'lodash-es';
import ModelSelection from '../model/selection';

/**
* Contains {@link module:engine/view/view view} to {@link module:engine/model/model model} converters for
Expand Down Expand Up @@ -352,6 +353,41 @@ export function convertText() {
};
}

/**
* Function factory, creates a callback function which converts a {@link module:engine/view/selection~Selection
* view selection} taken from the {@link module:engine/view/document~Document#event:selectionChange} event
* and sets in on the {@link module:engine/model/document~Document#selection model}.
*
* **Note**: because there is no view selection change dispatcher nor any other advanced view selection to model
* conversion mechanism, the callback should be set directly on view document.
*
* view.document.on( 'selectionChange', convertSelectionChange( modelDocument, mapper ) );
*
* @param {module:engine/model/model~Model} model Data model.
* @param {module:engine/conversion/mapper~Mapper} mapper Conversion mapper.
* @returns {Function} {@link module:engine/view/document~Document#event:selectionChange} callback function.
*/
export function convertSelectionChange( model, mapper ) {
return ( evt, data ) => {
const viewSelection = data.newSelection;
const modelSelection = new ModelSelection();

const ranges = [];

for ( const viewRange of viewSelection.getRanges() ) {
ranges.push( mapper.toModelRange( viewRange ) );
}

modelSelection.setTo( ranges, { backward: viewSelection.isBackward } );

if ( !modelSelection.isEqual( model.document.selection ) ) {
model.change( writer => {
writer.setSelection( modelSelection );
} );
}
};
}

// View element to model element conversion helper.
//
// See {@link ~UpcastHelpers#elementToElement `.elementToElement()` upcast helper} for examples.
Expand Down
9 changes: 6 additions & 3 deletions src/dev-utils/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@ import DowncastDispatcher from '../conversion/downcastdispatcher';
import UpcastDispatcher from '../conversion/upcastdispatcher';
import Mapper from '../conversion/mapper';
import {
convertRangeSelection,
convertCollapsedSelection,
} from '../conversion/downcast-selection-converters';
import { insertElement, insertText, insertUIElement, wrap } from '../conversion/downcasthelpers';
convertRangeSelection,
insertElement,
insertText,
insertUIElement,
wrap
} from '../conversion/downcasthelpers';

import { isPlainObject } from 'lodash-es';
import toMap from '@ckeditor/ckeditor5-utils/src/tomap';
Expand Down

0 comments on commit d59e9f7

Please sign in to comment.