<!DOCTYPE html>
<html ng-app="myApp">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <link data-require="bootstrap-css@*" data-semver="3.0.0-rc2" rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0-rc2/css/bootstrap.min.css" />
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.1.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js" data-semver="1.1.5"></script>
    <script src="http://pc035860.github.io/ngQueue/ngQueue.min.js"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl" ng-init="asyncDelay = 300">
    <a href="https://github.com/pc035860/ngQueue">
      <img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub" />
    </a>
    <div class="container">
      <h3>ngQueue demo</h3>
      <br />
      <div class="row">
        <div class="col-xs-4 text-center">
          <button type="button" class="btn btn-primary" ng-click="queueSync()">queue sync</button>
        </div>
        <div class="col-xs-4 text-center">
          <button type="button" class="btn btn-success" ng-click="queueAsync()">queue async</button>
        </div>
        <div class="col-xs-4 text-center">
          <button type="button" class="btn btn-danger" ng-click="queueRandom(10)">random x 10</button>
        </div>
      </div>
      <hr />
      <div class="view-queue">
        <div class="row" ng-repeat="item in vq" ng-animate="{enter: 'ng-enter', leave: 'ng-leave'}">
          <div class="col-xs-2 text-right">{{ item[0] }}</div>
          <div class="col-xs-10 text-left">
            <span class="label" ng-class="{'sync': 'label-primary', 'async': 'label-success'}[item[1]]">{{ item[1] }}</span>
            <span ng-if="item[2]">
              <small class="countdown-text">
                <span ng-hide="item[3]">{{ item[2] }}</span>
                <span class="active" ng-if="item[3]" ui-countdown="{{ item[2] }}"></span>
                ms
              </small>
            </span>
          </div>
        </div>
      </div>
    </div>
  </body>

</html>
var app = angular.module('myApp', ['ngQueue']);

app.directive('uiCountdown', function($window, $timeout) {
  return {
    restrict: 'EA',
    scope: {
      startFrom: "@uiCountdown"
    },
    link: function postLink(scope, iElm, iAttrs) {
      var _requestAnimFrame = (function(){
              return  $window.requestAnimationFrame       ||
                      $window.webkitRequestAnimationFrame ||
                      $window.mozRequestAnimationFrame    ||
                      function( callback ){
                        $window.setTimeout(callback, 1000 / 60);
                      };
            })(),
          _start,
          _counter;

      scope.$watch('startFrom', function (val) {

        if (angular.isDefined(val)) {
          _start = _now();
          _tick();
        }
        
      });

      function _now () {
        return (new Date()).getTime();
      }

      function _tick () {
        var diff = _now() - _start,
            result = Math.max(0, scope.startFrom - diff);

        iElm.text(result >>> 0);

        if (result > 0) {
          _requestAnimFrame(_tick);
        }
      }
    }
  };
});

app.controller('MainCtrl', function($scope, $queueFactory, $q, $timeout) {
  
  var _taskId = 1,
      // two concurrent tasks available
      _queue = $queueFactory(2);
  
  // view queue for demostration
  $scope.vq = [];
  
  $scope.queueSync = function () {
    
    var taskId = _taskId++, 
        obj = [taskId, 'sync'];
    
    $scope.vq.push(obj);
    _queue.enqueue(function (vqObj) {
      _removeFromVQ(vqObj);
    }, null, [obj]);
    
  };
  
  $scope.queueAsync = function () {
    
    var taskId = _taskId++, 
        duration = (Math.random() * 500 + 600) >>> 0,
        obj = [taskId, 'async', duration];
    
    $scope.vq.push(obj);
    _queue.enqueue(function (vqObj) {
      
      var dfd = $q.defer();
      
      $timeout(function () {
        _removeFromVQ(vqObj);
        dfd.resolve();
      }, duration);
      
      // start countdown
      vqObj.push(true);
      
      return dfd.promise;
      
    }, null, [obj]);
  };
  
  $scope.queueRandom = function (itrCount) {

    for (var i = 0; i < itrCount; i++) {
      if (Math.random() >= 0.5) {
        $scope.queueAsync();
      }
      else {
        $scope.queueSync();
      }
    }
  };
  
  // start with 30 random tasks
  $scope.queueRandom(30);
  
  function _removeFromVQ(obj) {
    $scope.vq.splice($scope.vq.indexOf(obj), 1);
  }
});
/* Put your css in here */
.container {
  overflow: hidden;
}

