placeholder.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /**
  2. * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import { attachPlaceholder, detachPlaceholder } from '../../src/view/placeholder';
  6. import createViewRoot from './_utils/createroot';
  7. import View from '../../src/view/view';
  8. import ViewRange from '../../src/view/range';
  9. import { setData } from '../../src/dev-utils/view';
  10. describe( 'placeholder', () => {
  11. let view, viewDocument, viewRoot;
  12. beforeEach( () => {
  13. view = new View();
  14. viewDocument = view.document;
  15. viewRoot = createViewRoot( viewDocument );
  16. viewDocument.isFocused = true;
  17. } );
  18. describe( 'createPlaceholder', () => {
  19. it( 'should attach proper CSS class and data attribute', () => {
  20. setData( view, '<div></div><div>{another div}</div>' );
  21. const element = viewRoot.getChild( 0 );
  22. attachPlaceholder( view, element, 'foo bar baz' );
  23. expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
  24. expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
  25. } );
  26. it( 'if element has children set only data attribute', () => {
  27. setData( view, '<div>first div</div><div>{another div}</div>' );
  28. const element = viewRoot.getChild( 0 );
  29. attachPlaceholder( view, element, 'foo bar baz' );
  30. expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
  31. expect( element.hasClass( 'ck-placeholder' ) ).to.be.false;
  32. } );
  33. it( 'if element has only ui elements, set CSS class and data attribute', () => {
  34. setData( view, '<div><ui:span></ui:span><ui:span></ui:span></div><div>{another div}</div>' );
  35. const element = viewRoot.getChild( 0 );
  36. attachPlaceholder( view, element, 'foo bar baz' );
  37. expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
  38. expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
  39. } );
  40. it( 'if element has selection inside set only data attribute', () => {
  41. setData( view, '<div>[]</div><div>another div</div>' );
  42. const element = viewRoot.getChild( 0 );
  43. attachPlaceholder( view, element, 'foo bar baz' );
  44. expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
  45. expect( element.hasClass( 'ck-placeholder' ) ).to.be.false;
  46. } );
  47. it( 'if element has selection inside but document is blurred should contain placeholder CSS class', () => {
  48. setData( view, '<div>[]</div><div>another div</div>' );
  49. const element = viewRoot.getChild( 0 );
  50. viewDocument.isFocused = false;
  51. attachPlaceholder( view, element, 'foo bar baz' );
  52. expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
  53. expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
  54. } );
  55. it( 'use check function if one is provided', () => {
  56. setData( view, '<div></div><div>{another div}</div>' );
  57. const element = viewRoot.getChild( 0 );
  58. const spy = sinon.spy( () => false );
  59. attachPlaceholder( view, element, 'foo bar baz', spy );
  60. sinon.assert.calledOnce( spy );
  61. expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
  62. expect( element.hasClass( 'ck-placeholder' ) ).to.be.false;
  63. } );
  64. it( 'should remove CSS class if selection is moved inside', () => {
  65. setData( view, '<div></div><div>{another div}</div>' );
  66. const element = viewRoot.getChild( 0 );
  67. attachPlaceholder( view, element, 'foo bar baz' );
  68. expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
  69. expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
  70. view.change( writer => {
  71. writer.setSelection( ViewRange.createIn( element ) );
  72. } );
  73. expect( element.hasClass( 'ck-placeholder' ) ).to.be.false;
  74. } );
  75. it( 'should change placeholder settings when called twice', () => {
  76. setData( view, '<div></div><div>{another div}</div>' );
  77. const element = viewRoot.getChild( 0 );
  78. attachPlaceholder( view, element, 'foo bar baz' );
  79. attachPlaceholder( view, element, 'new text' );
  80. expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'new text' );
  81. expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
  82. } );
  83. it( 'should not throw when element is no longer in document', () => {
  84. setData( view, '<div></div><div>{another div}</div>' );
  85. const element = viewRoot.getChild( 0 );
  86. attachPlaceholder( view, element, 'foo bar baz' );
  87. setData( view, '<p>paragraph</p>' );
  88. view.render();
  89. } );
  90. it( 'should allow to add placeholder to elements from different documents', () => {
  91. setData( view, '<div></div><div>{another div}</div>' );
  92. const element = viewRoot.getChild( 0 );
  93. const secondView = new View();
  94. const secondDocument = secondView.document;
  95. secondDocument.isFocused = true;
  96. const secondRoot = createViewRoot( secondDocument );
  97. setData( secondView, '<div></div><div>{another div}</div>' );
  98. const secondElement = secondRoot.getChild( 0 );
  99. attachPlaceholder( view, element, 'first placeholder' );
  100. attachPlaceholder( secondView, secondElement, 'second placeholder' );
  101. expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'first placeholder' );
  102. expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
  103. expect( secondElement.getAttribute( 'data-placeholder' ) ).to.equal( 'second placeholder' );
  104. expect( secondElement.hasClass( 'ck-placeholder' ) ).to.be.true;
  105. // Move selection to the elements with placeholders.
  106. view.change( writer => {
  107. writer.setSelection( ViewRange.createIn( element ) );
  108. } );
  109. secondView.change( writer => {
  110. writer.setSelection( ViewRange.createIn( secondElement ) );
  111. } );
  112. expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'first placeholder' );
  113. expect( element.hasClass( 'ck-placeholder' ) ).to.be.false;
  114. expect( secondElement.getAttribute( 'data-placeholder' ) ).to.equal( 'second placeholder' );
  115. expect( secondElement.hasClass( 'ck-placeholder' ) ).to.be.false;
  116. } );
  117. it( 'should update placeholder before rendering', () => {
  118. setData( view, '<div></div><div>{another div}</div>' );
  119. const element = viewRoot.getChild( 0 );
  120. attachPlaceholder( view, element, 'foo bar baz' );
  121. view.change( writer => {
  122. writer.setSelection( ViewRange.createIn( element ) );
  123. // Here we are before rendering - placeholder is visible in first element;
  124. expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
  125. expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
  126. } );
  127. // After rendering - placeholder should be invisible since selection is moved there.
  128. expect( element.hasClass( 'ck-placeholder' ) ).to.be.false;
  129. } );
  130. } );
  131. describe( 'detachPlaceholder', () => {
  132. it( 'should remove placeholder from element', () => {
  133. setData( view, '<div></div><div>{another div}</div>' );
  134. const element = viewRoot.getChild( 0 );
  135. attachPlaceholder( view, element, 'foo bar baz' );
  136. expect( element.getAttribute( 'data-placeholder' ) ).to.equal( 'foo bar baz' );
  137. expect( element.hasClass( 'ck-placeholder' ) ).to.be.true;
  138. detachPlaceholder( element );
  139. expect( element.hasAttribute( 'data-placeholder' ) ).to.be.false;
  140. expect( element.hasClass( 'ck-placeholder' ) ).to.be.false;
  141. } );
  142. } );
  143. } );