signal.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. (function() {
  2. var Behavior, Emitter, Signal, Subscriber, isEqual,
  3. __hasProp = {}.hasOwnProperty,
  4. __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  5. __slice = [].slice;
  6. isEqual = require('underscore-plus').isEqual;
  7. Emitter = require('./emitter');
  8. Subscriber = require('./subscriber');
  9. Behavior = null;
  10. module.exports = Signal = (function(_super) {
  11. __extends(Signal, _super);
  12. Subscriber.includeInto(Signal);
  13. Signal.fromEmitter = function(emitter, eventName) {
  14. return new Signal(function() {
  15. var _this = this;
  16. return this.subscribe(emitter, eventName, function() {
  17. var metadata, value;
  18. value = arguments[0], metadata = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  19. return _this.emitValue.apply(_this, [value].concat(__slice.call(metadata)));
  20. });
  21. });
  22. };
  23. function Signal(subscribeCallback) {
  24. var _this = this;
  25. this.subscribeCallback = subscribeCallback;
  26. this.retainCount = 0;
  27. this.on('value-subscription-will-be-added', function() {
  28. return _this.retain();
  29. });
  30. this.on('value-subscription-removed', function() {
  31. return _this.release();
  32. });
  33. }
  34. Signal.prototype.isSignal = true;
  35. Signal.prototype.retained = function() {
  36. return typeof this.subscribeCallback === "function" ? this.subscribeCallback() : void 0;
  37. };
  38. Signal.prototype.released = function() {
  39. return this.unsubscribe();
  40. };
  41. Signal.prototype.retain = function() {
  42. if (++this.retainCount === 1) {
  43. if (typeof this.retained === "function") {
  44. this.retained();
  45. }
  46. }
  47. return this;
  48. };
  49. Signal.prototype.release = function() {
  50. if (--this.retainCount === 0) {
  51. if (typeof this.released === "function") {
  52. this.released();
  53. }
  54. }
  55. return this;
  56. };
  57. Signal.prototype.onValue = function(handler) {
  58. return this.on('value', handler);
  59. };
  60. Signal.prototype.emitValue = function(value, metadata) {
  61. if (metadata == null) {
  62. metadata = {};
  63. }
  64. if (metadata.source == null) {
  65. metadata.source = this;
  66. }
  67. return this.emit('value', value, metadata);
  68. };
  69. Signal.prototype.toBehavior = function(initialValue) {
  70. var source;
  71. source = this;
  72. return this.buildBehavior(initialValue, function() {
  73. var _this = this;
  74. return this.subscribe(source, 'value', function() {
  75. var metadata, value;
  76. value = arguments[0], metadata = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  77. return _this.emitValue.apply(_this, [value].concat(__slice.call(metadata)));
  78. });
  79. });
  80. };
  81. Signal.prototype.changes = function() {
  82. return this;
  83. };
  84. Signal.prototype.injectMetadata = function(fn) {
  85. var source;
  86. source = this;
  87. return new this.constructor(function() {
  88. var _this = this;
  89. return this.subscribe(source, 'value', function(value, metadata) {
  90. var k, newMetadata, v;
  91. newMetadata = fn(value, metadata);
  92. for (k in newMetadata) {
  93. v = newMetadata[k];
  94. metadata[k] = v;
  95. }
  96. return _this.emitValue(value, metadata);
  97. });
  98. });
  99. };
  100. Signal.prototype.filter = function(predicate) {
  101. var source;
  102. source = this;
  103. return new this.constructor(function() {
  104. var _this = this;
  105. return this.subscribe(source, 'value', function() {
  106. var metadata, value;
  107. value = arguments[0], metadata = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  108. if (predicate.call(value, value)) {
  109. return _this.emitValue.apply(_this, [value].concat(__slice.call(metadata)));
  110. }
  111. });
  112. });
  113. };
  114. Signal.prototype.filterDefined = function() {
  115. return this.filter(function(value) {
  116. return value != null;
  117. });
  118. };
  119. Signal.prototype.map = function(fn) {
  120. var property, source;
  121. if (typeof fn === 'string') {
  122. property = fn;
  123. fn = function(value) {
  124. return value != null ? value[property] : void 0;
  125. };
  126. }
  127. source = this;
  128. return new this.constructor(function() {
  129. var _this = this;
  130. return this.subscribe(source, 'value', function() {
  131. var metadata, value;
  132. value = arguments[0], metadata = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  133. return _this.emitValue.apply(_this, [fn.call(value, value)].concat(__slice.call(metadata)));
  134. });
  135. });
  136. };
  137. Signal.prototype["switch"] = function(fn) {
  138. var source;
  139. source = this.map(fn);
  140. return new this.constructor(function() {
  141. var currentSignal,
  142. _this = this;
  143. currentSignal = null;
  144. return this.subscribe(source, 'value', function(newSignal, outerMetadata) {
  145. if (currentSignal != null) {
  146. _this.unsubscribe(currentSignal);
  147. }
  148. currentSignal = newSignal;
  149. if (currentSignal != null) {
  150. return _this.subscribe(currentSignal, 'value', function(value, innerMetadata) {
  151. return _this.emitValue(value, innerMetadata);
  152. });
  153. } else {
  154. return _this.emitValue(void 0, outerMetadata);
  155. }
  156. });
  157. });
  158. };
  159. Signal.prototype.skipUntil = function(predicateOrTargetValue) {
  160. var doneSkipping, predicate, targetValue;
  161. if (typeof predicateOrTargetValue !== 'function') {
  162. targetValue = predicateOrTargetValue;
  163. return this.skipUntil(function(value) {
  164. return isEqual(value, targetValue);
  165. });
  166. }
  167. predicate = predicateOrTargetValue;
  168. doneSkipping = false;
  169. return this.filter(function(value) {
  170. if (doneSkipping) {
  171. return true;
  172. }
  173. if (predicate(value)) {
  174. return doneSkipping = true;
  175. } else {
  176. return false;
  177. }
  178. });
  179. };
  180. Signal.prototype.scan = function(initialValue, fn) {
  181. var source;
  182. source = this;
  183. return this.buildBehavior(initialValue, function() {
  184. var oldValue,
  185. _this = this;
  186. oldValue = initialValue;
  187. return this.subscribe(source, 'value', function() {
  188. var metadata, newValue;
  189. newValue = arguments[0], metadata = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  190. return _this.emitValue.apply(_this, [(oldValue = fn(oldValue, newValue))].concat(__slice.call(metadata)));
  191. });
  192. });
  193. };
  194. Signal.prototype.diff = function(initialValue, fn) {
  195. var source;
  196. source = this;
  197. return this.buildBehavior(function() {
  198. var oldValue,
  199. _this = this;
  200. oldValue = initialValue;
  201. return this.subscribe(source, 'value', function() {
  202. var fnOldValue, metadata, newValue;
  203. newValue = arguments[0], metadata = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  204. fnOldValue = oldValue;
  205. oldValue = newValue;
  206. return _this.emitValue.apply(_this, [fn(fnOldValue, newValue)].concat(__slice.call(metadata)));
  207. });
  208. });
  209. };
  210. Signal.prototype.distinctUntilChanged = function() {
  211. var source;
  212. source = this;
  213. return new this.constructor(function() {
  214. var oldValue, receivedValue,
  215. _this = this;
  216. receivedValue = false;
  217. oldValue = void 0;
  218. return this.subscribe(source, 'value', function() {
  219. var metadata, newValue;
  220. newValue = arguments[0], metadata = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  221. if (receivedValue) {
  222. if (isEqual(oldValue, newValue)) {
  223. return oldValue = newValue;
  224. } else {
  225. oldValue = newValue;
  226. return _this.emitValue.apply(_this, [newValue].concat(__slice.call(metadata)));
  227. }
  228. } else {
  229. receivedValue = true;
  230. oldValue = newValue;
  231. return _this.emitValue.apply(_this, [newValue].concat(__slice.call(metadata)));
  232. }
  233. });
  234. });
  235. };
  236. Signal.prototype.equals = function(expected) {
  237. return this.map(function(actual) {
  238. return isEqual(actual, expected);
  239. }).distinctUntilChanged();
  240. };
  241. Signal.prototype.isDefined = function() {
  242. return this.map(function(value) {
  243. return value != null;
  244. }).distinctUntilChanged();
  245. };
  246. Signal.prototype.buildBehavior = function() {
  247. var args;
  248. args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  249. if (Behavior == null) {
  250. Behavior = require('./behavior');
  251. }
  252. return (function(func, args, ctor) {
  253. ctor.prototype = func.prototype;
  254. var child = new ctor, result = func.apply(child, args);
  255. return Object(result) === result ? result : child;
  256. })(Behavior, args, function(){});
  257. };
  258. return Signal;
  259. })(Emitter);
  260. }).call(this);