converters.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /**
  2. * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import { viewFigureToModel, createImageAttributeConverter } from '../../src/image/converters';
  6. import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
  7. import { createImageViewElement } from '../../src/image/imageengine';
  8. import { toImageWidget } from '../../src/image/utils';
  9. import buildModelConverter from '@ckeditor/ckeditor5-engine/src/conversion/buildmodelconverter';
  10. import buildViewConverter from '@ckeditor/ckeditor5-engine/src/conversion/buildviewconverter';
  11. import ModelElement from '@ckeditor/ckeditor5-engine/src/model/element';
  12. import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
  13. import { setData as setModelData, getData as getModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  14. describe( 'Image converters', () => {
  15. let editor, document, viewDocument;
  16. beforeEach( () => {
  17. return VirtualTestEditor.create()
  18. .then( newEditor => {
  19. editor = newEditor;
  20. document = editor.document;
  21. viewDocument = editor.editing.view;
  22. const schema = document.schema;
  23. schema.registerItem( 'image' );
  24. schema.requireAttributes( 'image', [ 'src' ] );
  25. schema.allow( { name: 'image', attributes: [ 'alt', 'src' ], inside: '$root' } );
  26. schema.objects.add( 'image' );
  27. buildModelConverter().for( editor.editing.modelToView )
  28. .fromElement( 'image' )
  29. .toElement( () => toImageWidget( createImageViewElement() ) );
  30. createImageAttributeConverter( [ editor.editing.modelToView ], 'src' );
  31. createImageAttributeConverter( [ editor.editing.modelToView ], 'alt' );
  32. } );
  33. } );
  34. describe( 'viewFigureToModel', () => {
  35. function expectModel( model ) {
  36. expect( getModelData( document, { withoutSelection: true } ) ).to.equal( model );
  37. }
  38. let dispatcher, schema, imgConverterCalled;
  39. beforeEach( () => {
  40. imgConverterCalled = false;
  41. schema = document.schema;
  42. schema.allow( { name: '$text', inside: 'image' } );
  43. dispatcher = editor.data.viewToModel;
  44. dispatcher.on( 'element:figure', viewFigureToModel() );
  45. dispatcher.on( 'element:img', ( evt, data, consumable ) => {
  46. if ( consumable.consume( data.input, { name: true, attribute: 'src' } ) ) {
  47. data.output = new ModelElement( 'image', { src: data.input.getAttribute( 'src' ) } );
  48. imgConverterCalled = true;
  49. }
  50. } );
  51. } );
  52. it( 'should find img element among children and convert it using already defined converters', () => {
  53. editor.setData( '<figure class="image"><img src="foo.png" /></figure>' );
  54. expectModel( '<image src="foo.png"></image>' );
  55. expect( imgConverterCalled ).to.be.true;
  56. } );
  57. it( 'should convert non-img children in image context and append them to model image element', () => {
  58. buildViewConverter().for( editor.data.viewToModel ).fromElement( 'foo' ).toElement( 'foo' );
  59. buildViewConverter().for( editor.data.viewToModel ).fromElement( 'bar' ).toElement( 'bar' );
  60. schema.registerItem( 'foo' );
  61. schema.registerItem( 'bar' );
  62. schema.allow( { name: 'foo', inside: 'image' } );
  63. editor.setData( '<figure class="image">x<img src="foo.png" />y<foo></foo><bar></bar></figure>' );
  64. // Element bar not converted because schema does not allow it.
  65. expectModel( '<image src="foo.png">xy<foo></foo></image>' );
  66. } );
  67. it( 'should be possible to overwrite', () => {
  68. dispatcher.on( 'element:figure', ( evt, data, consumable ) => {
  69. consumable.consume( data.input, { name: true } );
  70. consumable.consume( data.input.getChild( 0 ), { name: true } );
  71. data.output = new ModelElement( 'myImage', { data: { src: data.input.getChild( 0 ).getAttribute( 'src' ) } } );
  72. }, { priority: 'high' } );
  73. editor.setData( '<figure class="image"><img src="foo.png" />xyz</figure>' );
  74. expectModel( '<myImage data="{"src":"foo.png"}"></myImage>' );
  75. } );
  76. // Test exactly what figure converter does, which is putting it's children element to image element.
  77. // If this has not been done, it means that figure converter was not used.
  78. it( 'should not convert if figure do not have class="image" attribute', () => {
  79. editor.setData( '<figure><img src="foo.png" />xyz</figure>' );
  80. // Default image converter will be fired.
  81. expectModel( '<image src="foo.png"></image>' );
  82. } );
  83. it( 'should not convert if there is no img element among children', () => {
  84. editor.setData( '<figure class="image">xyz</figure>' );
  85. // Figure converter outputs nothing and text is disallowed in root.
  86. expectModel( '' );
  87. } );
  88. it( 'should not convert if img element was not converted', () => {
  89. // Image element missing src attribute.
  90. editor.setData( '<figure class="image"><img alt="abc" />xyz</figure>' );
  91. // Figure converter outputs nothing and text is disallowed in root.
  92. expectModel( '' );
  93. } );
  94. } );
  95. describe( 'modelToViewAttributeConverter', () => {
  96. it( 'should convert adding attribute to image', () => {
  97. setModelData( document, '<image src=""></image>' );
  98. const image = document.getRoot().getChild( 0 );
  99. document.enqueueChanges( () => {
  100. const batch = document.batch();
  101. batch.setAttribute( image, 'alt', 'foo bar' );
  102. } );
  103. expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
  104. '<figure class="image ck-widget" contenteditable="false"><img alt="foo bar" src=""></img></figure>'
  105. );
  106. } );
  107. it( 'should convert removing attribute from image', () => {
  108. setModelData( document, '<image src="" alt="foo bar"></image>' );
  109. const image = document.getRoot().getChild( 0 );
  110. document.enqueueChanges( () => {
  111. const batch = document.batch();
  112. batch.removeAttribute( image, 'alt' );
  113. } );
  114. expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
  115. '<figure class="image ck-widget" contenteditable="false"><img src=""></img></figure>'
  116. );
  117. } );
  118. it( 'should convert change of attribute image', () => {
  119. setModelData( document, '<image src="" alt="foo bar"></image>' );
  120. const image = document.getRoot().getChild( 0 );
  121. document.enqueueChanges( () => {
  122. const batch = document.batch();
  123. batch.setAttribute( image, 'alt', 'baz quix' );
  124. } );
  125. expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
  126. '<figure class="image ck-widget" contenteditable="false"><img alt="baz quix" src=""></img></figure>'
  127. );
  128. } );
  129. it( 'should not change attribute if change is already consumed', () => {
  130. editor.editing.modelToView.on( `changeAttribute:alt:image`, ( evt, data, consumable ) => {
  131. consumable.consume( data.item, 'changeAttribute:alt' );
  132. }, { priority: 'high' } );
  133. setModelData( document, '<image src="" alt="foo bar"></image>' );
  134. const image = document.getRoot().getChild( 0 );
  135. document.enqueueChanges( () => {
  136. const batch = document.batch();
  137. batch.setAttribute( image, 'alt', 'baz quix' );
  138. } );
  139. expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
  140. '<figure class="image ck-widget" contenteditable="false"><img alt="foo bar" src=""></img></figure>'
  141. );
  142. } );
  143. } );
  144. } );