.view-queue {
  font-size: 22px;
}

.view-queue ul {
  list-style-type: none;
  margin-left: 0;
  padding-left: 0;
}

.view-queue > .row {
  overflow: hidden;
  height: 41px;
  
  -webkit-animation-duration: 600ms;
  -moz-animation-duration: 600ms;
  -ms-animation-duration: 600ms;
  -o-animation-duration: 600ms;
  animation-duration: 600ms;

  -webkit-animation-fill-mode: both;
  -moz-animation-fill-mode: both;
  -ms-animation-fill-mode: both;
  -o-animation-fill-mode: both;
  animation-fill-mode: both;

-webkit-transition-timing-function: cubic-bezier(0.390, 0.575, 0.565, 1.000); 
   -moz-transition-timing-function: cubic-bezier(0.390, 0.575, 0.565, 1.000); 
    -ms-transition-timing-function: cubic-bezier(0.390, 0.575, 0.565, 1.000); 
     -o-transition-timing-function: cubic-bezier(0.390, 0.575, 0.565, 1.000); 
        transition-timing-function: cubic-bezier(0.390, 0.575, 0.565, 1.000); /* easeOutSine */
}


.view-queue .row.ng-enter {
  -webkit-animation-name: "grow";
  -moz-animation-name: "grow";
  -ms-animation-name: "grow";
  -o-animation-name: "grow";
  animation-name: "grow";
}

.view-queue .row.ng-leave {
  -webkit-animation-name: "ungrow";
  -moz-animation-name: "ungrow";
  -ms-animation-name: "ungrow";
  -o-animation-name: "ungrow";
  animation-name: "ungrow";
}

.view-queue .countdown-text {
  font-size: 12px;
  color: #aaa;
}

.view-queue .countdown-text .active {
  color: #333;
  font-weight: bold;
}

/* miss from the cdn ? */
.label-primary {
  background-color: #428bca;
}

.label-primary[href]:hover,
.label-primary[href]:focus {
  background-color: #3071a9;
}

@-webkit-keyframes "ungrow" {
  from {
    height: 41px;
    opacity: 1;
  }
  to {
    height: 0px;
    opacity: 0;
  }
}

@-moz-keyframes "ungrow" {
  from {
    height: 41px;
    opacity: 1;
  }
  to {
    height: 0px;
    opacity: 0;
  }
}

@-o-keyframes "ungrow" {
  from {
    height: 41px;
    opacity: 1;
  }
  to {
    height: 0px;
    opacity: 0;
  }
}

@keyframes "ungrow" {
  from {
    height: 41px;
    opacity: 1;
  }
  to {
    height: 0px;
    opacity: 0;
  }
}

@keyframes "grow" {
 from {
    height: 0px;
    opacity: 0;
 }
 to {
    height: 41px;
    opacity: 1;
 }

}

@-moz-keyframes grow {
 from {
   height: 0px;
   filter: alpha(opacity=0);
   opacity: 0;
 }
 to {
   height: 41px;
   filter: alpha(opacity=100);
   opacity: 1;
 }

}

@-webkit-keyframes "grow" {
 from {
   height: 0px;
   opacity: 0;
 }
 to {
   height: 41px;
   opacity: 1;
 }

}

@-o-keyframes "grow" {
 from {
   height: 0px;
   filter: alpha(opacity=0);
   opacity: 0;
 }
 to {
   height: 41px;
   filter: alpha(opacity=100);
   opacity: 1;
 }

}