|
@@ -9,6 +9,7 @@
|
|
|
|
|
|
|
|
import ModelElement from '@ckeditor/ckeditor5-engine/src/model/element';
|
|
import ModelElement from '@ckeditor/ckeditor5-engine/src/model/element';
|
|
|
import ModelPosition from '@ckeditor/ckeditor5-engine/src/model/position';
|
|
import ModelPosition from '@ckeditor/ckeditor5-engine/src/model/position';
|
|
|
|
|
+import ModelRange from '@ckeditor/ckeditor5-engine/src/model/range';
|
|
|
|
|
|
|
|
import ViewContainerElement from '@ckeditor/ckeditor5-engine/src/view/containerelement';
|
|
import ViewContainerElement from '@ckeditor/ckeditor5-engine/src/view/containerelement';
|
|
|
import ViewPosition from '@ckeditor/ckeditor5-engine/src/view/position';
|
|
import ViewPosition from '@ckeditor/ckeditor5-engine/src/view/position';
|
|
@@ -341,7 +342,7 @@ export function modelViewMergeAfter( evt, data, conversionApi ) {
|
|
|
*
|
|
*
|
|
|
* To set correct values of the `type` and `indent` attributes the converter:
|
|
* To set correct values of the `type` and `indent` attributes the converter:
|
|
|
* * checks `<li>`'s parent,
|
|
* * checks `<li>`'s parent,
|
|
|
- * * passes the `data.indent` value when `<li>`'s sub-items are converted.
|
|
|
|
|
|
|
+ * * stores and increases the `conversionApi.data.indent` value when `<li>`'s sub-items are converted.
|
|
|
*
|
|
*
|
|
|
* @see module:engine/conversion/viewconversiondispatcher~ViewConversionDispatcher#event:element
|
|
* @see module:engine/conversion/viewconversiondispatcher~ViewConversionDispatcher#event:element
|
|
|
* @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.
|
|
* @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.
|
|
@@ -352,58 +353,44 @@ export function modelViewMergeAfter( evt, data, conversionApi ) {
|
|
|
export function viewModelConverter( evt, data, consumable, conversionApi ) {
|
|
export function viewModelConverter( evt, data, consumable, conversionApi ) {
|
|
|
if ( consumable.consume( data.input, { name: true } ) ) {
|
|
if ( consumable.consume( data.input, { name: true } ) ) {
|
|
|
const writer = conversionApi.writer;
|
|
const writer = conversionApi.writer;
|
|
|
|
|
+ const conversionData = this.conversionApi.data;
|
|
|
|
|
|
|
|
// 1. Create `listItem` model element.
|
|
// 1. Create `listItem` model element.
|
|
|
const listItem = writer.createElement( 'listItem' );
|
|
const listItem = writer.createElement( 'listItem' );
|
|
|
|
|
|
|
|
// 2. Handle `listItem` model element attributes.
|
|
// 2. Handle `listItem` model element attributes.
|
|
|
- data.indent = data.indent ? data.indent : 0;
|
|
|
|
|
- writer.setAttribute( 'indent', data.indent, listItem );
|
|
|
|
|
|
|
+ conversionData.indent = conversionData.indent || 0;
|
|
|
|
|
+ writer.setAttribute( 'indent', conversionData.indent, listItem );
|
|
|
|
|
|
|
|
// Set 'bulleted' as default. If this item is pasted into a context,
|
|
// Set 'bulleted' as default. If this item is pasted into a context,
|
|
|
const type = data.input.parent && data.input.parent.name == 'ol' ? 'numbered' : 'bulleted';
|
|
const type = data.input.parent && data.input.parent.name == 'ol' ? 'numbered' : 'bulleted';
|
|
|
writer.setAttribute( 'type', type, listItem );
|
|
writer.setAttribute( 'type', type, listItem );
|
|
|
|
|
|
|
|
- let alteredContext = false;
|
|
|
|
|
-
|
|
|
|
|
- // See https://github.com/ckeditor/ckeditor5-list/issues/87
|
|
|
|
|
- if ( data.context[ data.context.length - 1 ].name != 'listItem' ) {
|
|
|
|
|
- // 3. Handle `<li>` children.
|
|
|
|
|
- data.context.push( listItem );
|
|
|
|
|
- alteredContext = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
// `listItem`s created recursively should have bigger indent.
|
|
// `listItem`s created recursively should have bigger indent.
|
|
|
- data.indent++;
|
|
|
|
|
|
|
+ conversionData.indent++;
|
|
|
|
|
|
|
|
- // `listItem`s will be kept in flat structure.
|
|
|
|
|
- const items = writer.createDocumentFragment();
|
|
|
|
|
- writer.append( listItem, items );
|
|
|
|
|
|
|
+ writer.insert( listItem, data.position );
|
|
|
|
|
+
|
|
|
|
|
+ // Remember position after list item.
|
|
|
|
|
+ let nextPosition = ModelPosition.createAfter( listItem );
|
|
|
|
|
|
|
|
// Check all children of the converted `<li>`.
|
|
// Check all children of the converted `<li>`.
|
|
|
// At this point we assume there are no "whitespace" view text nodes in view list, between view list items.
|
|
// At this point we assume there are no "whitespace" view text nodes in view list, between view list items.
|
|
|
// This should be handled by `<ul>` and `<ol>` converters.
|
|
// This should be handled by `<ul>` and `<ol>` converters.
|
|
|
for ( const child of data.input.getChildren() ) {
|
|
for ( const child of data.input.getChildren() ) {
|
|
|
- // Let's convert the child.
|
|
|
|
|
- const converted = conversionApi.convertItem( child, consumable, data );
|
|
|
|
|
-
|
|
|
|
|
- // If this is a view list element, we will convert it and concat the result (`listItem` model elements)
|
|
|
|
|
- // with already gathered results (in `items` array). `converted` should be a `ModelDocumentFragment`.
|
|
|
|
|
|
|
+ // If this is a view list element, we will convert it after last `listItem` model element.
|
|
|
if ( child.name == 'ul' || child.name == 'ol' ) {
|
|
if ( child.name == 'ul' || child.name == 'ol' ) {
|
|
|
- writer.append( converted, items );
|
|
|
|
|
|
|
+ nextPosition = conversionApi.convertItem( child, consumable, nextPosition ).end;
|
|
|
}
|
|
}
|
|
|
// If it was not a list it was a "regular" list item content. Just append it to `listItem`.
|
|
// If it was not a list it was a "regular" list item content. Just append it to `listItem`.
|
|
|
else {
|
|
else {
|
|
|
- writer.append( converted, listItem );
|
|
|
|
|
|
|
+ conversionApi.convertItem( child, consumable, ModelPosition.createAt( listItem, 'end' ) );
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- data.indent--;
|
|
|
|
|
- if ( alteredContext ) {
|
|
|
|
|
- data.context.pop();
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ conversionData.indent--;
|
|
|
|
|
|
|
|
- data.output = items;
|
|
|
|
|
|
|
+ data.output = new ModelRange( data.position, nextPosition );
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -571,12 +558,18 @@ export function viewToModelPosition( evt, data ) {
|
|
|
/**
|
|
/**
|
|
|
* Post-fixer that reacts to changes on document and fixes incorrect model states.
|
|
* Post-fixer that reacts to changes on document and fixes incorrect model states.
|
|
|
*
|
|
*
|
|
|
- * Example:
|
|
|
|
|
|
|
+ * In an example below, there is a correct list structure.
|
|
|
|
|
+ * Then the middle element will be removed so the list structure will become incorrect:
|
|
|
*
|
|
*
|
|
|
* <listItem type="bulleted" indent=0>Item 1</listItem>
|
|
* <listItem type="bulleted" indent=0>Item 1</listItem>
|
|
|
* <listItem type="bulleted" indent=1>Item 2</listItem> <--- this is removed.
|
|
* <listItem type="bulleted" indent=1>Item 2</listItem> <--- this is removed.
|
|
|
* <listItem type="bulleted" indent=2>Item 3</listItem>
|
|
* <listItem type="bulleted" indent=2>Item 3</listItem>
|
|
|
*
|
|
*
|
|
|
|
|
+ * List structure after the middle element removed:
|
|
|
|
|
+ *
|
|
|
|
|
+ * <listItem type="bulleted" indent=0>Item 1</listItem>
|
|
|
|
|
+ * <listItem type="bulleted" indent=2>Item 3</listItem>
|
|
|
|
|
+ *
|
|
|
* Should become:
|
|
* Should become:
|
|
|
*
|
|
*
|
|
|
* <listItem type="bulleted" indent=0>Item 1</listItem>
|
|
* <listItem type="bulleted" indent=0>Item 1</listItem>
|