@@ -20,7 +20,7 @@ import ViewText from '../../src/view/text';
2020import log from '@ckeditor/ckeditor5-utils/src/log' ;
2121import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils' ;
2222
23- import DowncastHelpers , { createViewElementFromHighlightDescriptor , wrap } from '../../src/conversion/downcasthelpers' ;
23+ import DowncastHelpers , { createViewElementFromHighlightDescriptor } from '../../src/conversion/downcasthelpers' ;
2424
2525import { stringify } from '../../src/dev-utils/view' ;
2626
@@ -107,6 +107,10 @@ describe( 'DowncastHelpers', () => {
107107 } ) ;
108108
109109 describe ( 'attributeToElement()' , ( ) => {
110+ beforeEach ( ( ) => {
111+ downcastHelpers . elementToElement ( { model : 'paragraph' , view : 'p' } ) ;
112+ } ) ;
113+
110114 it ( 'should be chainable' , ( ) => {
111115 expect ( downcastHelpers . attributeToElement ( { model : 'bold' , view : 'strong' } ) ) . to . equal ( downcastHelpers ) ;
112116 } ) ;
@@ -264,6 +268,143 @@ describe( 'DowncastHelpers', () => {
264268
265269 expect ( viewToString ( viewRoot ) ) . to . equal ( '<div></div>' ) ;
266270 } ) ;
271+
272+ it ( 'should convert insert/change/remove of attribute in model into wrapping element in a view' , ( ) => {
273+ const modelElement = new ModelElement ( 'paragraph' , null , new ModelText ( 'foobar' , { bold : true } ) ) ;
274+
275+ downcastHelpers . attributeToElement ( {
276+ model : 'bold' ,
277+ view : ( modelAttributeValue , viewWriter ) => viewWriter . createAttributeElement ( 'b' )
278+ } ) ;
279+
280+ model . change ( writer => {
281+ writer . insert ( modelElement , modelRootStart ) ;
282+ } ) ;
283+
284+ expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p><b>foobar</b></p></div>' ) ;
285+
286+ model . change ( writer => {
287+ writer . removeAttribute ( 'bold' , writer . createRangeIn ( modelElement ) ) ;
288+ } ) ;
289+
290+ expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p>foobar</p></div>' ) ;
291+ } ) ;
292+
293+ it ( 'should convert insert/remove of attribute in model with wrapping element generating function as a parameter' , ( ) => {
294+ const modelElement = new ModelElement ( 'paragraph' , null , new ModelText ( 'foobar' , { style : 'bold' } ) ) ;
295+
296+ downcastHelpers . attributeToElement ( {
297+ model : 'style' ,
298+ view : ( modelAttributeValue , viewWriter ) => {
299+ if ( modelAttributeValue == 'bold' ) {
300+ return viewWriter . createAttributeElement ( 'b' ) ;
301+ }
302+ }
303+ } ) ;
304+
305+ model . change ( writer => {
306+ writer . insert ( modelElement , modelRootStart ) ;
307+ } ) ;
308+
309+ expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p><b>foobar</b></p></div>' ) ;
310+
311+ model . change ( writer => {
312+ writer . removeAttribute ( 'style' , writer . createRangeIn ( modelElement ) ) ;
313+ } ) ;
314+
315+ expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p>foobar</p></div>' ) ;
316+ } ) ;
317+
318+ it ( 'should update range on re-wrapping attribute (#475)' , ( ) => {
319+ const modelElement = new ModelElement ( 'paragraph' , null , [
320+ new ModelText ( 'x' ) ,
321+ new ModelText ( 'foo' , { link : 'http://foo.com' } ) ,
322+ new ModelText ( 'x' )
323+ ] ) ;
324+
325+ downcastHelpers . attributeToElement ( {
326+ model : 'link' ,
327+ view : ( modelAttributeValue , viewWriter ) => {
328+ return viewWriter . createAttributeElement ( 'a' , { href : modelAttributeValue } ) ;
329+ }
330+ } ) ;
331+
332+ model . change ( writer => {
333+ writer . insert ( modelElement , modelRootStart ) ;
334+ } ) ;
335+
336+ expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p>x<a href="http://foo.com">foo</a>x</p></div>' ) ;
337+
338+ // Set new attribute on old link but also on non-linked characters.
339+ model . change ( writer => {
340+ writer . setAttribute ( 'link' , 'http://foobar.com' , writer . createRangeIn ( modelElement ) ) ;
341+ } ) ;
342+
343+ expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p><a href="http://foobar.com">xfoox</a></p></div>' ) ;
344+ } ) ;
345+
346+ it ( 'should support unicode' , ( ) => {
347+ const modelElement = new ModelElement ( 'paragraph' , null , [ 'நி' , new ModelText ( 'லைக்' , { bold : true } ) , 'கு' ] ) ;
348+
349+ downcastHelpers . attributeToElement ( {
350+ model : 'bold' ,
351+ view : ( modelAttributeValue , viewWriter ) => viewWriter . createAttributeElement ( 'b' )
352+ } ) ;
353+
354+ model . change ( writer => {
355+ writer . insert ( modelElement , modelRootStart ) ;
356+ } ) ;
357+
358+ expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p>நி<b>லைக்</b>கு</p></div>' ) ;
359+
360+ model . change ( writer => {
361+ writer . removeAttribute ( 'bold' , writer . createRangeIn ( modelElement ) ) ;
362+ } ) ;
363+
364+ expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p>நிலைக்கு</p></div>' ) ;
365+ } ) ;
366+
367+ it ( 'should be possible to override ' , ( ) => {
368+ const modelElement = new ModelElement ( 'paragraph' , null , new ModelText ( 'foobar' , { bold : true } ) ) ;
369+
370+ downcastHelpers . attributeToElement ( {
371+ model : 'bold' ,
372+ view : ( modelAttributeValue , viewWriter ) => viewWriter . createAttributeElement ( 'b' )
373+ } ) ;
374+ downcastHelpers . attributeToElement ( {
375+ model : 'bold' ,
376+ view : ( modelAttributeValue , viewWriter ) => viewWriter . createAttributeElement ( 'strong' ) ,
377+ converterPriority : 'high'
378+ } ) ;
379+
380+ model . change ( writer => {
381+ writer . insert ( modelElement , modelRootStart ) ;
382+ } ) ;
383+
384+ expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p><strong>foobar</strong></p></div>' ) ;
385+ } ) ;
386+
387+ it ( 'should not convert and not consume if creator function returned null' , ( ) => {
388+ sinon . spy ( controller . downcastDispatcher , 'fire' ) ;
389+
390+ const modelElement = new ModelElement ( 'paragraph' , null , new ModelText ( 'foobar' , { italic : true } ) ) ;
391+
392+ downcastHelpers . attributeToElement ( {
393+ model : 'italic' ,
394+ view : ( ) => null
395+ } ) ;
396+
397+ const spy = sinon . spy ( ) ;
398+ controller . downcastDispatcher . on ( 'attribute:italic' , spy ) ;
399+
400+ model . change ( writer => {
401+ writer . insert ( modelElement , modelRootStart ) ;
402+ } ) ;
403+
404+ expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p>foobar</p></div>' ) ;
405+ expect ( controller . downcastDispatcher . fire . calledWith ( 'attribute:italic:$text' ) ) . to . be . true ;
406+ expect ( spy . called ) . to . be . true ;
407+ } ) ;
267408 } ) ;
268409
269410 describe ( 'attributeToAttribute()' , ( ) => {
@@ -1424,136 +1565,6 @@ describe( 'downcast-converters', () => {
14241565 } ) ;
14251566 } ) ;
14261567
1427- describe ( 'wrap' , ( ) => {
1428- it ( 'should convert insert/change/remove of attribute in model into wrapping element in a view' , ( ) => {
1429- const modelElement = new ModelElement ( 'paragraph' , null , new ModelText ( 'foobar' , { bold : true } ) ) ;
1430- const creator = ( modelAttributeValue , viewWriter ) => viewWriter . createAttributeElement ( 'b' ) ;
1431-
1432- dispatcher . on ( 'attribute:bold' , wrap ( creator ) ) ;
1433-
1434- model . change ( writer => {
1435- writer . insert ( modelElement , modelRootStart ) ;
1436- } ) ;
1437-
1438- expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p><b>foobar</b></p></div>' ) ;
1439-
1440- model . change ( writer => {
1441- writer . removeAttribute ( 'bold' , writer . createRangeIn ( modelElement ) ) ;
1442- } ) ;
1443-
1444- expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p>foobar</p></div>' ) ;
1445- } ) ;
1446-
1447- it ( 'should convert insert/remove of attribute in model with wrapping element generating function as a parameter' , ( ) => {
1448- const modelElement = new ModelElement ( 'paragraph' , null , new ModelText ( 'foobar' , { style : 'bold' } ) ) ;
1449-
1450- const elementGenerator = ( modelAttributeValue , viewWriter ) => {
1451- if ( modelAttributeValue == 'bold' ) {
1452- return viewWriter . createAttributeElement ( 'b' ) ;
1453- }
1454- } ;
1455-
1456- dispatcher . on ( 'attribute:style' , wrap ( elementGenerator ) ) ;
1457-
1458- model . change ( writer => {
1459- writer . insert ( modelElement , modelRootStart ) ;
1460- } ) ;
1461-
1462- expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p><b>foobar</b></p></div>' ) ;
1463-
1464- model . change ( writer => {
1465- writer . removeAttribute ( 'style' , writer . createRangeIn ( modelElement ) ) ;
1466- } ) ;
1467-
1468- expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p>foobar</p></div>' ) ;
1469- } ) ;
1470-
1471- it ( 'should update range on re-wrapping attribute (#475)' , ( ) => {
1472- const modelElement = new ModelElement ( 'paragraph' , null , [
1473- new ModelText ( 'x' ) ,
1474- new ModelText ( 'foo' , { link : 'http://foo.com' } ) ,
1475- new ModelText ( 'x' )
1476- ] ) ;
1477-
1478- const elementGenerator = ( modelAttributeValue , viewWriter ) => {
1479- return viewWriter . createAttributeElement ( 'a' , { href : modelAttributeValue } ) ;
1480- } ;
1481-
1482- dispatcher . on ( 'attribute:link' , wrap ( elementGenerator ) ) ;
1483-
1484- model . change ( writer => {
1485- writer . insert ( modelElement , modelRootStart ) ;
1486- } ) ;
1487-
1488- expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p>x<a href="http://foo.com">foo</a>x</p></div>' ) ;
1489-
1490- // Set new attribute on old link but also on non-linked characters.
1491- model . change ( writer => {
1492- writer . setAttribute ( 'link' , 'http://foobar.com' , writer . createRangeIn ( modelElement ) ) ;
1493- } ) ;
1494-
1495- expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p><a href="http://foobar.com">xfoox</a></p></div>' ) ;
1496- } ) ;
1497-
1498- it ( 'should support unicode' , ( ) => {
1499- const modelElement = new ModelElement ( 'paragraph' , null , [ 'நி' , new ModelText ( 'லைக்' , { bold : true } ) , 'கு' ] ) ;
1500- const creator = ( modelAttributeValue , viewWriter ) => viewWriter . createAttributeElement ( 'b' ) ;
1501-
1502- dispatcher . on ( 'attribute:bold' , wrap ( creator ) ) ;
1503-
1504- model . change ( writer => {
1505- writer . insert ( modelElement , modelRootStart ) ;
1506- } ) ;
1507-
1508- expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p>நி<b>லைக்</b>கு</p></div>' ) ;
1509-
1510- model . change ( writer => {
1511- writer . removeAttribute ( 'bold' , writer . createRangeIn ( modelElement ) ) ;
1512- } ) ;
1513-
1514- expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p>நிலைக்கு</p></div>' ) ;
1515- } ) ;
1516-
1517- it ( 'should be possible to override wrap' , ( ) => {
1518- const modelElement = new ModelElement ( 'paragraph' , null , new ModelText ( 'foobar' , { bold : true } ) ) ;
1519-
1520- dispatcher . on ( 'attribute:bold' , wrap ( ( modelAttributeValue , viewWriter ) => viewWriter . createAttributeElement ( 'b' ) ) ) ;
1521-
1522- dispatcher . on (
1523- 'attribute:bold' ,
1524- wrap ( ( modelAttributeValue , viewWriter ) => viewWriter . createAttributeElement ( 'strong' ) ) ,
1525- { priority : 'high' }
1526- ) ;
1527-
1528- model . change ( writer => {
1529- writer . insert ( modelElement , modelRootStart ) ;
1530- } ) ;
1531-
1532- expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p><strong>foobar</strong></p></div>' ) ;
1533- } ) ;
1534-
1535- it ( 'should not convert and not consume if creator function returned null' , ( ) => {
1536- const elementGenerator = ( ) => null ;
1537-
1538- sinon . spy ( dispatcher , 'fire' ) ;
1539-
1540- const modelElement = new ModelElement ( 'paragraph' , null , new ModelText ( 'foobar' , { italic : true } ) ) ;
1541-
1542- dispatcher . on ( 'attribute:italic' , wrap ( elementGenerator ) ) ;
1543-
1544- const spy = sinon . spy ( ) ;
1545- dispatcher . on ( 'attribute:italic' , spy ) ;
1546-
1547- model . change ( writer => {
1548- writer . insert ( modelElement , modelRootStart ) ;
1549- } ) ;
1550-
1551- expect ( viewToString ( viewRoot ) ) . to . equal ( '<div><p>foobar</p></div>' ) ;
1552- expect ( dispatcher . fire . calledWith ( 'attribute:italic:$text' ) ) . to . be . true ;
1553- expect ( spy . called ) . to . be . true ;
1554- } ) ;
1555- } ) ;
1556-
15571568 // Remove converter is by default already added in `EditingController` instance.
15581569 describe ( 'remove' , ( ) => {
15591570 it ( 'should remove items from view accordingly to changes in model #1' , ( ) => {
0 commit comments