emittermixin.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /**
  6. * @module utils/emittermixin
  7. */
  8. import EventInfo from './eventinfo';
  9. import uid from './uid';
  10. import priorities from './priorities';
  11. // To check if component is loaded more than once.
  12. import './version';
  13. import CKEditorError from './ckeditorerror';
  14. const _listeningTo = Symbol( 'listeningTo' );
  15. const _emitterId = Symbol( 'emitterId' );
  16. /**
  17. * Mixin that injects the {@link ~Emitter events API} into its host.
  18. *
  19. * @mixin EmitterMixin
  20. * @implements module:utils/emittermixin~Emitter
  21. */
  22. const EmitterMixin = {
  23. /**
  24. * @inheritDoc
  25. */
  26. on( event, callback, options = {} ) {
  27. this.listenTo( this, event, callback, options );
  28. },
  29. /**
  30. * @inheritDoc
  31. */
  32. once( event, callback, options ) {
  33. let wasFired = false;
  34. const onceCallback = function( event, ...args ) {
  35. // Ensure the callback is called only once even if the callback itself leads to re-firing the event
  36. // (which would call the callback again).
  37. if ( !wasFired ) {
  38. wasFired = true;
  39. // Go off() at the first call.
  40. event.off();
  41. // Go with the original callback.
  42. callback.call( this, event, ...args );
  43. }
  44. };
  45. // Make a similar on() call, simply replacing the callback.
  46. this.listenTo( this, event, onceCallback, options );
  47. },
  48. /**
  49. * @inheritDoc
  50. */
  51. off( event, callback ) {
  52. this.stopListening( this, event, callback );
  53. },
  54. /**
  55. * @inheritDoc
  56. */
  57. listenTo( emitter, event, callback, options = {} ) {
  58. let emitterInfo, eventCallbacks;
  59. // _listeningTo contains a list of emitters that this object is listening to.
  60. // This list has the following format:
  61. //
  62. // _listeningTo: {
  63. // emitterId: {
  64. // emitter: emitter,
  65. // callbacks: {
  66. // event1: [ callback1, callback2, ... ]
  67. // ....
  68. // }
  69. // },
  70. // ...
  71. // }
  72. if ( !this[ _listeningTo ] ) {
  73. this[ _listeningTo ] = {};
  74. }
  75. const emitters = this[ _listeningTo ];
  76. if ( !_getEmitterId( emitter ) ) {
  77. _setEmitterId( emitter );
  78. }
  79. const emitterId = _getEmitterId( emitter );
  80. if ( !( emitterInfo = emitters[ emitterId ] ) ) {
  81. emitterInfo = emitters[ emitterId ] = {
  82. emitter,
  83. callbacks: {}
  84. };
  85. }
  86. if ( !( eventCallbacks = emitterInfo.callbacks[ event ] ) ) {
  87. eventCallbacks = emitterInfo.callbacks[ event ] = [];
  88. }
  89. eventCallbacks.push( callback );
  90. // Finally register the callback to the event.
  91. createEventNamespace( emitter, event );
  92. const lists = getCallbacksListsForNamespace( emitter, event );
  93. const priority = priorities.get( options.priority );
  94. const callbackDefinition = {
  95. callback,
  96. priority
  97. };
  98. // Add the callback to all callbacks list.
  99. for ( const callbacks of lists ) {
  100. // Add the callback to the list in the right priority position.
  101. let added = false;
  102. for ( let i = 0; i < callbacks.length; i++ ) {
  103. if ( callbacks[ i ].priority < priority ) {
  104. callbacks.splice( i, 0, callbackDefinition );
  105. added = true;
  106. break;
  107. }
  108. }
  109. // Add at the end, if right place was not found.
  110. if ( !added ) {
  111. callbacks.push( callbackDefinition );
  112. }
  113. }
  114. },
  115. /**
  116. * @inheritDoc
  117. */
  118. stopListening( emitter, event, callback ) {
  119. const emitters = this[ _listeningTo ];
  120. let emitterId = emitter && _getEmitterId( emitter );
  121. const emitterInfo = emitters && emitterId && emitters[ emitterId ];
  122. const eventCallbacks = emitterInfo && event && emitterInfo.callbacks[ event ];
  123. // Stop if nothing has been listened.
  124. if ( !emitters || ( emitter && !emitterInfo ) || ( event && !eventCallbacks ) ) {
  125. return;
  126. }
  127. // All params provided. off() that single callback.
  128. if ( callback ) {
  129. removeCallback( emitter, event, callback );
  130. }
  131. // Only `emitter` and `event` provided. off() all callbacks for that event.
  132. else if ( eventCallbacks ) {
  133. while ( ( callback = eventCallbacks.pop() ) ) {
  134. removeCallback( emitter, event, callback );
  135. }
  136. delete emitterInfo.callbacks[ event ];
  137. }
  138. // Only `emitter` provided. off() all events for that emitter.
  139. else if ( emitterInfo ) {
  140. for ( event in emitterInfo.callbacks ) {
  141. this.stopListening( emitter, event );
  142. }
  143. delete emitters[ emitterId ];
  144. }
  145. // No params provided. off() all emitters.
  146. else {
  147. for ( emitterId in emitters ) {
  148. this.stopListening( emitters[ emitterId ].emitter );
  149. }
  150. delete this[ _listeningTo ];
  151. }
  152. },
  153. /**
  154. * @inheritDoc
  155. */
  156. fire( eventOrInfo, ...args ) {
  157. try {
  158. const eventInfo = eventOrInfo instanceof EventInfo ? eventOrInfo : new EventInfo( this, eventOrInfo );
  159. const event = eventInfo.name;
  160. let callbacks = getCallbacksForEvent( this, event );
  161. // Record that the event passed this emitter on its path.
  162. eventInfo.path.push( this );
  163. // Handle event listener callbacks first.
  164. if ( callbacks ) {
  165. // Arguments passed to each callback.
  166. const callbackArgs = [ eventInfo, ...args ];
  167. // Copying callbacks array is the easiest and most secure way of preventing infinite loops, when event callbacks
  168. // are added while processing other callbacks. Previous solution involved adding counters (unique ids) but
  169. // failed if callbacks were added to the queue before currently processed callback.
  170. // If this proves to be too inefficient, another method is to change `.on()` so callbacks are stored if same
  171. // event is currently processed. Then, `.fire()` at the end, would have to add all stored events.
  172. callbacks = Array.from( callbacks );
  173. for ( let i = 0; i < callbacks.length; i++ ) {
  174. callbacks[ i ].callback.apply( this, callbackArgs );
  175. // Remove the callback from future requests if off() has been called.
  176. if ( eventInfo.off.called ) {
  177. // Remove the called mark for the next calls.
  178. delete eventInfo.off.called;
  179. removeCallback( this, event, callbacks[ i ].callback );
  180. }
  181. // Do not execute next callbacks if stop() was called.
  182. if ( eventInfo.stop.called ) {
  183. break;
  184. }
  185. }
  186. }
  187. // Delegate event to other emitters if needed.
  188. if ( this._delegations ) {
  189. const destinations = this._delegations.get( event );
  190. const passAllDestinations = this._delegations.get( '*' );
  191. if ( destinations ) {
  192. fireDelegatedEvents( destinations, eventInfo, args );
  193. }
  194. if ( passAllDestinations ) {
  195. fireDelegatedEvents( passAllDestinations, eventInfo, args );
  196. }
  197. }
  198. return eventInfo.return;
  199. } catch ( err ) {
  200. // @if CK_DEBUG // throw err;
  201. /* istanbul ignore next */
  202. CKEditorError.rethrowUnexpectedError( err, this );
  203. }
  204. },
  205. /**
  206. * @inheritDoc
  207. */
  208. delegate( ...events ) {
  209. return {
  210. to: ( emitter, nameOrFunction ) => {
  211. if ( !this._delegations ) {
  212. this._delegations = new Map();
  213. }
  214. // Originally there was a for..of loop which unfortunately caused an error in Babel that didn't allow
  215. // build an application. See: https://github.com/ckeditor/ckeditor5-react/issues/40.
  216. events.forEach( eventName => {
  217. const destinations = this._delegations.get( eventName );
  218. if ( !destinations ) {
  219. this._delegations.set( eventName, new Map( [ [ emitter, nameOrFunction ] ] ) );
  220. } else {
  221. destinations.set( emitter, nameOrFunction );
  222. }
  223. } );
  224. }
  225. };
  226. },
  227. /**
  228. * @inheritDoc
  229. */
  230. stopDelegating( event, emitter ) {
  231. if ( !this._delegations ) {
  232. return;
  233. }
  234. if ( !event ) {
  235. this._delegations.clear();
  236. } else if ( !emitter ) {
  237. this._delegations.delete( event );
  238. } else {
  239. const destinations = this._delegations.get( event );
  240. if ( destinations ) {
  241. destinations.delete( emitter );
  242. }
  243. }
  244. }
  245. };
  246. export default EmitterMixin;
  247. /**
  248. * Emitter/listener interface.
  249. *
  250. * Can be easily implemented by a class by mixing the {@link module:utils/emittermixin~EmitterMixin} mixin.
  251. *
  252. * @interface Emitter
  253. */
  254. /**
  255. * Registers a callback function to be executed when an event is fired.
  256. *
  257. * Shorthand for {@link #listenTo `this.listenTo( this, event, callback, options )`} (it makes the emitter
  258. * listen on itself).
  259. *
  260. * @method #on
  261. * @param {String} event The name of the event.
  262. * @param {Function} callback The function to be called on event.
  263. * @param {Object} [options={}] Additional options.
  264. * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher
  265. * the priority value the sooner the callback will be fired. Events having the same priority are called in the
  266. * order they were added.
  267. */
  268. /**
  269. * Registers a callback function to be executed on the next time the event is fired only. This is similar to
  270. * calling {@link #on} followed by {@link #off} in the callback.
  271. *
  272. * @method #once
  273. * @param {String} event The name of the event.
  274. * @param {Function} callback The function to be called on event.
  275. * @param {Object} [options={}] Additional options.
  276. * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher
  277. * the priority value the sooner the callback will be fired. Events having the same priority are called in the
  278. * order they were added.
  279. */
  280. /**
  281. * Stops executing the callback on the given event.
  282. * Shorthand for {@link #stopListening `this.stopListening( this, event, callback )`}.
  283. *
  284. * @method #off
  285. * @param {String} event The name of the event.
  286. * @param {Function} callback The function to stop being called.
  287. */
  288. /**
  289. * Registers a callback function to be executed when an event is fired in a specific (emitter) object.
  290. *
  291. * Events can be grouped in namespaces using `:`.
  292. * When namespaced event is fired, it additionally fires all callbacks for that namespace.
  293. *
  294. * // myEmitter.on( ... ) is a shorthand for myEmitter.listenTo( myEmitter, ... ).
  295. * myEmitter.on( 'myGroup', genericCallback );
  296. * myEmitter.on( 'myGroup:myEvent', specificCallback );
  297. *
  298. * // genericCallback is fired.
  299. * myEmitter.fire( 'myGroup' );
  300. * // both genericCallback and specificCallback are fired.
  301. * myEmitter.fire( 'myGroup:myEvent' );
  302. * // genericCallback is fired even though there are no callbacks for "foo".
  303. * myEmitter.fire( 'myGroup:foo' );
  304. *
  305. * An event callback can {@link module:utils/eventinfo~EventInfo#stop stop the event} and
  306. * set the {@link module:utils/eventinfo~EventInfo#return return value} of the {@link #fire} method.
  307. *
  308. * @method #listenTo
  309. * @param {module:utils/emittermixin~Emitter} emitter The object that fires the event.
  310. * @param {String} event The name of the event.
  311. * @param {Function} callback The function to be called on event.
  312. * @param {Object} [options={}] Additional options.
  313. * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher
  314. * the priority value the sooner the callback will be fired. Events having the same priority are called in the
  315. * order they were added.
  316. */
  317. /**
  318. * Stops listening for events. It can be used at different levels:
  319. *
  320. * * To stop listening to a specific callback.
  321. * * To stop listening to a specific event.
  322. * * To stop listening to all events fired by a specific object.
  323. * * To stop listening to all events fired by all objects.
  324. *
  325. * @method #stopListening
  326. * @param {module:utils/emittermixin~Emitter} [emitter] The object to stop listening to. If omitted, stops it for all objects.
  327. * @param {String} [event] (Requires the `emitter`) The name of the event to stop listening to. If omitted, stops it
  328. * for all events from `emitter`.
  329. * @param {Function} [callback] (Requires the `event`) The function to be removed from the call list for the given
  330. * `event`.
  331. */
  332. /**
  333. * Fires an event, executing all callbacks registered for it.
  334. *
  335. * The first parameter passed to callbacks is an {@link module:utils/eventinfo~EventInfo} object,
  336. * followed by the optional `args` provided in the `fire()` method call.
  337. *
  338. * @method #fire
  339. * @param {String|module:utils/eventinfo~EventInfo} eventOrInfo The name of the event or `EventInfo` object if event is delegated.
  340. * @param {...*} [args] Additional arguments to be passed to the callbacks.
  341. * @returns {*} By default the method returns `undefined`. However, the return value can be changed by listeners
  342. * through modification of the {@link module:utils/eventinfo~EventInfo#return `evt.return`}'s property (the event info
  343. * is the first param of every callback).
  344. */
  345. /**
  346. * Delegates selected events to another {@link module:utils/emittermixin~Emitter}. For instance:
  347. *
  348. * emitterA.delegate( 'eventX' ).to( emitterB );
  349. * emitterA.delegate( 'eventX', 'eventY' ).to( emitterC );
  350. *
  351. * then `eventX` is delegated (fired by) `emitterB` and `emitterC` along with `data`:
  352. *
  353. * emitterA.fire( 'eventX', data );
  354. *
  355. * and `eventY` is delegated (fired by) `emitterC` along with `data`:
  356. *
  357. * emitterA.fire( 'eventY', data );
  358. *
  359. * @method #delegate
  360. * @param {...String} events Event names that will be delegated to another emitter.
  361. * @returns {module:utils/emittermixin~EmitterMixinDelegateChain}
  362. */
  363. /**
  364. * Stops delegating events. It can be used at different levels:
  365. *
  366. * * To stop delegating all events.
  367. * * To stop delegating a specific event to all emitters.
  368. * * To stop delegating a specific event to a specific emitter.
  369. *
  370. * @method #stopDelegating
  371. * @param {String} [event] The name of the event to stop delegating. If omitted, stops it all delegations.
  372. * @param {module:utils/emittermixin~Emitter} [emitter] (requires `event`) The object to stop delegating a particular event to.
  373. * If omitted, stops delegation of `event` to all emitters.
  374. */
  375. /**
  376. * Checks if `listeningEmitter` listens to an emitter with given `listenedToEmitterId` and if so, returns that emitter.
  377. * If not, returns `null`.
  378. *
  379. * @protected
  380. * @param {module:utils/emittermixin~Emitter} listeningEmitter An emitter that listens.
  381. * @param {String} listenedToEmitterId Unique emitter id of emitter listened to.
  382. * @returns {module:utils/emittermixin~Emitter|null}
  383. */
  384. export function _getEmitterListenedTo( listeningEmitter, listenedToEmitterId ) {
  385. if ( listeningEmitter[ _listeningTo ] && listeningEmitter[ _listeningTo ][ listenedToEmitterId ] ) {
  386. return listeningEmitter[ _listeningTo ][ listenedToEmitterId ].emitter;
  387. }
  388. return null;
  389. }
  390. /**
  391. * Sets emitter's unique id.
  392. *
  393. * **Note:** `_emitterId` can be set only once.
  394. *
  395. * @protected
  396. * @param {module:utils/emittermixin~Emitter} emitter An emitter for which id will be set.
  397. * @param {String} [id] Unique id to set. If not passed, random unique id will be set.
  398. */
  399. export function _setEmitterId( emitter, id ) {
  400. if ( !emitter[ _emitterId ] ) {
  401. emitter[ _emitterId ] = id || uid();
  402. }
  403. }
  404. /**
  405. * Returns emitter's unique id.
  406. *
  407. * @protected
  408. * @param {module:utils/emittermixin~Emitter} emitter An emitter which id will be returned.
  409. */
  410. export function _getEmitterId( emitter ) {
  411. return emitter[ _emitterId ];
  412. }
  413. // Gets the internal `_events` property of the given object.
  414. // `_events` property store all lists with callbacks for registered event names.
  415. // If there were no events registered on the object, empty `_events` object is created.
  416. function getEvents( source ) {
  417. if ( !source._events ) {
  418. Object.defineProperty( source, '_events', {
  419. value: {}
  420. } );
  421. }
  422. return source._events;
  423. }
  424. // Creates event node for generic-specific events relation architecture.
  425. function makeEventNode() {
  426. return {
  427. callbacks: [],
  428. childEvents: []
  429. };
  430. }
  431. // Creates an architecture for generic-specific events relation.
  432. // If needed, creates all events for given eventName, i.e. if the first registered event
  433. // is foo:bar:abc, it will create foo:bar:abc, foo:bar and foo event and tie them together.
  434. // It also copies callbacks from more generic events to more specific events when
  435. // specific events are created.
  436. function createEventNamespace( source, eventName ) {
  437. const events = getEvents( source );
  438. // First, check if the event we want to add to the structure already exists.
  439. if ( events[ eventName ] ) {
  440. // If it exists, we don't have to do anything.
  441. return;
  442. }
  443. // In other case, we have to create the structure for the event.
  444. // Note, that we might need to create intermediate events too.
  445. // I.e. if foo:bar:abc is being registered and we only have foo in the structure,
  446. // we need to also register foo:bar.
  447. // Currently processed event name.
  448. let name = eventName;
  449. // Name of the event that is a child event for currently processed event.
  450. let childEventName = null;
  451. // Array containing all newly created specific events.
  452. const newEventNodes = [];
  453. // While loop can't check for ':' index because we have to handle generic events too.
  454. // In each loop, we truncate event name, going from the most specific name to the generic one.
  455. // I.e. foo:bar:abc -> foo:bar -> foo.
  456. while ( name !== '' ) {
  457. if ( events[ name ] ) {
  458. // If the currently processed event name is already registered, we can be sure
  459. // that it already has all the structure created, so we can break the loop here
  460. // as no more events need to be registered.
  461. break;
  462. }
  463. // If this event is not yet registered, create a new object for it.
  464. events[ name ] = makeEventNode();
  465. // Add it to the array with newly created events.
  466. newEventNodes.push( events[ name ] );
  467. // Add previously processed event name as a child of this event.
  468. if ( childEventName ) {
  469. events[ name ].childEvents.push( childEventName );
  470. }
  471. childEventName = name;
  472. // If `.lastIndexOf()` returns -1, `.substr()` will return '' which will break the loop.
  473. name = name.substr( 0, name.lastIndexOf( ':' ) );
  474. }
  475. if ( name !== '' ) {
  476. // If name is not empty, we found an already registered event that was a parent of the
  477. // event we wanted to register.
  478. // Copy that event's callbacks to newly registered events.
  479. for ( const node of newEventNodes ) {
  480. node.callbacks = events[ name ].callbacks.slice();
  481. }
  482. // Add last newly created event to the already registered event.
  483. events[ name ].childEvents.push( childEventName );
  484. }
  485. }
  486. // Gets an array containing callbacks list for a given event and it's more specific events.
  487. // I.e. if given event is foo:bar and there is also foo:bar:abc event registered, this will
  488. // return callback list of foo:bar and foo:bar:abc (but not foo).
  489. function getCallbacksListsForNamespace( source, eventName ) {
  490. const eventNode = getEvents( source )[ eventName ];
  491. if ( !eventNode ) {
  492. return [];
  493. }
  494. let callbacksLists = [ eventNode.callbacks ];
  495. for ( let i = 0; i < eventNode.childEvents.length; i++ ) {
  496. const childCallbacksLists = getCallbacksListsForNamespace( source, eventNode.childEvents[ i ] );
  497. callbacksLists = callbacksLists.concat( childCallbacksLists );
  498. }
  499. return callbacksLists;
  500. }
  501. // Get the list of callbacks for a given event, but only if there any callbacks have been registered.
  502. // If there are no callbacks registered for given event, it checks if this is a specific event and looks
  503. // for callbacks for it's more generic version.
  504. function getCallbacksForEvent( source, eventName ) {
  505. let event;
  506. if ( !source._events || !( event = source._events[ eventName ] ) || !event.callbacks.length ) {
  507. // There are no callbacks registered for specified eventName.
  508. // But this could be a specific-type event that is in a namespace.
  509. if ( eventName.indexOf( ':' ) > -1 ) {
  510. // If the eventName is specific, try to find callback lists for more generic event.
  511. return getCallbacksForEvent( source, eventName.substr( 0, eventName.lastIndexOf( ':' ) ) );
  512. } else {
  513. // If this is a top-level generic event, return null;
  514. return null;
  515. }
  516. }
  517. return event.callbacks;
  518. }
  519. // Fires delegated events for given map of destinations.
  520. //
  521. // @private
  522. // * @param {Map.<utils.Emitter>} destinations A map containing
  523. // `[ {@link module:utils/emittermixin~Emitter}, "event name" ]` pair destinations.
  524. // * @param {utils.EventInfo} eventInfo The original event info object.
  525. // * @param {Array.<*>} fireArgs Arguments the original event was fired with.
  526. function fireDelegatedEvents( destinations, eventInfo, fireArgs ) {
  527. for ( let [ emitter, name ] of destinations ) {
  528. if ( !name ) {
  529. name = eventInfo.name;
  530. } else if ( typeof name == 'function' ) {
  531. name = name( eventInfo.name );
  532. }
  533. const delegatedInfo = new EventInfo( eventInfo.source, name );
  534. delegatedInfo.path = [ ...eventInfo.path ];
  535. emitter.fire( delegatedInfo, ...fireArgs );
  536. }
  537. }
  538. // Removes callback from emitter for given event.
  539. //
  540. // @param {module:utils/emittermixin~Emitter} emitter
  541. // @param {String} event
  542. // @param {Function} callback
  543. function removeCallback( emitter, event, callback ) {
  544. const lists = getCallbacksListsForNamespace( emitter, event );
  545. for ( const callbacks of lists ) {
  546. for ( let i = 0; i < callbacks.length; i++ ) {
  547. if ( callbacks[ i ].callback == callback ) {
  548. // Remove the callback from the list (fixing the next index).
  549. callbacks.splice( i, 1 );
  550. i--;
  551. }
  552. }
  553. }
  554. }
  555. /**
  556. * The return value of {@link ~EmitterMixin#delegate}.
  557. *
  558. * @interface module:utils/emittermixin~EmitterMixinDelegateChain
  559. */
  560. /**
  561. * Selects destination for {@link module:utils/emittermixin~EmitterMixin#delegate} events.
  562. *
  563. * @method #to
  564. * @param {module:utils/emittermixin~Emitter} emitter An `EmitterMixin` instance which is the destination for delegated events.
  565. * @param {String|Function} [nameOrFunction] A custom event name or function which converts the original name string.
  566. */