UNPKG

6.54 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true
5});
6exports.getActionDef = getActionDef;
7exports.create = create;
8exports.createMany = createMany;
9exports['default'] = Actions;
10
11function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
12
13var _stampit = require('stampit');
14
15var _stampit2 = _interopRequireDefault(_stampit);
16
17var _warning = require('warning');
18
19var _warning2 = _interopRequireDefault(_warning);
20
21var _debug = require('debug');
22
23var _debug2 = _interopRequireDefault(_debug);
24
25var _rx = require('rx');
26
27var _waitFor = require('./waitFor');
28
29var _waitFor2 = _interopRequireDefault(_waitFor);
30
31var __DEV__ = process.env.NODE_ENV !== 'production';
32var checkDisposed = _rx.Disposable.checkDisposed;
33
34var assign = Object.assign;
35var debug = (0, _debug2['default'])('thundercats:actions');
36var currentStampSpec = ['methods', 'statics', 'props', 'refs', 'init', 'compose', 'create', 'isStamp'];
37
38var protectedProperties = ['shouldBindMethods', 'displayName', 'constructor'].join(currentStampSpec);
39
40function getActionDef(ctx) {
41 return Object.getOwnPropertyNames(ctx).filter(function (name) {
42 return protectedProperties.indexOf(name) === -1 && name.indexOf('_') === -1;
43 }).map(function (name) {
44 return { name: name, map: ctx[name] };
45 }).map(function (def) {
46 if (typeof def.map !== 'function') {
47 def.map = _rx.helpers.identity;
48 }
49 return def;
50 });
51}
52
53function create(shouldBind, _ref) {
54 var name = _ref.name;
55 var map = _ref.map;
56
57 var observers = [];
58 var actionDisposable = new _rx.CompositeDisposable();
59 var actionStart = new _rx.Subject();
60 var actionEnd = new _rx.Subject();
61 var maybeBound = shouldBind ? map.bind(this) : map;
62
63 function action(value) {
64 // throw if disposed observable is retried
65 checkDisposed(action);
66 if (action.isStopped) {
67 debug('%s called after being stopped', name);
68 return value;
69 }
70
71 // NOTE: if an error is thrown in the mapping function
72 // this will cause the stream to collapse
73 // and the action will no longer be observable
74 // nor will the observers listen as they have been stopped by
75 // the error
76 var mapDisposable = _rx.Observable.just(value).map(maybeBound).flatMap(function (value) {
77 if (_rx.Observable.isObservable(value)) {
78 return value;
79 }
80 return _rx.Observable.just(value);
81 })
82 // notify of action start
83 ['do'](function (value) {
84 return actionStart.onNext(value);
85 })
86 // notify action observers
87 .doOnNext(function (value) {
88 return observers.forEach(function (observer) {
89 return observer.onNext(value);
90 });
91 }).doOnCompleted(function () {
92 return actionEnd.onNext();
93 }).subscribe(function () {
94 return debug('%s onNext', name);
95 }, function (err) {
96 // observables returned by the mapping function must use
97 // a catch to prevent the action from collapsing the stream
98 action.error = err;
99 action.isStopped = true;
100 action.hasError = true;
101
102 // notify action observers of error
103 observers.forEach(function (observer) {
104 return observer.onError(err);
105 });
106 // observers will no longer listen after pushing error
107 // as the stream has collapsed
108 // so we remove them
109 observers.length = 0;
110 });
111
112 actionDisposable.add(mapDisposable);
113 return value;
114 }
115
116 action.isDisposed = false;
117 action.isStopped = false;
118 action.displayName = name;
119 action.observers = observers;
120 assign(action, _rx.Observable.prototype);
121
122 action.hasObservers = function hasObservers() {
123 // in next major version this should throw if already disposed
124 // in order to better follow RxJS conventions
125 //
126 // checkDisposed(action);
127
128 return !!(observers.length > 0 || actionStart.observers && actionStart.observers.length > 0);
129 };
130
131 action.waitFor = function () {
132 var _arguments = arguments;
133
134 /* istanbul ignore else */
135 if (__DEV__) {
136 (0, _warning2['default'])(false, 'action.waitFor is deprecated and will be removed in ' + 'the next version of thundercats');
137 }
138 return actionStart.flatMap(function (payload) {
139 return _waitFor2['default'].apply(undefined, _arguments).map(function () {
140 return payload;
141 });
142 });
143 };
144
145 // NOTE: not public API. May change or be removed at any time
146 action.__duration = function __duration() {
147 return actionStart.flatMap(actionEnd).first();
148 };
149
150 action._subscribe = function subscribeToAction(observer) {
151 // in next major version this should check if action
152 // has been stopped or disposed and act accordingly
153 observers.push(observer);
154 return new _rx.Disposable(function () {
155 observers.splice(observers.indexOf(observer), 1);
156 });
157 };
158
159 var subscription = new _rx.Disposable(function () {
160 observers.length = 0;
161 action.isDisposed = true;
162 actionStart.dispose();
163 actionDisposable.dispose();
164 });
165
166 action.dispose = function () {
167 return subscription.dispose();
168 };
169
170 _rx.Observable.call(action);
171
172 debug('%s created', action.displayName);
173 return {
174 action: action,
175 subscription: subscription
176 };
177}
178
179function createMany(shouldBind, instance, compositeDisposable) {
180 return this.map(create.bind(instance, shouldBind)).reduce(function (ctx, _ref2) {
181 var action = _ref2.action;
182 var subscription = _ref2.subscription;
183
184 compositeDisposable.add(subscription);
185 ctx[action.displayName] = action;
186 return ctx;
187 }, {});
188}
189
190function Actions() {
191 var obj = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
192 var shouldBind = obj.shouldBindMethods;
193 var _obj$init = obj.init;
194 var init = _obj$init === undefined ? [] : _obj$init;
195 var _obj$props = obj.props;
196 var props = _obj$props === undefined ? {} : _obj$props;
197 var _obj$refs = obj.refs;
198 var refs = _obj$refs === undefined ? {} : _obj$refs;
199 var _obj$statics = obj.statics;
200 var statics = _obj$statics === undefined ? {} : _obj$statics;
201
202 return (0, _stampit2['default'])().init(function (_ref3) {
203 var _context;
204
205 var instance = _ref3.instance;
206
207 var actionsDisposable = new _rx.CompositeDisposable();
208 var actionMethods = (_context = getActionDef(obj), createMany).call(_context, shouldBind, instance, actionsDisposable);
209
210 return assign(instance, actionMethods, { dispose: function dispose() {
211 actionsDisposable.dispose();
212 } });
213 }).refs(refs).props(props)['static'](statics).init(init);
214}
\No newline at end of file