- /**
- * @module proact-core
- */
-
-
- /**
- * ActorUtil provides methods that can be used to make the Actor to 'act'.
- * The Actor is ProAct.js version of the base `Observable` object. Various types
- * of listeners can be attached to it and used to observe its `actions`.
- *
- * On the other hand the `Actor` should do something or `act`, because something
- * has to be observed after all.
- *
- * The `ActorUtil` contains a set of methods that help implementing these `acts`.
- *
- * For example the we can trigger events/values in the `Streams`. This is thier `act`.
- * This triggering can be implemented with ease using the methods defined in `ActorUtil`.
- *
- * Another example is `Properties` - they can be set or updated by the reactive flow -> they should react.
- *
- * So `ActorUtil` provides the `Actors` with helpful methods for `acting` and `reacting`.
- *
- * All these methods use the {{#crossLink "ProAct.Flow"}}{{/crossLink}} to defer the changes the right way.
- * And the using the `flow` these methods handle the dependencies between the `Actors`.
- *
- * Use the methods in the `ActorUtil` to implement your `Actor's` `actions` and `reactions`.
- *
- * @namespace ProAct
- * @private
- * @class ActorUtil
- * @extensionfor ProAct.Actor
- * @static
- */
- ActorUtil = {
-
- /**
- * Updating/notifying method that can be applied to an {{#crossLink "ProAct.Actor"}}{{/crossLink}}
- *
- * This method defers the update and the notifications into {{#crossLink "ProAct.flow"}}{{/crossLink}}.
- *
- * If the state of the caller is {{#crossLink "ProAct.States.destroyed)"}}{{/crossLink}}, an exception will be thrown.
- * If the state of the caller is {{#crossLink "ProAct.States.closed)"}}{{/crossLink}}, nothing will happen.
- *
- * Examples:
- *
- * You can implement a stream and in it's `trigger` method use this:
- * ```
- * ActorUtil.update.call(this, event);
- * ```
- * This way the event will be triggered into the stream and all the listeners to the stream will be notified.
- * For this to work you'll have to override the `makeEvent` method of the stream to return the unmodified source - no state/no event generation,
- * the event will just go through.
- *
- *
- * If you want to implement a statefull `Actor` like a `property`, you can set a state in it and just notify all the
- * observing `Actors` with this method.
- *
- *
- * @method update
- * @protected
- * @param {Object} [source] The event/value, causing the update -> can be null : no source.
- * @param {Object} [actions] For which actions should notify -> can be null : default actions.
- * @param {Object} [eventData] Data for creating the updating event -> can be null : no data.
- * @return {Object} The calling object.
- */
- update: function (source, actions, eventData) {
- if (this.state === ProAct.States.destroyed) {
- throw new Error('You can not trigger actions on destroyed actors!');
- }
-
- if (this.state === ProAct.States.closed) {
- return;
- }
-
- var actor = this;
- if (!P.flow.isRunning()) {
- P.flow.run(function () {
- ActorUtil.doUpdate.call(actor, source, actions, eventData);
- });
- } else {
- ActorUtil.doUpdate.call(actor, source, actions, eventData);
- }
- return this;
- },
-
- /**
- * Contains the real notify/update logic defered by {{#crossLink "ProAct.ActorUtil/update:method"}}{{/crossLink}} into the flow.
- * It is private method, should not be used - use `update`.
- *
- * @method doUpdate
- * @private
- * @param {Object} [source] The event/value, causing the update -> can be null : no source.
- * @param {Object} [actions] For which actions should notify -> can be null : default actions.
- * @param {Object} [eventData] Data for creating the updating event -> can be null : no data.
- * @return {Object} The calling object.
- */
- doUpdate: function (source, actions, eventData) {
- if (!actions) {
- actions = this.defaultActions();
- }
-
- var ln, i, j,
- listener,
- listeners,
- length,
- event;
-
- if (P.U.isString(actions)) {
- listeners = this.listeners[actions];
- } else {
- while (actions.indexOf('close') !== -1) {
- P.U.remove(actions, 'close');
- }
-
- listeners = [];
- ln = actions.length;
-
- if (this.parent === null && actions.length === 0) {
- return this;
- }
-
- for (i = 0; i < ln; i++) {
- listenersForAction = this.listeners[actions[i]];
-
- if (listenersForAction) {
- for (j = 0; j < listenersForAction.length; j++) {
- if (listenersForAction[j].destroyed || listenersForAction[j].closed) {
- this.off(actions[i], listenersForAction[j]);
- continue;
- }
- }
- listeners = listeners.concat(listenersForAction);
- }
- }
- }
-
- if (listeners.length === 0 && this.parent === null && actions !== 'close') {
- return this;
- }
-
- if (actions === 'close' && !this.canClose()) {
- return this;
- }
-
- length = listeners.length;
- event = this.makeEvent(source, eventData);
-
- for (i = 0; i < length; i++) {
- listener = listeners[i];
- if (!listener) {
- throw new Error('Invalid null listener for actions : ' + actions);
- }
-
- if (P.U.isString(actions) && listener.destroyed) {
- this.off(actions, listener);
- continue;
- }
-
- this.defer(event, listener);
-
- if (listener.property) {
- ActorUtil.doUpdate.call(listener.property, event);
- }
- }
-
- if (this.parent && this.parent.call) {
- this.defer(event, this.parent);
- }
-
- if (actions === 'close') {
- P.flow.pushClose(this, this.doClose);
- }
-
- return this;
- }
- };
- P.U.defValProp(ProAct, 'ActorUtil', false, false, false, ActorUtil);
-
-