Source: dependencies/resource-loader/node_modules/mini-signals/src/mini-signals.js

dependencies/resource-loader/node_modules/mini-signals/src/mini-signals.js

  1. /* jshint -W097 */
  2. export class MiniSignalBinding {
  3. /**
  4. * MiniSignalBinding constructor.
  5. * @constructs MiniSignalBinding
  6. * @param {Function} fn Event handler to be called.
  7. * @param {Boolean} [once=false] Should this listener be removed after dispatch
  8. * @param {Mixed} [thisArg] The context of the callback function.
  9. * @api private
  10. */
  11. constructor (fn, once = false, thisArg) {
  12. this._fn = fn;
  13. this._once = once;
  14. this._thisArg = thisArg;
  15. this._next = this._prev = this._owner = null;
  16. }
  17. detach () {
  18. if (this._owner === null) return false;
  19. this._owner.detach(this);
  20. return true;
  21. }
  22. }
  23. /**
  24. * @private
  25. */
  26. function _addMiniSignalBinding (self, node) {
  27. if (!self._head) {
  28. self._head = node;
  29. self._tail = node;
  30. } else {
  31. self._tail._next = node;
  32. node._prev = self._tail;
  33. self._tail = node;
  34. }
  35. node._owner = self;
  36. return node;
  37. }
  38. export class MiniSignal {
  39. /**
  40. * MiniSignal constructor.
  41. * @constructs MiniSignal
  42. * @api public
  43. *
  44. * @example
  45. * let mySignal = new MiniSignal();
  46. * let binding = mySignal.add(onSignal);
  47. * mySignal.dispatch('foo', 'bar');
  48. * mySignal.detach(binding);
  49. */
  50. constructor () {
  51. this._head = this._tail = undefined;
  52. }
  53. /**
  54. * Return an array of attached MiniSignalBinding.
  55. *
  56. * @param {Boolean} [exists=false] We only need to know if there are handlers.
  57. * @returns {MiniSignalBinding[]|Boolean} Array of attached MiniSignalBinding or Boolean if called with exists = true
  58. * @api public
  59. */
  60. handlers (exists = false) {
  61. let node = this._head;
  62. if (exists) return !!node;
  63. const ee = [];
  64. while (node) {
  65. ee.push(node);
  66. node = node._next;
  67. }
  68. return ee;
  69. }
  70. /**
  71. * Return true if node is a MiniSignalBinding attached to this MiniSignal
  72. *
  73. * @param {MiniSignalBinding} node Node to check.
  74. * @returns {Boolean} True if node is attache to mini-signal
  75. * @api public
  76. */
  77. has (node) {
  78. if (!(node instanceof MiniSignalBinding)) {
  79. throw new Error('MiniSignal#has(): First arg must be a MiniSignalBinding object.');
  80. }
  81. return node._owner === this;
  82. }
  83. /**
  84. * Dispaches a signal to all registered listeners.
  85. *
  86. * @returns {Boolean} Indication if we've emitted an event.
  87. * @api public
  88. */
  89. dispatch () {
  90. let node = this._head;
  91. if (!node) return false;
  92. while (node) {
  93. if (node._once) this.detach(node);
  94. node._fn.apply(node._thisArg, arguments);
  95. node = node._next;
  96. }
  97. return true;
  98. }
  99. /**
  100. * Register a new listener.
  101. *
  102. * @param {Function} fn Callback function.
  103. * @param {Mixed} [thisArg] The context of the callback function.
  104. * @returns {MiniSignalBinding} The MiniSignalBinding node that was added.
  105. * @api public
  106. */
  107. add (fn, thisArg = null) {
  108. if (typeof fn !== 'function') {
  109. throw new Error('MiniSignal#add(): First arg must be a Function.');
  110. }
  111. return _addMiniSignalBinding(this, new MiniSignalBinding(fn, false, thisArg));
  112. }
  113. /**
  114. * Register a new listener that will be executed only once.
  115. *
  116. * @param {Function} fn Callback function.
  117. * @param {Mixed} [thisArg] The context of the callback function.
  118. * @returns {MiniSignalBinding} The MiniSignalBinding node that was added.
  119. * @api public
  120. */
  121. once (fn, thisArg = null) {
  122. if (typeof fn !== 'function') {
  123. throw new Error('MiniSignal#once(): First arg must be a Function.');
  124. }
  125. return _addMiniSignalBinding(this, new MiniSignalBinding(fn, true, thisArg));
  126. }
  127. /**
  128. * Remove binding object.
  129. *
  130. * @param {MiniSignalBinding} node The binding node that will be removed.
  131. * @returns {MiniSignal} The instance on which this method was called.
  132. * @api public */
  133. detach (node) {
  134. if (!(node instanceof MiniSignalBinding)) {
  135. throw new Error('MiniSignal#detach(): First arg must be a MiniSignalBinding object.');
  136. }
  137. if (node._owner !== this) return this; // todo: or error?
  138. if (node._prev) node._prev._next = node._next;
  139. if (node._next) node._next._prev = node._prev;
  140. if (node === this._head) { // first node
  141. this._head = node._next;
  142. if (node._next === null) {
  143. this._tail = null;
  144. }
  145. } else if (node === this._tail) { // last node
  146. this._tail = node._prev;
  147. this._tail._next = null;
  148. }
  149. node._owner = null;
  150. return this;
  151. }
  152. /**
  153. * Detach all listeners.
  154. *
  155. * @returns {MiniSignal} The instance on which this method was called.
  156. * @api public
  157. */
  158. detachAll () {
  159. let node = this._head;
  160. if (!node) return this;
  161. this._head = this._tail = null;
  162. while (node) {
  163. node._owner = null;
  164. node = node._next;
  165. }
  166. return this;
  167. }
  168. }
  169. export default MiniSignal;