Show:
  1. /**
  2. * @module proact-core
  3. */
  4.  
  5. /**
  6. * <p>
  7. * `ProAct.Actor` is the basic observer-observable functionallity in ProAct.js
  8. * </p>
  9. * <p>
  10. * The actors in ProAct.js form the dependency graph.
  11. * If some actor listens to changes from another - it depends on it.
  12. * </p>
  13. * <p>
  14. * The actors can transform the values or events incoming to them.
  15. * </p>
  16. * <p>
  17. * Every actor can have a parent actor, that will be notified for all the changes
  18. * on the child-actor, it is something as special observer.
  19. * </p>
  20. * <p>
  21. * ProAct.Actor is part of the core module of ProAct.js.
  22. System.out.println();
  23. * </p>
  24. *
  25. * @class ProAct.Actor
  26. * @constructor
  27. * @param {String} [queueName]
  28. * The name of the queue all the updates should be pushed to.
  29. * <p>
  30. * If this parameter is null/undefined the default queue of
  31. * {{#crossLink "ProAct/flow:property"}}{{/crossLink}} is used.
  32. * </p>
  33. * <p>
  34. * If this parameter is not a string it is used as the
  35. * <i>transforms</i>.
  36. * </p>
  37. * @param {Array} [transforms]
  38. * A list of transformation to be used on all incoming chages.
  39. */
  40. function Actor (queueName, transforms) {
  41. if (queueName && !P.U.isString(queueName)) {
  42. transforms = queueName;
  43. queueName = null;
  44. }
  45.  
  46. P.U.defValProp(this, 'listeners', false, false, true, this.defaultListeners());
  47.  
  48. P.U.defValProp(this, 'listener', false, false, true, null);
  49. P.U.defValProp(this, 'errListener', false, false, true, null);
  50. P.U.defValProp(this, 'closeListener', false, false, true, null);
  51. P.U.defValProp(this, 'parent', false, false, true, null);
  52.  
  53. P.U.defValProp(this, 'queueName', false, false, false, queueName);
  54. P.U.defValProp(this, 'transforms', false, false, true,
  55. (transforms ? transforms : []));
  56.  
  57. P.U.defValProp(this, 'state', false, false, true, P.States.init);
  58.  
  59. this.init();
  60. }
  61. ProAct.Actor = P.Pro = Actor;
  62.  
  63. P.U.ex(P.Actor, {
  64.  
  65. /**
  66. * A constant defining bad values or bad events.
  67. *
  68. * Part of the filtering mechainsm; If a transformation returns
  69. * a `BadValue`, based on uncomming event -> the event is skipped.
  70. *
  71. * @property BadValue
  72. * @type Object
  73. * @final
  74. * @static
  75. * @for ProAct.Actor
  76. */
  77. BadValue: {},
  78.  
  79. /**
  80. * A constant defining closing or ending events.
  81. *
  82. * If a transformation returns this value, the actor will be closed.
  83. *
  84. * You can manually close `Actor`s updating them with this constant as an event.
  85. *
  86. * @property Close
  87. * @type Object
  88. * @final
  89. * @static
  90. * @for ProAct.Actor
  91. */
  92. Close: {},
  93.  
  94. /**
  95. * Transforms the passed <i>val</i> using the {{#crossLink "ProAct.Actor/transforms:method"}}{{/crossLink}} method of the passed <i>actor</i>.
  96. *
  97. * @method transforms
  98. * @for ProAct.Actor
  99. * @static
  100. * @param {ProAct.Actor} actor The `ProAct.Actor` which transformations should be used.
  101. * @param {Object} val The value to transform.
  102. * @return {Object} The transformed value.
  103. */
  104. transform: function (actor, val) {
  105. var i, t = actor.transforms, ln = t.length;
  106. for (i = 0; i < ln; i++) {
  107. val = t[i].call(actor, val);
  108. if (val === P.Actor.BadValue) {
  109. break;
  110. }
  111.  
  112. if (val === P.Actor.Close) {
  113. break;
  114. }
  115. }
  116.  
  117. return val;
  118. }
  119. });
  120.  
  121. P.Actor.prototype = {
  122.  
  123. /**
  124. * Reference to the constructor of this object.
  125. *
  126. * @property constructor
  127. * @type ProAct.Actor
  128. * @final
  129. * @for ProAct.Actor
  130. */
  131. constructor: ProAct.Actor,
  132.  
  133. /**
  134. * Initializes this actor.
  135. * <p>
  136. * This method logic is run only if the current state of <i>this</i> is
  137. * {{#crossLink "ProAct.States/init:property"}}{{/crossLink}}.
  138. * </p>
  139. * <p>
  140. * Then {{#crossLink "ProAct.Actor/afterInit:method"}}{{/crossLink}} is called to finish the initialization.
  141. * </p>
  142. *
  143. * @for ProAct.Actor
  144. * @instance
  145. * @method init
  146. */
  147. init: function () {
  148. if (this.state !== P.States.init) {
  149. return;
  150. }
  151.  
  152. this.doInit();
  153.  
  154. this.afterInit();
  155. },
  156.  
  157. /**
  158. * Allocating of resources or initializing is done here.
  159. * <p>
  160. * Empty by default.
  161. * </p>
  162. *
  163. * @for ProAct.Actor
  164. * @instance
  165. * @protected
  166. * @method doInit
  167. */
  168. doInit: function () {},
  169.  
  170. /**
  171. * Called automatically after initialization of this actor.
  172. * <p>
  173. * By default it changes the state of <i>this</i> to {{#crossLink "ProAct.States/ready:property"}}{{/crossLink}}.
  174. * </p>
  175. * <p>
  176. * It can be overridden to define more complex initialization logic.
  177. * </p>
  178. *
  179. * @for ProAct.Actor
  180. * @instance
  181. * @protected
  182. * @method afterInit
  183. */
  184. afterInit: function () {
  185. this.state = P.States.ready;
  186. },
  187.  
  188. /**
  189. * Closes this actor => it state becomes {{#crossLink "ProAct.States/closed:property"}}{{/crossLink}}.
  190. *
  191. * This sends a `close` event to all the subscribers to closing.
  192. *
  193. * After closing the actor it can't emit events anymore.
  194. *
  195. * Example:
  196. * ```
  197. * var actor = new ProAct.Actor();
  198. * actor.onClose(function () {
  199. * console.log('Done!');
  200. * });
  201. *
  202. * actor.close(); // We will see 'Done!' on the console output.
  203. * ```
  204. *
  205. * @for ProAct.Actor
  206. * @instance
  207. * @method close
  208. * @return {ProAct.Actor} This instance - can be chained.
  209. */
  210. close: function () {
  211. if (this.state === P.States.closed) {
  212. return;
  213. }
  214. return ActorUtil.update.call(this, P.Actor.Close, 'close');
  215. },
  216.  
  217. /**
  218. * Checks if <i>this</i> can be closed.
  219. * <p>
  220. * Defaults to return true.
  221. * </p>
  222. *
  223. * @for ProAct.Actor
  224. * @protected
  225. * @instance
  226. * @method canClose
  227. */
  228. canClose: function () {
  229. return true;
  230. },
  231.  
  232. /**
  233. * This method is called when a `close` event is pushed to this `Actor`.
  234. *
  235. * It removes all the subscriptions to the `Actor` and sets its
  236. * state to {{#crossLink "ProAct.States/closed:property"}}{{/crossLink}}.
  237. *
  238. * Do not call this method; it is private!
  239. *
  240. * @for ProAct.Actor
  241. * @private
  242. * @instance
  243. * @protected
  244. * @method doClose
  245. */
  246. doClose: function () {
  247. this.state = P.States.closed;
  248. this.offAll();
  249. if (this.listener) {
  250. this.listener.closed = true;
  251. }
  252. },
  253.  
  254. /**
  255. * Called immediately before destruction.
  256. *
  257. * The idea is to be implemented by extenders to free additional resources on destroy.
  258. *
  259. * @for ProAct.Actor
  260. * @instance
  261. * @abstract
  262. * @protected
  263. * @method beforeDestroy
  264. */
  265. beforeDestroy: function () {
  266. },
  267.  
  268. /**
  269. * Destroys this `ProAct.Actor` instance.
  270. * <p>
  271. * The state of <i>this</i> is set to {{#crossLink "ProAct.States/destroyed:property"}}{{/crossLink}}.
  272. * </p>
  273. *
  274. * Calls {{#crossLink "ProAct.Actor/beforeDestroy:method"}}{{/crossLink}}
  275. *
  276. * @for ProAct.Actor
  277. * @instance
  278. * @method destroy
  279. */
  280. destroy: function () {
  281. if (this.state === P.States.destroyed) {
  282. return;
  283. }
  284.  
  285. this.beforeDestroy();
  286.  
  287. this.listeners = undefined;
  288.  
  289. if (this.listener) {
  290. this.listener.destroyed = true;
  291. }
  292. this.listener = undefined;
  293. this.errListener = undefined;
  294. this.closeListener = undefined;
  295. this.parent = undefined;
  296.  
  297. this.queueName = undefined;
  298. this.transforms = undefined;
  299.  
  300. this.state = P.States.destroyed;
  301. },
  302.  
  303. /**
  304. * Generates the initial listeners object.
  305. * It can be overridden for alternative listeners collections.
  306. * It is used for resetting all the listeners too.
  307. *
  308. * The default types of listeners are:
  309. * ```
  310. * {
  311. * change: [],
  312. * error: [],
  313. * close: []
  314. * }
  315. * ```
  316. *
  317. * @for ProAct.Actor
  318. * @instance
  319. * @protected
  320. * @method defaultListeners
  321. * @return {Object} A map containing the default listeners collections.
  322. */
  323. defaultListeners: function () {
  324. return {
  325. change: [],
  326. error: [],
  327. close: []
  328. };
  329. },
  330.  
  331. /**
  332. * A list of actions or action to be used when no action is passed for the methods working with actions.
  333. *
  334. * @for ProAct.Actor
  335. * @instance
  336. * @method defaultActions
  337. * @protected
  338. * @default 'change'
  339. * @return {Array|String} The actions to be used if no actions are provided to action related methods, like
  340. * {{#crossLink "ProAct.Actor/on:method"}}{{/crossLink}},
  341. * {{#crossLink "ProAct.Actor/off:method"}}{{/crossLink}},
  342. * {{#crossLink "ProAct.ActorUtil/update:method"}}{{/crossLink}}.
  343. */
  344. defaultActions: function () {
  345. return 'change';
  346. },
  347.  
  348. /**
  349. * Creates the <i>listener</i> of this actor.
  350. *
  351. * Every actor should have one listener that should pass to other actors.
  352. *
  353. * <p>
  354. * This listener turns the actor in a observer.
  355. * </p>
  356. * <p>
  357. * Should be overriden with specific listener, by default it returns {{#crossLink "ProAct/N:method"}}{{/crossLink}}.
  358. * </p>
  359. *
  360. * @for ProAct.Actor
  361. * @instance
  362. * @abstract
  363. * @method makeListener
  364. * @protected
  365. * @default {ProAct.N}
  366. * @return {Object} The <i>listener of this observer</i>.
  367. */
  368. makeListener: P.N,
  369.  
  370. /**
  371. * Creates the <i>error listener</i> of this actor.
  372. *
  373. * Every actor should have one error listener that should pass to other actors.
  374. *
  375. * <p>
  376. * This listener turns the actor in a observer for errors.
  377. * </p>
  378. * <p>
  379. * Should be overriden with specific listener, by default it returns {{#crossLink "ProAct/N:method"}}{{/crossLink}}.
  380. * </p>
  381. *
  382. * @for ProAct.Actor
  383. * @instance
  384. * @abstract
  385. * @method makeErrListener
  386. * @protected
  387. * @default {ProAct.N}
  388. * @return {Object} The <i>error listener of this observer</i>.
  389. */
  390. makeErrListener: P.N,
  391.  
  392. /**
  393. * Creates the <i>closing listener</i> of this actor.
  394. *
  395. * Every actor should have one closing listener that should pass to other actors.
  396. *
  397. * <p>
  398. * This listener turns the actor in a observer for closing events.
  399. * </p>
  400. * <p>
  401. * Should be overriden with specific listener, by default it returns {{#crossLink "ProAct/N:method"}}{{/crossLink}}.
  402. * </p>
  403. *
  404. * @for ProAct.Actor
  405. * @instance
  406. * @abstract
  407. * @protected
  408. * @method makeCloseListener
  409. * @default {ProAct.N}
  410. * @return {Object} The <i>closing listener of this observer</i>.
  411. */
  412. makeCloseListener: P.N,
  413.  
  414. /**
  415. * Creates the <i>event</i> to be send to the listeners on update.
  416. *
  417. * <p>
  418. * The <i>event</i> should be an instance of {{#crossLink "ProAct.Event"}}{{/crossLink}}.
  419. * </p>
  420. *
  421. * <p>
  422. * By default this method returns {{#crossLink "ProAct.Event.Types/value:property"}}{{/crossLink}} event.
  423. * </p>
  424. *
  425. * @for ProAct.Actor
  426. * @instance
  427. * @method makeEvent
  428. * @default {ProAct.Event} with type {{#crossLink "ProAct.Event.Types/value:property"}}{{/crossLink}}.
  429. * @protected
  430. * @param {ProAct.Event} source The source event of the event. It can be null
  431. * @return {ProAct.Event} The event.
  432. */
  433. makeEvent: function (source) {
  434. return new P.Event(source, this, P.Event.Types.value);
  435. },
  436.  
  437. /**
  438. * Attaches a new listener to this `ProAct.Actor`.
  439. *
  440. * The listener may be function or object that defines a <i>call</i> method.
  441. *
  442. * ```
  443. * actor.on(function (v) {
  444. * console.log(v);
  445. * });
  446. *
  447. * actor.on('error', function (v) {
  448. * console.error(v);
  449. * });
  450. *
  451. * actor.on({
  452. * call: function (v) {
  453. * console.log(v);
  454. * }
  455. * });
  456. * ```
  457. *
  458. * @for ProAct.Actor
  459. * @instance
  460. * @method on
  461. * @param {Array|String} actions
  462. * The action/actions to listen for. If this parameter is skipped or null/undefined,
  463. * the actions from {{#crossLink "ProAct.Actor/defaultActions:method"}}{{/crossLink}} are used.
  464. * <p>
  465. * The actions can be skipped and on their place as first parameter to be passed the <i>listener</i>.
  466. * </p>
  467. * @param {Object} listener
  468. * The listener to attach. It must be instance of Function or object with a <i>call</i> method.
  469. * @return {ProAct.Actor}
  470. * <b>this</b>
  471. */
  472. on: function (actions, listener) {
  473. if (!P.U.isString(actions) && !P.U.isArray(actions)) {
  474. listener = actions;
  475. actions = this.defaultActions();
  476. }
  477. if (!P.U.isArray(actions)) {
  478. actions = [actions];
  479. }
  480.  
  481. var ln = actions.length,
  482. action, i, listeners;
  483.  
  484. for (i = 0; i < ln; i ++) {
  485. action = actions[i];
  486. listeners = this.listeners[action];
  487.  
  488. if (!listeners) {
  489. listeners = this.listeners[action] = [];
  490. }
  491.  
  492. listeners.push(listener);
  493. }
  494.  
  495. return this;
  496. },
  497.  
  498. /**
  499. * Removes a <i>listener</i> from the passed <i>action</i>.
  500. *
  501. * <p>
  502. * If this method is called without parameters, all the listeners for all the actions are removed.
  503. * The listeners are reset using {{#crossLink "ProAct.Actor/defaultActions:method"}}{{/crossLink}}.
  504. * </p>
  505. *
  506. * Examples are:
  507. *
  508. * Removing a listener:
  509. * ```
  510. * var listener = function (v) {
  511. * console.log(v);
  512. * };
  513. * actor.on(listener);
  514. * actor.off(listener);
  515. * ```
  516. *
  517. * Or for removing all the listeners attached to an actor:
  518. * ```
  519. * actor.off();
  520. * ```
  521. *
  522. * Or for removing all the listeners of a given type attached to an actor:
  523. * ```
  524. * actor.off('error');
  525. * ```
  526. *
  527. * Or for removing a listener from different type of actions:
  528. * ```
  529. * var listener = function (v) {
  530. * console.log(v);
  531. * };
  532. * actor.on(listener);
  533. * actor.onErr(listener);
  534. *
  535. * actor.off(['error', 'change'], listener);
  536. * ```
  537. *
  538. * @for ProAct.Actor
  539. * @instance
  540. * @method off
  541. * @param {Array|String} actions
  542. * The action/actions to stop listening for. If this parameter is skipped or null/undefined,
  543. * the actions from {{#crossLink "ProAct.Actor/defaultActions:method"}}{{/crossLink}} are used.
  544. * <p>
  545. * The actions can be skipped and on their place as first parameter to be passed the <i>listener</i>.
  546. * </p>
  547. * @param {Object} listener
  548. * The listener to detach. If it is skipped, null or undefined all the listeners are removed from this actor.
  549. * @return {ProAct.Actor}
  550. * <b>this</b>
  551. */
  552. off: function (actions, listener) {
  553. if (!actions && !listener) {
  554. this.listeners = this.defaultListeners();
  555. return this;
  556. }
  557.  
  558. if (!P.U.isString(actions) && !P.U.isArray(actions)) {
  559. listener = actions;
  560. actions = this.defaultActions();
  561. }
  562. if (!P.U.isArray(actions)) {
  563. actions = [actions];
  564. }
  565.  
  566. var ln = actions.length,
  567. action, i, listeners;
  568.  
  569. for (i = 0; i < ln; i ++) {
  570. action = actions[i];
  571. listeners = this.listeners[action];
  572.  
  573. if (listeners) {
  574. P.U.remove(listeners, listener);
  575. }
  576. }
  577.  
  578. return this;
  579. },
  580.  
  581. /**
  582. * Attaches a new error listener to this ProAct.Actor.
  583. *
  584. * The listener may be function or object that defines a <i>call</i> method.
  585. *
  586. * This is the same as calling `on('error', listener)` on an `Actor`...
  587. *
  588. * @for ProAct.Actor
  589. * @instance
  590. * @method onErr
  591. * @param {Object} listener
  592. * The listener to attach. It must be instance of Function or object with a <i>call</i> method.
  593. * @return {ProAct.Actor}
  594. * <b>this</b>
  595. */
  596. onErr: function (listener) {
  597. return this.on('error', listener);
  598. },
  599.  
  600. /**
  601. * Removes an error <i>listener</i> from the passed <i>action</i>.
  602. *
  603. * This is the same as calling `off('error', listener)` on an `Actor`...
  604. *
  605. * @for ProAct.Actor
  606. * @instance
  607. * @method offErr
  608. * @param {Object} listener
  609. * The listener to detach. If it is skipped, null or undefined all the listeners are removed from this actor.
  610. * @return {ProAct.Actor}
  611. * <b>this</b>
  612. */
  613. offErr: function (listener) {
  614. return this.off('error', listener);
  615. },
  616.  
  617. /**
  618. * Attaches a new close notifcation listener to this `ProAct.Actor`.
  619. *
  620. * The listener may be function or object that defines a <i>call</i> method.
  621. *
  622. * This is the same as calling `on('close', listener)` on an `Actor`...
  623. *
  624. * @for ProAct.Actor
  625. * @instance
  626. * @method onClose
  627. * @param {Object} listener
  628. * The listener to attach. It must be instance of Function or object with a <i>call</i> method.
  629. * @return {ProAct.Actor}
  630. * <b>this</b>
  631. */
  632. onClose: function (listener) {
  633. return this.on('close', listener);
  634. },
  635.  
  636. /**
  637. * Removes a close notification <i>listener</i> from the passed <i>action</i>.
  638. *
  639. * This is the same as calling `off('close', listener)` on an `Actor`...
  640. *
  641. * @for ProAct.Actor
  642. * @instance
  643. * @method offClose
  644. * @param {Object} listener
  645. * The listener to detach. If it is skipped, null or undefined all the listeners are removed from this actor.
  646. * @return {ProAct.Actor}
  647. * <b>this</b>
  648. */
  649. offClose: function (listener) {
  650. return this.off('close', listener);
  651. },
  652.  
  653. /**
  654. * Attaches the passed listener to listen to values, errors and the close notification from this `ProAct.Actor`.
  655. *
  656. * The listener may be function or object that defines a <i>call</i> method.
  657. *
  658. * @for ProAct.Actor
  659. * @instance
  660. * @method onAll
  661. * @param {Object} listener
  662. * The listener to attach. It must be instance of Function or object with a <i>call</i> method.
  663. * @return {ProAct.Actor}
  664. * <b>this</b>
  665. */
  666. onAll: function (listener) {
  667. return this.on(listener).onClose(listener).onErr(listener);
  668. },
  669.  
  670. /**
  671. * Removes all notifications <i>listener</i> from the passed <i>action</i>.
  672. *
  673. * @for ProAct.Actor
  674. * @instance
  675. * @method offAll
  676. * @param {Object} listener
  677. * The listener to detach. If it is skipped, null or undefined all the listeners are removed from this actor.
  678. * @return {ProAct.Actor}
  679. * <b>this</b>
  680. */
  681. offAll: function (listener) {
  682. this.off(listener);
  683. this.off('error', listener);
  684. return this.off('close', listener);
  685. },
  686.  
  687. /**
  688. * Links source actors into this actor. This means that <i>this actor</i>
  689. * is listening for changes from the <i>sources</i>.
  690. * <p>
  691. * A good example is one stream to have another as as source -> if data comes into the source
  692. * stream, it is passed to the listening too. That way the source stream is plugged <b>into</b> the listening one.
  693. * </p>
  694. * <p>
  695. * The listeners from {{#crossLink "ProAct.Actor/makeListener:method"}}{{/crossLink}},
  696. * {{#crossLink "ProAct.Actor/makeErrListener:method"}}{{/crossLink}} and {{#crossLink "ProAct.Actor/makeCloseListener:method"}}{{/crossLink}} are used.
  697. * </p>
  698. *
  699. * Chaining actors is very powerful operation. It can be used to merge many source actors into one.
  700. *
  701. * ```
  702. * var sourceActor1 = <Actor implementation>;
  703. * var sourceActor2 = <Actor implementation>;
  704. * var actor = <Actor implementation>;
  705. *
  706. * actor.into(sourceActor1, sourceActor2);
  707. * actor.on(function (v) {
  708. * console.log(v);
  709. * });
  710. *
  711. * ```
  712. *
  713. * Now if the any of the source actors is updated, the update will be printed on the console by the `actor`.
  714. *
  715. * @for ProAct.Actor
  716. * @instance
  717. * @method into
  718. * @param [...]
  719. * Zero or more source ProAct.Actors to set as sources.
  720. * @return {ProAct.Actor}
  721. * <b>this</b>
  722. */
  723. into: function () {
  724. var args = slice.call(arguments),
  725. ln = args.length, i, source;
  726. for (i = 0; i < ln; i++) {
  727. source = args[i];
  728. source.on(this.makeListener());
  729. source.onErr(this.makeErrListener());
  730. source.onClose(this.makeCloseListener());
  731. }
  732.  
  733. return this;
  734. },
  735.  
  736. /**
  737. * The reverse of {{#crossLink "ProAct.Actor/into:method"}}{{/crossLink}} - sets <i>this actor</i> as a source
  738. * to the passed <i>destination</i> actor.
  739. *
  740. * ```
  741. * var sourceActor = <Actor implementation>;
  742. * var actor = <Actor implementation>;
  743. *
  744. * sourceActor.out(actor);
  745. * actor.on(function (v) {
  746. * console.log(v);
  747. * });
  748. *
  749. * Now if the any of the source actors is updated, the update will be printed on the console by the `actor`.
  750. *
  751. * ```
  752. *
  753. * @for ProAct.Actor
  754. * @instance
  755. * @method out
  756. * @param {ProAct.Actor} destination
  757. * The actor to set as source <i>this</i> to.
  758. * @return {ProAct.Actor}
  759. * <b>this</b>
  760. */
  761. out: function (destination) {
  762. destination.into(this);
  763.  
  764. return this;
  765. },
  766.  
  767. /**
  768. * Adds a new <i>transformation</i> to the list of transformations
  769. * of <i>this actor</i>.
  770. *
  771. * <p>
  772. * A transformation is a function or an object that has a <i>call</i> method defined.
  773. * This function or call method should have one argument and to return a transformed version of it.
  774. * If the returned value is {@link ProAct.Actor.BadValue}, the next transformations are skipped and the updating
  775. * value/event becomes - bad value.
  776. * </p>
  777. *
  778. * <p>
  779. * Every value/event that updates <i>this actor</i> will be transformed using the new transformation.
  780. * </p>
  781. *
  782. * @for ProAct.Actor
  783. * @instance
  784. * @method transform
  785. * @protected
  786. * @param {Object} transformation
  787. * The transformation to add.
  788. * @return {ProAct.Actor}
  789. * <b>this</b>
  790. */
  791. transform: function (transformation) {
  792. this.transforms.push(transformation);
  793. return this;
  794. },
  795.  
  796. /**
  797. * Adds a new <i>transformation</i> to the list of transformations
  798. * of <i>this actor</i>.
  799. *
  800. * A transformation is a function or an object that has a <i>call</i> method defined.
  801. * This function or call method should have one argument and to return a transformed version of it.
  802. * If the returned value is {@link ProAct.Actor.BadValue}, the next transformations are skipped and the updating
  803. * value/event becomes - bad value.
  804. *
  805. * Every value/event that updates <i>this actor</i> will be transformed using the new transformation.
  806. *
  807. * The idea of this method is that it just calls {{#crossLink "ProAct.Actor/transform:method"}}{{/crossLink}},
  808. * but it can be overidden from another module.
  809. *
  810. * TODO Maybe transformStored is a bad name
  811. *
  812. * @for ProAct.Actor
  813. * @instance
  814. * @method transformStored
  815. * @protected
  816. * @param {Object} transformation
  817. * The transformation to add. Can be string - to be retrieved by name.
  818. * @param {String} type
  819. * The type of the transformation, for example `mapping`.
  820. * @return {ProAct.Actor}
  821. * <b>this</b>
  822. */
  823. transformStored: function (transformation, type) {
  824. return this.transform(transformation);
  825. },
  826.  
  827. /**
  828. * Adds a mapping transformation to <i>this actor</i>.
  829. * <p>
  830. * Mapping transformations just transform one value into another. For example if we get update with
  831. * the value of <i>3</i> and we have mapping transformation that returns the updating value powered by <i>2</i>,
  832. * we'll get <i>9</i> as actual updating value.
  833. * </p>
  834. *
  835. * @for ProAct.Actor
  836. * @protected
  837. * @instance
  838. * @method mapping
  839. * @param {Object} mappingFunction
  840. * Function or object with a <i>call method</i> to use as map function.
  841. * @return {ProAct.Actor}
  842. * <b>this</b>
  843. */
  844. mapping: function (mappingFunction) {
  845. return this.transformStored(mappingFunction, 'map');
  846. },
  847.  
  848. /**
  849. * Adds a filtering transformation to <i>this actor</i>.
  850. * <p>
  851. * Filtering can be used to filter the incoming update values. For example you can
  852. * filter by only odd numbers as update values.
  853. * </p>
  854. *
  855. * @for ProAct.Actor
  856. * @instance
  857. * @protected
  858. * @method filtering
  859. * @param {Object} filteringFunction
  860. * The filtering function or object with a call method, should return boolean.
  861. * @return {ProAct.Actor}
  862. * <b>this</b>
  863. */
  864. filtering: function(filteringFunction) {
  865. var self = this,
  866. filter = filteringFunction.call ? function (val) {
  867. if (filteringFunction.call(self, val)) {
  868. return val;
  869. };
  870. return P.Actor.BadValue;
  871. } : filteringFunction;
  872.  
  873. return this.transformStored(filter, 'filter');
  874. },
  875.  
  876. /**
  877. * Adds an accumulation transformation to <i>this actor</i>.
  878. * <p>
  879. * Accumulation is used to compute a value based on the previous one.
  880. * </p>
  881. *
  882. * @for ProAct.Actor
  883. * @instance
  884. * @protected
  885. * @method accumulation
  886. * @param {Object} initVal
  887. * Initial value for the accumulation. For example '0' for sum.
  888. * @param {Object} accumulationFunction
  889. * The function to accumulate.
  890. * @return {ProAct.Actor}
  891. * <b>this</b>
  892. */
  893. accumulation: function (initVal, accumulationFunction) {
  894. if (!accumulationFunction) {
  895. accumulationFunction = initVal;
  896. initVal = undefined;
  897. }
  898.  
  899. var self = this,
  900. val = initVal,
  901. acc = accumulationFunction.call ? function (newVal) {
  902. val = accumulationFunction.call(self, val, newVal)
  903. return val;
  904. } : accumulationFunction;
  905. return this.transformStored(acc, 'acc');
  906. },
  907.  
  908. /**
  909. * Creates a new ProAct.Actor instance with source <i>this</i> and mapping
  910. * the passed <i>mapping function</i>.
  911. * <p>
  912. * Should be overridden with creating the right actor.
  913. * </p>
  914. *
  915. * ```
  916. * var actor = sourceActor.map(function (el) {
  917. * return el * el;
  918. * });
  919. * ```
  920. *
  921. * or
  922. *
  923. * ```
  924. * var actor = sourceActor.map('+');
  925. * ```
  926. *
  927. * @for ProAct.Actor
  928. * @instance
  929. * @abstract
  930. * @method map
  931. * @param {Object|Function|Strin} mappingFunction
  932. * Function or object with a <i>call method</i> to use as map function.
  933. * Can be string for predefined mapping functions.
  934. * @return {ProAct.Actor}
  935. * A new ProAct.Actor instance with the <i>mapping</i> applied.
  936. */
  937. map: P.N,
  938.  
  939. /**
  940. * Creates a new ProAct.Actor instance with source <i>this</i> and filtering
  941. * the passed <i>filtering function</i>.
  942. * <p>
  943. * Should be overridden with creating the right actor.
  944. * </p>
  945. *
  946. * ```
  947. * var actor = sourceActor.filter(function (el) {
  948. * return el % 2 == 0;
  949. * });
  950. * ```
  951. *
  952. * or
  953. *
  954. * ```
  955. * var actor = sourceActor.filter('odd');
  956. *
  957. * ```
  958. *
  959. * @for ProAct.Actor
  960. * @instance
  961. * @abstract
  962. * @method filter
  963. * @param {Object} filteringFunction
  964. * The filtering function or object with a call method, should return boolean.
  965. * @return {ProAct.Actor}
  966. * A new ProAct.Actor instance with the <i>filtering</i> applied.
  967. */
  968. filter: P.N,
  969.  
  970. /**
  971. * Creates a new ProAct.Actor instance with source <i>this</i> and accumulation
  972. * the passed <i>accumulation function</i>.
  973. * <p>
  974. * Should be overridden with creating the right actor.
  975. * </p>
  976. *
  977. * ```
  978. * var actor = sourceActor.accumulate(0, function (current, el) {
  979. * return current + el;
  980. * });
  981. * ```
  982. *
  983. * or
  984. *
  985. * ```
  986. * var actor = sourceActor.accumulate('+');
  987. * ```
  988. *
  989. * @for ProAct.Actor
  990. * @instance
  991. * @abstract
  992. * @method accumulate
  993. * @param {Object} initVal
  994. * Initial value for the accumulation. For example '0' for sum.
  995. * @param {Object} accumulationFunction
  996. * The function to accumulate.
  997. * @return {ProAct.Actor}
  998. * A new ProAct.Actor instance with the <i>accumulation</i> applied.
  999. */
  1000. accumulate: P.N,
  1001.  
  1002. /**
  1003. * Defers a ProAct.Actor listener.
  1004. * <p>
  1005. * By default this means that the listener is put into active {{#crossLink "ProAct.Flow"}}{{/crossLink}} using it's
  1006. * {{#crossLink "ProAct.Flow/pushOnce:method"}}{{/crossLink}} method, but it can be overridden.
  1007. * </p>
  1008. *
  1009. * This method determines the order of actions, triggered by the changes in the data flow.
  1010. * The default implementation is executing only one update on this Actor per data flow change.
  1011. * This means that if the `Actor` depends on other three Actors, and all of them get updated,
  1012. * it is updated only once with the last update value.
  1013. *
  1014. * @for ProAct.Actor
  1015. * @protected
  1016. * @instance
  1017. * @method defer
  1018. * @param {Object} event
  1019. * The event/value to pass to the listener.
  1020. * @param {Object} listener
  1021. * The listener to defer. It should be a function or object defining the <i>call</i> method.
  1022. * @return {ProAct.Actor}
  1023. * <i>this</i>
  1024. */
  1025. defer: function (event, listener) {
  1026. var queueName = (listener.queueName) ? listener.queueName : this.queueName;
  1027.  
  1028. if (P.U.isFunction(listener)) {
  1029. P.flow.pushOnce(queueName, listener, [event]);
  1030. } else {
  1031. P.flow.pushOnce(queueName, listener, listener.call, [event]);
  1032. }
  1033. return this;
  1034. }
  1035. };
  1036.