domemittermixin.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /**
  2. * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /* global document, Event, MouseEvent */
  6. /* bender-tags: ui */
  7. 'use strict';
  8. import testUtils from '/tests/_utils/utils.js';
  9. import objectUtils from '/ckeditor5/core/lib/lodash/object.js';
  10. import DOMEmitterMixin from '/ckeditor5/core/ui/domemittermixin.js';
  11. import EmitterMixin from '/ckeditor5/core/emittermixin.js';
  12. let emitter, domEmitter, node;
  13. testUtils.createSinonSandbox();
  14. let getEmitterInstance = () => objectUtils.extend( {}, EmitterMixin );
  15. let getDOMEmitterInstance = () => objectUtils.extend( {}, DOMEmitterMixin );
  16. let getDOMNodeInstance = () => document.createElement( 'div' );
  17. function updateEmitterInstance() {
  18. emitter = getEmitterInstance();
  19. }
  20. function updateDOMEmitterInstance() {
  21. domEmitter = getDOMEmitterInstance();
  22. }
  23. function updateDOMNodeInstance() {
  24. node = getDOMNodeInstance();
  25. }
  26. beforeEach( updateEmitterInstance );
  27. beforeEach( updateDOMEmitterInstance );
  28. beforeEach( updateDOMNodeInstance );
  29. describe( 'listenTo', () => {
  30. it( 'should listen to EmitterMixin events', () => {
  31. let spy = testUtils.sinon.spy();
  32. domEmitter.listenTo( emitter, 'test', spy );
  33. emitter.fire( 'test' );
  34. sinon.assert.calledOnce( spy );
  35. } );
  36. it( 'should listen to native DOM events', () => {
  37. let spy = testUtils.sinon.spy();
  38. domEmitter.listenTo( node, 'test', spy );
  39. let event = new Event( 'test' );
  40. node.dispatchEvent( event );
  41. sinon.assert.calledOnce( spy );
  42. } );
  43. } );
  44. describe( 'stopListening', () => {
  45. it( 'should stop listening to a specific event callback', () => {
  46. let spy1 = testUtils.sinon.spy();
  47. let spy2 = testUtils.sinon.spy();
  48. domEmitter.listenTo( node, 'event1', spy1 );
  49. domEmitter.listenTo( node, 'event2', spy2 );
  50. node.dispatchEvent( new Event( 'event1' ) );
  51. node.dispatchEvent( new Event( 'event2' ) );
  52. domEmitter.stopListening( node, 'event1', spy1 );
  53. node.dispatchEvent( new Event( 'event1' ) );
  54. node.dispatchEvent( new Event( 'event2' ) );
  55. sinon.assert.calledOnce( spy1 );
  56. sinon.assert.calledTwice( spy2 );
  57. } );
  58. it( 'should stop listening to an specific event', () => {
  59. let spy1a = testUtils.sinon.spy();
  60. let spy1b = testUtils.sinon.spy();
  61. let spy2 = testUtils.sinon.spy();
  62. domEmitter.listenTo( node, 'event1', spy1a );
  63. domEmitter.listenTo( node, 'event1', spy1b );
  64. domEmitter.listenTo( node, 'event2', spy2 );
  65. node.dispatchEvent( new Event( 'event1' ) );
  66. node.dispatchEvent( new Event( 'event2' ) );
  67. sinon.assert.calledOnce( spy1a );
  68. sinon.assert.calledOnce( spy1b );
  69. sinon.assert.calledOnce( spy2 );
  70. domEmitter.stopListening( node, 'event1' );
  71. node.dispatchEvent( new Event( 'event1' ) );
  72. node.dispatchEvent( new Event( 'event2' ) );
  73. sinon.assert.calledOnce( spy1a );
  74. sinon.assert.calledOnce( spy1b );
  75. sinon.assert.calledTwice( spy2 );
  76. } );
  77. it( 'should stop listening to all events from a specific node', () => {
  78. let spy1 = testUtils.sinon.spy();
  79. let spy2 = testUtils.sinon.spy();
  80. domEmitter.listenTo( node, 'event1', spy1 );
  81. domEmitter.listenTo( node, 'event2', spy2 );
  82. node.dispatchEvent( new Event( 'event1' ) );
  83. node.dispatchEvent( new Event( 'event2' ) );
  84. domEmitter.stopListening( node );
  85. node.dispatchEvent( new Event( 'event1' ) );
  86. node.dispatchEvent( new Event( 'event2' ) );
  87. sinon.assert.calledOnce( spy1 );
  88. sinon.assert.calledOnce( spy2 );
  89. } );
  90. it( 'should stop listening to everything', () => {
  91. let spy1 = testUtils.sinon.spy();
  92. let spy2 = testUtils.sinon.spy();
  93. let node1 = getDOMNodeInstance();
  94. let node2 = getDOMNodeInstance();
  95. domEmitter.listenTo( node1, 'event1', spy1 );
  96. domEmitter.listenTo( node2, 'event2', spy2 );
  97. expect( domEmitter ).to.have.property( '_listeningTo' );
  98. node1.dispatchEvent( new Event( 'event1' ) );
  99. node2.dispatchEvent( new Event( 'event2' ) );
  100. domEmitter.stopListening();
  101. node1.dispatchEvent( new Event( 'event1' ) );
  102. node2.dispatchEvent( new Event( 'event2' ) );
  103. sinon.assert.calledOnce( spy1 );
  104. sinon.assert.calledOnce( spy2 );
  105. expect( domEmitter ).to.not.have.property( '_listeningTo' );
  106. } );
  107. it( 'should not stop other nodes when a non-listened node is provided', () => {
  108. let spy = testUtils.sinon.spy();
  109. let node1 = getDOMNodeInstance();
  110. let node2 = getDOMNodeInstance();
  111. domEmitter.listenTo( node1, 'test', spy );
  112. domEmitter.stopListening( node2 );
  113. node1.dispatchEvent( new Event( 'test' ) );
  114. sinon.assert.called( spy );
  115. } );
  116. it( 'should pass DOM Event data to the listener', () => {
  117. let spy = testUtils.sinon.spy();
  118. let node = getDOMNodeInstance();
  119. domEmitter.listenTo( node, 'click', spy );
  120. let mouseEvent = new MouseEvent( 'click', {
  121. screenX: 10,
  122. screenY: 20
  123. } );
  124. node.dispatchEvent( mouseEvent );
  125. sinon.assert.calledOnce( spy );
  126. expect( spy.args[ 0 ][ 1 ] ).to.be.equal( mouseEvent );
  127. } );
  128. it( 'should detach native DOM event listener proxy, specific event', () => {
  129. let spy1a = testUtils.sinon.spy();
  130. let spy1b = testUtils.sinon.spy();
  131. domEmitter.listenTo( node, 'test', spy1a );
  132. let proxyEmitter = domEmitter._getProxyEmitter( node );
  133. let spy2 = testUtils.sinon.spy( proxyEmitter, 'fire' );
  134. node.dispatchEvent( new Event( 'test' ) );
  135. sinon.assert.calledOnce( spy1a );
  136. sinon.assert.calledOnce( spy2 );
  137. domEmitter.stopListening( node, 'test' );
  138. node.dispatchEvent( new Event( 'test' ) );
  139. sinon.assert.calledOnce( spy1a );
  140. sinon.assert.calledOnce( spy2 );
  141. // Attach same event again.
  142. domEmitter.listenTo( node, 'test', spy1b );
  143. node.dispatchEvent( new Event( 'test' ) );
  144. expect( proxyEmitter ).to.be.equal( domEmitter._getProxyEmitter( node ) );
  145. sinon.assert.calledOnce( spy1a );
  146. sinon.assert.calledOnce( spy1b );
  147. sinon.assert.calledTwice( spy2 );
  148. } );
  149. it( 'should detach native DOM event listener proxy, specific callback', () => {
  150. let spy1a = testUtils.sinon.spy();
  151. let spy1b = testUtils.sinon.spy();
  152. let spy1c = testUtils.sinon.spy();
  153. domEmitter.listenTo( node, 'test', spy1a );
  154. domEmitter.listenTo( node, 'test', spy1b );
  155. let proxyEmitter = domEmitter._getProxyEmitter( node );
  156. let spy2 = testUtils.sinon.spy( proxyEmitter, 'fire' );
  157. node.dispatchEvent( new Event( 'test' ) );
  158. sinon.assert.calledOnce( spy1a );
  159. sinon.assert.calledOnce( spy1b );
  160. sinon.assert.calledOnce( spy2 );
  161. domEmitter.stopListening( node, 'test', spy1a );
  162. node.dispatchEvent( new Event( 'test' ) );
  163. sinon.assert.calledOnce( spy1a );
  164. sinon.assert.calledTwice( spy1b );
  165. sinon.assert.calledTwice( spy2 );
  166. domEmitter.stopListening( node, 'test', spy1b );
  167. node.dispatchEvent( new Event( 'test' ) );
  168. sinon.assert.calledOnce( spy1a );
  169. sinon.assert.calledTwice( spy1b );
  170. sinon.assert.calledTwice( spy2 );
  171. // Attach same event again.
  172. domEmitter.listenTo( node, 'test', spy1c );
  173. node.dispatchEvent( new Event( 'test' ) );
  174. expect( proxyEmitter ).to.be.equal( domEmitter._getProxyEmitter( node ) );
  175. sinon.assert.calledOnce( spy1a );
  176. sinon.assert.calledTwice( spy1b );
  177. sinon.assert.calledOnce( spy1c );
  178. sinon.assert.calledThrice( spy2 );
  179. } );
  180. it( 'should detach native DOM event listener proxy, specific emitter', () => {
  181. let spy1a = testUtils.sinon.spy();
  182. let spy1b = testUtils.sinon.spy();
  183. let spy1c = testUtils.sinon.spy();
  184. let spy1d = testUtils.sinon.spy();
  185. domEmitter.listenTo( node, 'test1', spy1a );
  186. domEmitter.listenTo( node, 'test2', spy1b );
  187. let proxyEmitter = domEmitter._getProxyEmitter( node );
  188. let spy2 = testUtils.sinon.spy( proxyEmitter, 'fire' );
  189. node.dispatchEvent( new Event( 'test1' ) );
  190. node.dispatchEvent( new Event( 'test2' ) );
  191. sinon.assert.calledOnce( spy1a );
  192. sinon.assert.calledOnce( spy1b );
  193. sinon.assert.calledTwice( spy2 );
  194. domEmitter.stopListening( node );
  195. node.dispatchEvent( new Event( 'test1' ) );
  196. node.dispatchEvent( new Event( 'test2' ) );
  197. sinon.assert.calledOnce( spy1a );
  198. sinon.assert.calledOnce( spy1b );
  199. sinon.assert.calledTwice( spy2 );
  200. // Attach same event again.
  201. domEmitter.listenTo( node, 'test1', spy1c );
  202. domEmitter.listenTo( node, 'test2', spy1d );
  203. // Old proxy emitter died when stopped listening to the node.
  204. let proxyEmitter2 = domEmitter._getProxyEmitter( node );
  205. let spy3 = testUtils.sinon.spy( proxyEmitter2, 'fire' );
  206. node.dispatchEvent( new Event( 'test1' ) );
  207. node.dispatchEvent( new Event( 'test2' ) );
  208. expect( proxyEmitter ).to.not.be.equal( proxyEmitter2 );
  209. sinon.assert.calledOnce( spy1a );
  210. sinon.assert.calledOnce( spy1b );
  211. sinon.assert.calledOnce( spy1c );
  212. sinon.assert.calledOnce( spy1d );
  213. sinon.assert.calledTwice( spy2 );
  214. sinon.assert.calledTwice( spy3 );
  215. } );
  216. it( 'should detach native DOM event listener proxy, everything', () => {
  217. let spy1a = testUtils.sinon.spy();
  218. let spy1b = testUtils.sinon.spy();
  219. let spy1c = testUtils.sinon.spy();
  220. let spy1d = testUtils.sinon.spy();
  221. domEmitter.listenTo( node, 'test1', spy1a );
  222. domEmitter.listenTo( node, 'test2', spy1b );
  223. let proxyEmitter = domEmitter._getProxyEmitter( node );
  224. let spy2 = testUtils.sinon.spy( proxyEmitter, 'fire' );
  225. node.dispatchEvent( new Event( 'test1' ) );
  226. node.dispatchEvent( new Event( 'test2' ) );
  227. sinon.assert.calledOnce( spy1a );
  228. sinon.assert.calledOnce( spy1b );
  229. sinon.assert.calledTwice( spy2 );
  230. domEmitter.stopListening();
  231. node.dispatchEvent( new Event( 'test1' ) );
  232. node.dispatchEvent( new Event( 'test2' ) );
  233. sinon.assert.calledOnce( spy1a );
  234. sinon.assert.calledOnce( spy1b );
  235. sinon.assert.calledTwice( spy2 );
  236. // Attach same event again.
  237. domEmitter.listenTo( node, 'test1', spy1c );
  238. domEmitter.listenTo( node, 'test2', spy1d );
  239. // Old proxy emitter died when stopped listening to the node.
  240. let proxyEmitter2 = domEmitter._getProxyEmitter( node );
  241. let spy3 = testUtils.sinon.spy( proxyEmitter2, 'fire' );
  242. node.dispatchEvent( new Event( 'test1' ) );
  243. node.dispatchEvent( new Event( 'test2' ) );
  244. expect( proxyEmitter ).to.not.be.equal( proxyEmitter2 );
  245. sinon.assert.calledOnce( spy1a );
  246. sinon.assert.calledOnce( spy1b );
  247. sinon.assert.calledOnce( spy1c );
  248. sinon.assert.calledOnce( spy1d );
  249. sinon.assert.calledTwice( spy2 );
  250. sinon.assert.calledTwice( spy3 );
  251. } );
  252. } );