# Code coverage report for lib/runloop.js

## Statements: 100% (39 / 39) Branches: 100% (22 / 22) Functions: 100% (7 / 7) Lines: 100% (37 / 37) Ignored: 2 statements, 1 function, 1 branch

All files » lib/ » runloop.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    1011

    1

    1
    1
    1

    1
    6

    1
    8
    8
    8

    1

    5

    134

    134
    20
    5

    20

    114

    114

    114
    77
    77

    77
    77
    77

    145
    145
    145

    145
    114
    114
    114

    114
    1

    145

    1
     var protoclass = require("protoclass");

    var rAF = (global.requestAnimationFrame      ||
              global.webkitRequestAnimationFrame ||
              global.mozRequestAnimationFrame    ||
              process.nextTick).bind(global);

    /* istanbul ignore next */
    Iif (process.browser) {
      var defaultTick = function(next) {
        rAF(next);
      };
    } else {
      var defaultTick = function(next) {
        next();
      };
    }

    /**
     */

    function RunLoop(options) {
      this._animationQueue = [];
      this.tick = options.tick || defaultTick;
      this._id = options._id || 2;
    }

    protoclass(RunLoop, {

      /**
       * child runloop in-case we get into recursive loops
       */

      child: function() {
        return this.__child || (this.__child = new RunLoop({ tick: this.tick, _id: this._id << 2 }));
      },

      /**
       * Runs animatable object on requestAnimationFrame. This gets
       * called whenever the UI state changes.
       *
       * @method animate
       * @param {Object} animatable object. Must have `update()`
       */

      deferOnce: function(context) {

        if (!context.__running) context.__running = 1;

        if (context.__running & this._id) {
          if (this._running) {
            this.child().deferOnce(context);
          }
          return;
        }

        context.__running |= this._id;

        // push on the animatable object
        this._animationQueue.push(context);

        // if animating, don't continue
        if (this._requestingFrame) return;
        this._requestingFrame = true;
        var self = this;

        // run the animation frame, and callback all the animatable objects
        this.tick(function() {
          self.runNow();
          self._requestingFrame = false;
        });
      },

      /**
       */

      runNow: function() {
        var queue = this._animationQueue;
        this._animationQueue = [];
        this._running = true;

        // queue.length is important here, because animate() can be
        // called again immediately after an update
        for (var i = 0; i < queue.length; i++) {
          var item = queue[i];
          item.update();
          item.__running &= ~this._id;

          // check for anymore animations - need to run
          // them in order
          if (this._animationQueue.length) {
            this.runNow();
          }
        }

        this._running = false;
      }
    });

    module.exports = RunLoop;