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

Commit

Permalink
Merge pull request #278 from ckeditor/t/ckeditor5/1524
Browse files Browse the repository at this point in the history
Fix: Insert missing caption for images that are nested in other elements. Closes ckeditor/ckeditor5#1524.
  • Loading branch information
scofalik authored Feb 18, 2019
2 parents f89fe04 + 99f114f commit 0e3a7c5
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 9 deletions.
29 changes: 20 additions & 9 deletions src/imagecaption/imagecaptionediting.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@

import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import { isImage } from '../image/utils';
import {
captionElementCreator,
getCaptionFromImage,
matchImageCaption
} from './utils';
import { captionElementCreator, getCaptionFromImage, matchImageCaption } from './utils';

/**
* The image caption engine plugin.
Expand Down Expand Up @@ -182,17 +178,32 @@ export default class ImageCaptionEditing extends Plugin {
const model = this.editor.model;
const changes = model.document.differ.getChanges();

const imagesWithoutCaption = [];

for ( const entry of changes ) {
if ( entry.type == 'insert' && entry.name == 'image' ) {
if ( entry.type == 'insert' && entry.name != '$text' ) {
const item = entry.position.nodeAfter;

if ( !getCaptionFromImage( item ) ) {
writer.appendElement( 'caption', item );
if ( item.is( 'image' ) && !getCaptionFromImage( item ) ) {
imagesWithoutCaption.push( item );
}

return true;
// Check elements with children for nested images.
if ( !item.is( 'image' ) && item.childCount ) {
for ( const nestedItem of model.createRangeIn( item ).getItems() ) {
if ( nestedItem.is( 'image' ) && !getCaptionFromImage( nestedItem ) ) {
imagesWithoutCaption.push( nestedItem );
}
}
}
}
}

for ( const image of imagesWithoutCaption ) {
writer.appendElement( 'caption', image );
}

return !!imagesWithoutCaption.length;
}
}

Expand Down
81 changes: 81 additions & 0 deletions tests/imagecaption/imagecaptionediting.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,66 @@ describe( 'ImageCaptionEditing', () => {
);
} );

it( 'should add caption element if image does not have it (image is nested in inserted element)', () => {
model.change( writer => {
model.schema.register( 'table', { allowWhere: '$block', isLimit: true, isObject: true, isBlock: true } );
model.schema.register( 'tableRow', { allowIn: 'table', isLimit: true } );
model.schema.register( 'tableCell', { allowIn: 'tableRow', isLimit: true } );
model.schema.extend( '$block', { allowIn: 'tableCell' } );
editor.conversion.for( 'downcast' ).elementToElement( { model: 'table', view: 'table' } );
editor.conversion.for( 'downcast' ).elementToElement( { model: 'tableRow', view: 'tr' } );
editor.conversion.for( 'downcast' ).elementToElement( { model: 'tableCell', view: 'td' } );

const table = writer.createElement( 'table' );
const tableRow = writer.createElement( 'tableRow' );
const tableCell1 = writer.createElement( 'tableCell' );
const tableCell2 = writer.createElement( 'tableCell' );
const image1 = writer.createElement( 'image', { src: '', alt: '' } );
const image2 = writer.createElement( 'image', { src: '', alt: '' } );

writer.insert( tableRow, table );
writer.insert( tableCell1, tableRow );
writer.insert( tableCell2, tableRow );
writer.insert( image1, tableCell1 );
writer.insert( image2, tableCell2 );
writer.insert( table, doc.getRoot() );
} );

expect( getModelData( model ) ).to.equal(
'[<table>' +
'<tableRow>' +
'<tableCell><image alt="" src=""><caption></caption></image></tableCell>' +
'<tableCell><image alt="" src=""><caption></caption></image></tableCell>' +
'</tableRow>' +
'</table>]' +
'<paragraph></paragraph>'
);

expect( getViewData( view ) ).to.equal(
'[<table>' +
'<tr>' +
'<td>' +
'<figure class="ck-widget image" contenteditable="false">' +
'<img alt="" src=""></img>' +
'<figcaption class="ck-editor__editable ck-editor__nested-editable ck-hidden ck-placeholder" ' +
'contenteditable="true" data-placeholder="Enter image caption">' +
'</figcaption>' +
'</figure>' +
'</td>' +
'<td>' +
'<figure class="ck-widget image" contenteditable="false">' +
'<img alt="" src=""></img>' +
'<figcaption class="ck-editor__editable ck-editor__nested-editable ck-hidden ck-placeholder" ' +
'contenteditable="true" data-placeholder="Enter image caption">' +
'</figcaption>' +
'</figure>' +
'</td>' +
'</tr>' +
'</table>]' +
'<p></p>'
);
} );

it( 'should not add caption element if image already have it', () => {
model.change( writer => {
const caption = writer.createElement( 'caption' );
Expand Down Expand Up @@ -318,6 +378,27 @@ describe( 'ImageCaptionEditing', () => {
'<image alt="alt text" src=""><caption>foo bar</caption></image>'
);
} );

it( 'should do nothing on $text insert', () => {
setModelData( model, '<image src=""><caption>foo bar</caption></image><paragraph>[]</paragraph>' );

const paragraph = doc.getRoot().getChild( 1 );

// Simulate typing behavior - second input will generate input change without entry.item in change entry.
const batch = model.createBatch();

model.enqueueChange( batch, writer => {
writer.insertText( 'f', paragraph, 0 );
} );

model.enqueueChange( batch, writer => {
writer.insertText( 'oo', paragraph, 1 );
} );

expect( getModelData( model, { withoutSelection: true } ) ).to.equal(
'<image src=""><caption>foo bar</caption></image><paragraph>foo</paragraph>'
);
} );
} );

describe( 'editing view', () => {
Expand Down

0 comments on commit 0e3a7c5

Please sign in to comment.