@@ -1803,8 +1803,9 @@ describe( 'Renderer', () => {
1803
1803
) ;
1804
1804
} ) ;
1805
1805
1806
- // Happens when `shift + up` arrow pressed during composition in Chrome on Windows.
1807
- it ( 'should not delete inline filler when selection (ranged) changes without compositionend (filler on end)' , ( ) => {
1806
+ // Happens when `shift + up` arrow pressed during composition (Chrome on Windows).
1807
+ // https://github.com/ckeditor/ckeditor5-engine/pull/1355#issuecomment-376087328
1808
+ it ( 'should not delete inline filler when selection changes without compositionend (filler in styled element)' , ( ) => {
1808
1809
const domSelection = document . getSelection ( ) ;
1809
1810
1810
1811
// 1. Render <h1>h1</h1><p>foo<b>FILLER{}</b>bar</p>.
@@ -1860,8 +1861,186 @@ describe( 'Renderer', () => {
1860
1861
expect ( domSelection . getRangeAt ( 0 ) . collapsed ) . to . be . false ;
1861
1862
} ) ;
1862
1863
1864
+ // Happens when `shift + up` arrow pressed during composition after unbolding text (Chrome on Windows).
1865
+ // https://github.com/ckeditor/ckeditor5-engine/pull/1355#issuecomment-381516509
1866
+ it ( 'should not delete inline filler when selection changes without compositionend (filler on paragraph end with text)' , ( ) => {
1867
+ const domSelection = document . getSelection ( ) ;
1868
+
1869
+ // 1. Render <p>foo<b>FILLER{}</b></p>.
1870
+ const { view : viewContent , selection : newSelection } = parse (
1871
+ '<container:p>foo<attribute:b>[]</attribute:b></container:p>' ) ;
1872
+
1873
+ viewRoot . _appendChild ( viewContent ) ;
1874
+ selection . _setTo ( newSelection ) ;
1875
+
1876
+ renderer . markToSync ( 'children' , viewRoot ) ;
1877
+ renderer . render ( ) ;
1878
+
1879
+ expect ( normalizeHtml ( domRoot . innerHTML ) ) . to . equal ( '<p>foo<b></b></p>' ) ;
1880
+
1881
+ // 2. Start composition and edit to resulting HTML: <p>foo<b>bar</b>FILLER{}</p>.
1882
+ renderer . isComposing = true ;
1883
+
1884
+ const domP = domRoot . childNodes [ 0 ] ;
1885
+ const domB = domP . childNodes [ 1 ] ;
1886
+
1887
+ domB . childNodes [ 0 ] . data += 'bar' ;
1888
+
1889
+ const viewP = viewRoot . getChild ( 0 ) ;
1890
+ const viewB = viewP . getChild ( 1 ) ;
1891
+
1892
+ viewB . _appendChild ( new ViewText ( 'bar' ) ) ;
1893
+
1894
+ selection . _setTo ( ViewRange . createFromParentsAndOffsets ( viewP , 2 , viewP , 2 ) ) ;
1895
+
1896
+ renderer . markToSync ( 'children' , viewRoot ) ;
1897
+ renderer . render ( ) ;
1898
+
1899
+ expect ( normalizeHtml ( domRoot . innerHTML ) ) . to . equal ( '<p>foo<b>bar</b></p>' ) ;
1900
+ expect ( domB . childNodes [ 0 ] . data ) . to . equal ( 'bar' ) ;
1901
+ expect ( domP . childNodes [ 0 ] . data ) . to . equal ( 'foo' ) ;
1902
+ expect ( domP . childNodes [ 2 ] . data ) . to . equal ( INLINE_FILLER ) ;
1903
+
1904
+ // 3. Edit to resulting HTML: <p>foo<b>bar</b>FILLERbaz{}</p>.
1905
+ viewP . _appendChild ( new ViewText ( 'baz' ) ) ;
1906
+
1907
+ selection . _setTo ( ViewRange . createFromParentsAndOffsets ( viewP . getChild ( 2 ) , 3 , viewP . getChild ( 2 ) , 3 ) ) ;
1908
+
1909
+ renderer . markToSync ( 'children' , viewRoot ) ;
1910
+ renderer . render ( ) ;
1911
+
1912
+ expect ( normalizeHtml ( domRoot . innerHTML ) ) . to . equal ( '<p>foo<b>bar</b>baz</p>' ) ;
1913
+ expect ( domB . childNodes [ 0 ] . data ) . to . equal ( 'bar' ) ;
1914
+ expect ( domP . childNodes [ 0 ] . data ) . to . equal ( 'foo' ) ;
1915
+ expect ( domP . childNodes [ 2 ] . data ) . to . equal ( INLINE_FILLER + 'baz' ) ;
1916
+
1917
+ // 4. Move selection (<p>{foo<b>bar</b>FILLERbaz}</p>) and render to check if filler stays untouched.
1918
+ selection . _setTo ( ViewRange . createFromParentsAndOffsets ( viewP . getChild ( 0 ) , 0 , viewP . getChild ( 2 ) , 3 ) ) ;
1919
+
1920
+ renderer . markToSync ( 'children' , viewRoot ) ;
1921
+ renderer . render ( ) ;
1922
+
1923
+ expect ( normalizeHtml ( domRoot . innerHTML ) ) . to . equal ( '<p>foo<b>bar</b>baz</p>' ) ;
1924
+ expect ( domB . childNodes [ 0 ] . data ) . to . equal ( 'bar' ) ;
1925
+ expect ( domP . childNodes [ 0 ] . data ) . to . equal ( 'foo' ) ;
1926
+ expect ( domP . childNodes [ 2 ] . data ) . to . equal ( INLINE_FILLER + 'baz' ) ;
1927
+
1928
+ expect ( domSelection . getRangeAt ( 0 ) . startContainer ) . to . equal ( domP . childNodes [ 0 ] ) ;
1929
+ expect ( domSelection . getRangeAt ( 0 ) . endContainer ) . to . equal ( domP . childNodes [ 2 ] ) ;
1930
+ expect ( domSelection . getRangeAt ( 0 ) . collapsed ) . to . be . false ;
1931
+ } ) ;
1932
+
1933
+ // Happens when `shift + up` arrow pressed during composition after unbolding text (Chrome on Windows).
1934
+ // https://github.com/ckeditor/ckeditor5-engine/pull/1355#issuecomment-381516509
1935
+ it ( 'should not delete inline filler when selection changes without compositionend (filler on paragraph end)' , ( ) => {
1936
+ const domSelection = document . getSelection ( ) ;
1937
+
1938
+ // 1. Render <p>foo<b>FILLER{}</b></p>.
1939
+ const { view : viewContent , selection : newSelection } = parse (
1940
+ '<container:p>foo<attribute:b>[]</attribute:b></container:p>' ) ;
1941
+
1942
+ viewRoot . _appendChild ( viewContent ) ;
1943
+ selection . _setTo ( newSelection ) ;
1944
+
1945
+ renderer . markToSync ( 'children' , viewRoot ) ;
1946
+ renderer . render ( ) ;
1947
+
1948
+ expect ( normalizeHtml ( domRoot . innerHTML ) ) . to . equal ( '<p>foo<b></b></p>' ) ;
1949
+
1950
+ // 2. Start composition and edit to resulting HTML: <p>foo<b>bar</b>FILLER{}</p>.
1951
+ renderer . isComposing = true ;
1952
+
1953
+ const domP = domRoot . childNodes [ 0 ] ;
1954
+ const domB = domP . childNodes [ 1 ] ;
1955
+
1956
+ domB . childNodes [ 0 ] . data += 'bar' ;
1957
+
1958
+ const viewP = viewRoot . getChild ( 0 ) ;
1959
+ const viewB = viewP . getChild ( 1 ) ;
1960
+
1961
+ viewB . _appendChild ( new ViewText ( 'bar' ) ) ;
1962
+
1963
+ selection . _setTo ( ViewRange . createFromParentsAndOffsets ( viewP , 2 , viewP , 2 ) ) ;
1964
+
1965
+ renderer . markToSync ( 'children' , viewRoot ) ;
1966
+ renderer . render ( ) ;
1967
+
1968
+ expect ( normalizeHtml ( domRoot . innerHTML ) ) . to . equal ( '<p>foo<b>bar</b></p>' ) ;
1969
+ expect ( domB . childNodes [ 0 ] . data ) . to . equal ( 'bar' ) ;
1970
+ expect ( domP . childNodes [ 0 ] . data ) . to . equal ( 'foo' ) ;
1971
+ expect ( domP . childNodes [ 2 ] . data ) . to . equal ( INLINE_FILLER ) ;
1972
+
1973
+ // 3. Edit to resulting HTML: <p>foo<b>bar</b>FILLER{}</p>.
1974
+ selection . _setTo ( ViewRange . createFromParentsAndOffsets ( viewP , 2 , viewP , 2 ) ) ;
1975
+
1976
+ renderer . markToSync ( 'children' , viewRoot ) ;
1977
+ renderer . render ( ) ;
1978
+
1979
+ expect ( normalizeHtml ( domRoot . innerHTML ) ) . to . equal ( '<p>foo<b>bar</b></p>' ) ;
1980
+ expect ( domB . childNodes [ 0 ] . data ) . to . equal ( 'bar' ) ;
1981
+ expect ( domP . childNodes [ 0 ] . data ) . to . equal ( 'foo' ) ;
1982
+ expect ( domP . childNodes [ 2 ] . data ) . to . equal ( INLINE_FILLER ) ;
1983
+
1984
+ // 4. Move selection (<p>{foo<b>bar</b>FILLER}</p>) and render to check if filler stays untouched.
1985
+ selection . _setTo ( ViewRange . createFromParentsAndOffsets ( viewP . getChild ( 0 ) , 0 , viewP , 2 ) ) ;
1986
+
1987
+ renderer . markToSync ( 'children' , viewRoot ) ;
1988
+ renderer . render ( ) ;
1989
+
1990
+ expect ( normalizeHtml ( domRoot . innerHTML ) ) . to . equal ( '<p>foo<b>bar</b></p>' ) ;
1991
+ expect ( domB . childNodes [ 0 ] . data ) . to . equal ( 'bar' ) ;
1992
+ expect ( domP . childNodes [ 0 ] . data ) . to . equal ( 'foo' ) ;
1993
+ expect ( domP . childNodes [ 2 ] . data ) . to . equal ( INLINE_FILLER ) ;
1994
+
1995
+ expect ( domSelection . getRangeAt ( 0 ) . startContainer ) . to . equal ( domP . childNodes [ 0 ] ) ;
1996
+ expect ( domSelection . getRangeAt ( 0 ) . endContainer ) . to . equal ( domP . childNodes [ 2 ] ) ;
1997
+ expect ( domSelection . getRangeAt ( 0 ) . collapsed ) . to . be . false ;
1998
+ } ) ;
1999
+
2000
+ // This is more theoretical situation (should not be reproducible in real world unless composition is broken).
2001
+ it ( 'should not add new inline filler when empty inline element was removed by selection change during composition' , ( ) => {
2002
+ const domSelection = document . getSelection ( ) ;
2003
+
2004
+ // 1. Render <p>foo bar<b>FILLER{}</b></p>.
2005
+ const { view : viewContent , selection : newSelection } = parse (
2006
+ '<container:p>foo bar<attribute:b>[]</attribute:b></container:p>' ) ;
2007
+
2008
+ viewRoot . _appendChild ( viewContent ) ;
2009
+ selection . _setTo ( newSelection ) ;
2010
+
2011
+ renderer . markToSync ( 'children' , viewRoot ) ;
2012
+ renderer . render ( ) ;
2013
+
2014
+ const domP = domRoot . childNodes [ 0 ] ;
2015
+ const domB = domP . childNodes [ 1 ] ;
2016
+
2017
+ expect ( normalizeHtml ( domRoot . innerHTML ) ) . to . equal ( '<p>foo bar<b></b></p>' ) ;
2018
+ expect ( domB . childNodes [ 0 ] . data ) . to . equal ( INLINE_FILLER ) ;
2019
+ expect ( domP . childNodes [ 0 ] . data ) . to . equal ( 'foo bar' ) ;
2020
+
2021
+ // 2. Start composition and change selection to: <p>{foo bar}</p>.
2022
+ renderer . isComposing = true ;
2023
+
2024
+ const viewP = viewRoot . getChild ( 0 ) ;
2025
+
2026
+ viewP . getChild ( 1 ) . _remove ( ) ; // Simulate `<b>` removal.
2027
+
2028
+ selection . _setTo ( ViewRange . createFromParentsAndOffsets ( viewP . getChild ( 0 ) , 0 , viewP . getChild ( 0 ) , 7 ) ) ;
2029
+
2030
+ renderer . markToSync ( 'children' , viewP ) ;
2031
+ renderer . render ( ) ;
2032
+
2033
+ expect ( normalizeHtml ( domRoot . innerHTML ) ) . to . equal ( '<p>foo bar</p>' ) ;
2034
+ expect ( domP . childNodes [ 0 ] . data ) . to . equal ( 'foo bar' ) ;
2035
+ expect ( domP . childNodes . length ) . to . equal ( 1 ) ;
2036
+
2037
+ expect ( domSelection . getRangeAt ( 0 ) . startContainer ) . to . equal ( domP . childNodes [ 0 ] ) ;
2038
+ expect ( domSelection . getRangeAt ( 0 ) . endContainer ) . to . equal ( domP . childNodes [ 0 ] ) ;
2039
+ expect ( domSelection . getRangeAt ( 0 ) . collapsed ) . to . be . false ;
2040
+ } ) ;
2041
+
1863
2042
// This is more theoretical situation (should not be reproducible in real world unless composition is broken).
1864
- it ( 'should not delete inline filler when selection (ranged) changes without compositionend (filler inside)' , ( ) => {
2043
+ it ( 'should not delete inline filler when selection changes without compositionend (filler inside selection )' , ( ) => {
1865
2044
const domSelection = document . getSelection ( ) ;
1866
2045
1867
2046
// 1. Render <h1>h1</h1><p>foo<b>FILLER{}</b>bar</p>.
0 commit comments