8
0

domemittermixin.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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 extend from '/ckeditor5/core/lib/lodash/extend.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 = () => extend( {}, EmitterMixin );
  15. let getDOMEmitterInstance = () => 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. // #187
  44. it( 'should work for DOM Nodes belonging to another window', () => {
  45. const spy = testUtils.sinon.spy();
  46. const iframe = document.createElement( 'iframe' );
  47. document.body.appendChild( iframe );
  48. const iframeNode = iframe.contentWindow.document.createElement( 'div' );
  49. domEmitter.listenTo( iframeNode, 'test', spy );
  50. iframeNode.dispatchEvent( new Event( 'test' ) );
  51. sinon.assert.calledOnce( spy );
  52. } );
  53. } );
  54. describe( 'stopListening', () => {
  55. it( 'should stop listening to a specific event callback', () => {
  56. let spy1 = testUtils.sinon.spy();
  57. let spy2 = testUtils.sinon.spy();
  58. domEmitter.listenTo( node, 'event1', spy1 );
  59. domEmitter.listenTo( node, 'event2', spy2 );
  60. node.dispatchEvent( new Event( 'event1' ) );
  61. node.dispatchEvent( new Event( 'event2' ) );
  62. domEmitter.stopListening( node, 'event1', spy1 );
  63. node.dispatchEvent( new Event( 'event1' ) );
  64. node.dispatchEvent( new Event( 'event2' ) );
  65. sinon.assert.calledOnce( spy1 );
  66. sinon.assert.calledTwice( spy2 );
  67. } );
  68. it( 'should stop listening to an specific event', () => {
  69. let spy1a = testUtils.sinon.spy();
  70. let spy1b = testUtils.sinon.spy();
  71. let spy2 = testUtils.sinon.spy();
  72. domEmitter.listenTo( node, 'event1', spy1a );
  73. domEmitter.listenTo( node, 'event1', spy1b );
  74. domEmitter.listenTo( node, 'event2', spy2 );
  75. node.dispatchEvent( new Event( 'event1' ) );
  76. node.dispatchEvent( new Event( 'event2' ) );
  77. sinon.assert.calledOnce( spy1a );
  78. sinon.assert.calledOnce( spy1b );
  79. sinon.assert.calledOnce( spy2 );
  80. domEmitter.stopListening( node, 'event1' );
  81. node.dispatchEvent( new Event( 'event1' ) );
  82. node.dispatchEvent( new Event( 'event2' ) );
  83. sinon.assert.calledOnce( spy1a );
  84. sinon.assert.calledOnce( spy1b );
  85. sinon.assert.calledTwice( spy2 );
  86. } );
  87. it( 'should stop listening to all events from a specific node', () => {
  88. let spy1 = testUtils.sinon.spy();
  89. let spy2 = testUtils.sinon.spy();
  90. domEmitter.listenTo( node, 'event1', spy1 );
  91. domEmitter.listenTo( node, 'event2', spy2 );
  92. node.dispatchEvent( new Event( 'event1' ) );
  93. node.dispatchEvent( new Event( 'event2' ) );
  94. domEmitter.stopListening( node );
  95. node.dispatchEvent( new Event( 'event1' ) );
  96. node.dispatchEvent( new Event( 'event2' ) );
  97. sinon.assert.calledOnce( spy1 );
  98. sinon.assert.calledOnce( spy2 );
  99. } );
  100. it( 'should stop listening to everything', () => {
  101. let spy1 = testUtils.sinon.spy();
  102. let spy2 = testUtils.sinon.spy();
  103. let node1 = getDOMNodeInstance();
  104. let node2 = getDOMNodeInstance();
  105. domEmitter.listenTo( node1, 'event1', spy1 );
  106. domEmitter.listenTo( node2, 'event2', spy2 );
  107. expect( domEmitter ).to.have.property( '_listeningTo' );
  108. node1.dispatchEvent( new Event( 'event1' ) );
  109. node2.dispatchEvent( new Event( 'event2' ) );
  110. domEmitter.stopListening();
  111. node1.dispatchEvent( new Event( 'event1' ) );
  112. node2.dispatchEvent( new Event( 'event2' ) );
  113. sinon.assert.calledOnce( spy1 );
  114. sinon.assert.calledOnce( spy2 );
  115. expect( domEmitter ).to.not.have.property( '_listeningTo' );
  116. } );
  117. it( 'should not stop other nodes when a non-listened node is provided', () => {
  118. let spy = testUtils.sinon.spy();
  119. let node1 = getDOMNodeInstance();
  120. let node2 = getDOMNodeInstance();
  121. domEmitter.listenTo( node1, 'test', spy );
  122. domEmitter.stopListening( node2 );
  123. node1.dispatchEvent( new Event( 'test' ) );
  124. sinon.assert.called( spy );
  125. } );
  126. it( 'should pass DOM Event data to the listener', () => {
  127. let spy = testUtils.sinon.spy();
  128. let node = getDOMNodeInstance();
  129. domEmitter.listenTo( node, 'click', spy );
  130. let mouseEvent = new MouseEvent( 'click', {
  131. screenX: 10,
  132. screenY: 20
  133. } );
  134. node.dispatchEvent( mouseEvent );
  135. sinon.assert.calledOnce( spy );
  136. expect( spy.args[ 0 ][ 1 ] ).to.be.equal( mouseEvent );
  137. } );
  138. it( 'should detach native DOM event listener proxy, specific event', () => {
  139. let spy1a = testUtils.sinon.spy();
  140. let spy1b = testUtils.sinon.spy();
  141. domEmitter.listenTo( node, 'test', spy1a );
  142. let proxyEmitter = domEmitter._getProxyEmitter( node );
  143. let spy2 = testUtils.sinon.spy( proxyEmitter, 'fire' );
  144. node.dispatchEvent( new Event( 'test' ) );
  145. sinon.assert.calledOnce( spy1a );
  146. sinon.assert.calledOnce( spy2 );
  147. domEmitter.stopListening( node, 'test' );
  148. node.dispatchEvent( new Event( 'test' ) );
  149. sinon.assert.calledOnce( spy1a );
  150. sinon.assert.calledOnce( spy2 );
  151. // Attach same event again.
  152. domEmitter.listenTo( node, 'test', spy1b );
  153. node.dispatchEvent( new Event( 'test' ) );
  154. expect( proxyEmitter ).to.be.equal( domEmitter._getProxyEmitter( node ) );
  155. sinon.assert.calledOnce( spy1a );
  156. sinon.assert.calledOnce( spy1b );
  157. sinon.assert.calledTwice( spy2 );
  158. } );
  159. it( 'should detach native DOM event listener proxy, specific callback', () => {
  160. let spy1a = testUtils.sinon.spy();
  161. let spy1b = testUtils.sinon.spy();
  162. let spy1c = testUtils.sinon.spy();
  163. domEmitter.listenTo( node, 'test', spy1a );
  164. domEmitter.listenTo( node, 'test', spy1b );
  165. let proxyEmitter = domEmitter._getProxyEmitter( node );
  166. let spy2 = testUtils.sinon.spy( proxyEmitter, 'fire' );
  167. node.dispatchEvent( new Event( 'test' ) );
  168. sinon.assert.calledOnce( spy1a );
  169. sinon.assert.calledOnce( spy1b );
  170. sinon.assert.calledOnce( spy2 );
  171. domEmitter.stopListening( node, 'test', spy1a );
  172. node.dispatchEvent( new Event( 'test' ) );
  173. sinon.assert.calledOnce( spy1a );
  174. sinon.assert.calledTwice( spy1b );
  175. sinon.assert.calledTwice( spy2 );
  176. domEmitter.stopListening( node, 'test', spy1b );
  177. node.dispatchEvent( new Event( 'test' ) );
  178. sinon.assert.calledOnce( spy1a );
  179. sinon.assert.calledTwice( spy1b );
  180. sinon.assert.calledTwice( spy2 );
  181. // Attach same event again.
  182. domEmitter.listenTo( node, 'test', spy1c );
  183. node.dispatchEvent( new Event( 'test' ) );
  184. expect( proxyEmitter ).to.be.equal( domEmitter._getProxyEmitter( node ) );
  185. sinon.assert.calledOnce( spy1a );
  186. sinon.assert.calledTwice( spy1b );
  187. sinon.assert.calledOnce( spy1c );
  188. sinon.assert.calledThrice( spy2 );
  189. } );
  190. it( 'should detach native DOM event listener proxy, specific emitter', () => {
  191. let spy1a = testUtils.sinon.spy();
  192. let spy1b = testUtils.sinon.spy();
  193. let spy1c = testUtils.sinon.spy();
  194. let spy1d = testUtils.sinon.spy();
  195. domEmitter.listenTo( node, 'test1', spy1a );
  196. domEmitter.listenTo( node, 'test2', spy1b );
  197. let proxyEmitter = domEmitter._getProxyEmitter( node );
  198. let spy2 = testUtils.sinon.spy( proxyEmitter, 'fire' );
  199. node.dispatchEvent( new Event( 'test1' ) );
  200. node.dispatchEvent( new Event( 'test2' ) );
  201. sinon.assert.calledOnce( spy1a );
  202. sinon.assert.calledOnce( spy1b );
  203. sinon.assert.calledTwice( spy2 );
  204. domEmitter.stopListening( node );
  205. node.dispatchEvent( new Event( 'test1' ) );
  206. node.dispatchEvent( new Event( 'test2' ) );
  207. sinon.assert.calledOnce( spy1a );
  208. sinon.assert.calledOnce( spy1b );
  209. sinon.assert.calledTwice( spy2 );
  210. // Attach same event again.
  211. domEmitter.listenTo( node, 'test1', spy1c );
  212. domEmitter.listenTo( node, 'test2', spy1d );
  213. // Old proxy emitter died when stopped listening to the node.
  214. let proxyEmitter2 = domEmitter._getProxyEmitter( node );
  215. let spy3 = testUtils.sinon.spy( proxyEmitter2, 'fire' );
  216. node.dispatchEvent( new Event( 'test1' ) );
  217. node.dispatchEvent( new Event( 'test2' ) );
  218. expect( proxyEmitter ).to.not.be.equal( proxyEmitter2 );
  219. sinon.assert.calledOnce( spy1a );
  220. sinon.assert.calledOnce( spy1b );
  221. sinon.assert.calledOnce( spy1c );
  222. sinon.assert.calledOnce( spy1d );
  223. sinon.assert.calledTwice( spy2 );
  224. sinon.assert.calledTwice( spy3 );
  225. } );
  226. it( 'should detach native DOM event listener proxy, everything', () => {
  227. let spy1a = testUtils.sinon.spy();
  228. let spy1b = testUtils.sinon.spy();
  229. let spy1c = testUtils.sinon.spy();
  230. let spy1d = testUtils.sinon.spy();
  231. domEmitter.listenTo( node, 'test1', spy1a );
  232. domEmitter.listenTo( node, 'test2', spy1b );
  233. let proxyEmitter = domEmitter._getProxyEmitter( node );
  234. let spy2 = testUtils.sinon.spy( proxyEmitter, 'fire' );
  235. node.dispatchEvent( new Event( 'test1' ) );
  236. node.dispatchEvent( new Event( 'test2' ) );
  237. sinon.assert.calledOnce( spy1a );
  238. sinon.assert.calledOnce( spy1b );
  239. sinon.assert.calledTwice( spy2 );
  240. domEmitter.stopListening();
  241. node.dispatchEvent( new Event( 'test1' ) );
  242. node.dispatchEvent( new Event( 'test2' ) );
  243. sinon.assert.calledOnce( spy1a );
  244. sinon.assert.calledOnce( spy1b );
  245. sinon.assert.calledTwice( spy2 );
  246. // Attach same event again.
  247. domEmitter.listenTo( node, 'test1', spy1c );
  248. domEmitter.listenTo( node, 'test2', spy1d );
  249. // Old proxy emitter died when stopped listening to the node.
  250. let proxyEmitter2 = domEmitter._getProxyEmitter( node );
  251. let spy3 = testUtils.sinon.spy( proxyEmitter2, 'fire' );
  252. node.dispatchEvent( new Event( 'test1' ) );
  253. node.dispatchEvent( new Event( 'test2' ) );
  254. expect( proxyEmitter ).to.not.be.equal( proxyEmitter2 );
  255. sinon.assert.calledOnce( spy1a );
  256. sinon.assert.calledOnce( spy1b );
  257. sinon.assert.calledOnce( spy1c );
  258. sinon.assert.calledOnce( spy1d );
  259. sinon.assert.calledTwice( spy2 );
  260. sinon.assert.calledTwice( spy3 );
  261. } );
  262. // #187
  263. it( 'should work for DOM Nodes belonging to another window', () => {
  264. const spy = testUtils.sinon.spy();
  265. const iframe = document.createElement( 'iframe' );
  266. document.body.appendChild( iframe );
  267. const iframeNode = iframe.contentWindow.document.createElement( 'div' );
  268. domEmitter.listenTo( iframeNode, 'test', spy );
  269. iframeNode.dispatchEvent( new Event( 'test' ) );
  270. domEmitter.stopListening( iframeNode );
  271. iframeNode.dispatchEvent( new Event( 'test' ) );
  272. sinon.assert.calledOnce( spy );
  273. } );
  274. } );