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

Commit

Permalink
Merge e4460db into 9306c22
Browse files Browse the repository at this point in the history
  • Loading branch information
jodator committed Jan 2, 2019
2 parents 9306c22 + e4460db commit 6b65bf9
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 86 deletions.
80 changes: 43 additions & 37 deletions src/conversion/downcasthelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -490,30 +490,33 @@ export function wrap( elementCreator ) {
};
}

// Function factory that creates a converter which converts node insertion changes from the model to the view.
// The function passed will be provided with all the parameters of the dispatcher's
// {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert` event}.
// It is expected that the function returns an {@link module:engine/view/element~Element}.
// The result of the function will be inserted into the view.
//
// The converter automatically consumes the corresponding value from the consumables list, stops the event (see
// {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}) and binds the model and view elements.
//
// downcastDispatcher.on(
// 'insert:myElem',
// insertElement( ( modelItem, viewWriter ) => {
// const text = viewWriter.createText( 'myText' );
// const myElem = viewWriter.createElement( 'myElem', { myAttr: 'my-' + modelItem.getAttribute( 'myAttr' ) }, text );
//
// // Do something fancy with `myElem` using `modelItem` or other parameters.
//
// return myElem;
// }
// ) );
//
// @param {Function} elementCreator Function returning a view element, which will be inserted.
// @returns {Function} Insert element event converter.
function insertElement( elementCreator ) {
/**
* Function factory that creates a converter which converts node insertion changes from the model to the view.
* The function passed will be provided with all the parameters of the dispatcher's
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert` event}.
* It is expected that the function returns an {@link module:engine/view/element~Element}.
* The result of the function will be inserted into the view.
*
* The converter automatically consumes the corresponding value from the consumables list, stops the event (see
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}) and binds the model and view elements.
*
* downcastDispatcher.on(
* 'insert:myElem',
* insertElement( ( modelItem, viewWriter ) => {
* const text = viewWriter.createText( 'myText' );
* const myElem = viewWriter.createElement( 'myElem', { myAttr: 'my-' + modelItem.getAttribute( 'myAttr' ) }, text );
*
* // Do something fancy with `myElem` using `modelItem` or other parameters.
*
* return myElem;
* }
* ) );
*
* @protected
* @param {Function} elementCreator Function returning a view element, which will be inserted.
* @returns {Function} Insert element event converter.
*/
export function insertElement( elementCreator ) {
return ( evt, data, conversionApi ) => {
const viewElement = elementCreator( data.item, conversionApi.writer );

Expand All @@ -532,19 +535,22 @@ function insertElement( elementCreator ) {
};
}

// Function factory that creates a converter which converts marker adding change to the
// {@link module:engine/view/uielement~UIElement view UI element}.
//
// The view UI element that will be added to the view depends on the passed parameter. See {@link ~insertElement}.
// In case of a non-collapsed range, the UI element will not wrap nodes but separate elements will be placed at the beginning
// and at the end of the range.
//
// This converter binds created UI elements with the marker name using {@link module:engine/conversion/mapper~Mapper#bindElementToMarker}.
//
// @param {module:engine/view/uielement~UIElement|Function} elementCreator A view UI element or a function returning the view element
// that will be inserted.
// @returns {Function} Insert element event converter.
function insertUIElement( elementCreator ) {
/**
* Function factory that creates a converter which converts marker adding change to the
* {@link module:engine/view/uielement~UIElement view UI element}.
*
* The view UI element that will be added to the view depends on the passed parameter. See {@link ~insertElement}.
* In case of a non-collapsed range, the UI element will not wrap nodes but separate elements will be placed at the beginning
* and at the end of the range.
*
* This converter binds created UI elements with the marker name using {@link module:engine/conversion/mapper~Mapper#bindElementToMarker}.
*
* @protected
* @param {module:engine/view/uielement~UIElement|Function} elementCreator A view UI element or a function returning the view element
* that will be inserted.
* @returns {Function} Insert element event converter.
*/
export function insertUIElement( elementCreator ) {
return ( evt, data, conversionApi ) => {
// Create two view elements. One will be inserted at the beginning of marker, one at the end.
// If marker is collapsed, only "opening" element will be inserted.
Expand Down
59 changes: 10 additions & 49 deletions src/dev-utils/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
convertRangeSelection,
convertCollapsedSelection,
} from '../conversion/downcast-selection-converters';
import { insertText, wrap } from '../conversion/downcasthelpers';
import { insertElement, insertText, insertUIElement, wrap } from '../conversion/downcasthelpers';

import { isPlainObject } from 'lodash-es';
import toMap from '@ckeditor/ckeditor5-utils/src/tomap';
Expand Down Expand Up @@ -225,59 +225,20 @@ export function stringify( node, selectionOrPositionOrRange = null, markers = nu
converter( evt, data, conversionApi );
}
} );
downcastDispatcher.on( 'insert', ( evt, data, conversionApi ) => {
const attributes = convertAttributes( data.item.getAttributes(), stringifyAttributeValue );
const viewElement = new ViewContainerElement( data.item.name, attributes );
downcastDispatcher.on( 'insert', insertElement( modelItem => {
// Stringify object types values for properly display as an output string.
const attributes = convertAttributes( modelItem.getAttributes(), stringifyAttributeValue );

if ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {
return;
}

const viewPosition = conversionApi.mapper.toViewPosition( data.range.start );

conversionApi.mapper.bindElements( data.item, viewElement );
conversionApi.writer.insert( viewPosition, viewElement );
} );
return new ViewContainerElement( modelItem.name, attributes );
} ) );

downcastDispatcher.on( 'selection', convertRangeSelection() );
downcastDispatcher.on( 'selection', convertCollapsedSelection() );
downcastDispatcher.on( 'addMarker', ( evt, data, conversionApi ) => {
const elementCreator = ( data, writer ) => {
const name = data.markerName + ':' + ( data.isOpening ? 'start' : 'end' );

return writer.createUIElement( name );
};

// Create two view elements. One will be inserted at the beginning of marker, one at the end.
// If marker is collapsed, only "opening" element will be inserted.
data.isOpening = true;
const viewStartElement = elementCreator( data, conversionApi.writer );

data.isOpening = false;
const viewEndElement = elementCreator( data, conversionApi.writer );

const markerRange = data.markerRange;
downcastDispatcher.on( 'addMarker', insertUIElement( ( data, writer ) => {
const name = data.markerName + ':' + ( data.isOpening ? 'start' : 'end' );

// If marker's range is not collapsed - consume all items inside.
for ( const value of markerRange ) {
conversionApi.consumable.consume( value.item, evt.name );
}

const mapper = conversionApi.mapper;
const viewWriter = conversionApi.writer;

// Add "opening" element.
viewWriter.insert( mapper.toViewPosition( markerRange.start ), viewStartElement );
conversionApi.mapper.bindElementToMarker( viewStartElement, data.markerName );

// Add "closing" element only if range is not collapsed.
if ( !markerRange.isCollapsed ) {
viewWriter.insert( mapper.toViewPosition( markerRange.end ), viewEndElement );
conversionApi.mapper.bindElementToMarker( viewEndElement, data.markerName );
}

evt.stop();
} );
return writer.createUIElement( name );
} ) );

// Convert model to view.
const writer = view._writer;
Expand Down

0 comments on commit 6b65bf9

Please sign in to comment.