angular empty fiddle

http://angularjs.org/

by gion_13

HTML

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<div ng-controller="myCtrl">
    <ul class="track-list">
        <li class="row" ng-repeat="track in tracks" ng-class='{"running":!!track.running, "finished":!!track.finished}'>
            <div class="background" style="width:{{track.percent}}%"></div>
            <h3>track #{{$index+1}}</h3>
            Play 
            <select ng-model="track.sound" ng-options="sound.name for sound in availableSounds"></select>
            at
            <input type="number" class="bpm" ng-model="track.bpm"/> 
            bpm for
            <input type="number" class="duration" ng-model="track.duration"/> 
            minutes
            <a href="#" ng-click="removeTrack($index)">remove</a>
            <br>
            percent: {{track.percent}}%
            <br>
            beats: {{track.beats}}
                
            <br>
            sound: {{track.sound.name}}
        </li>
    </ul>
    <h2>total duration: {{totalTime}} minutes</h2>
    <a href="#" ng-click="addTrack()">add track</a> 
    <br>
    <button ng-click="start()">start</button>
    <button ng-click="done()">stop</button>
    
    <div class="hidden-tracks">
        <audio ng-repeat="sound in availableSounds" src="{{sound.src}}" id="sound-{{sound.name}}" controls></audio>    
    <div>
</div>

CSS

input{
    width: 50px;
}
.running .background{
    background: red;
}

.finished{
    background: #ccc;
    opacity: .7;
}
.finished .backrgound{
    display: none;
}

.hidden-tracks{
    display: none;
}

li{
    position: relative;
}
.background{
    position: absolute;
    z-index: -1;
    height: 100%;
    width: 0;
}

JavaScript

angular
.module('myApp', ['Scope.safeApply'])

// controller here
.controller('myCtrl', function($scope) {
    $scope.tracks = [];
    
    window.t =  $scope.tracks;
    
    window.s =  $scope;
    
    $scope.removeTrack = function($index){
        $scope.tracks.splice($index, 1);
    }
    
    $scope.addTrack = function(){
        $scope.tracks.push(new Track({}));
    }
    
    $scope.totalTime = 0;
    $scope.$watch('tracks', function(){
        var t = 0;
        angular.forEach($scope.tracks, function(el){
            t += el.duration;
        });
        $scope.totalTime = t;
        $scope.currentTrackIndex = 0;
    });
    
    $scope.nextTrack = function(){
        $scope.currentTrackIndex++;
        if($scope.currentTrackIndex > $scope.tracks.length - 1){
            $scope.done();
        } else {
            $scope.start();
        }
    }
    
    $scope.done = function(){
        alert('done!!!');
    }
    
    $scope.start = function(){
        $scope.tracks[$scope.currentTrackIndex].run();
    }
    
    $scope.availableSounds = [
         {
             name: 'tick',
             src : 'http://www.webmetronome.com/audio/tick.mp3',
         },
         {
             name: 'tock',
             src : 'http://www.webmetronome.com/audio/tock.mp3',
         }
     ];
    
    $scope.playSound = function($sound){
        if(!$sound.api) {
            $sound.api = angular.element('#sound-' + $sound.name)[0];
        }
        
        $sound.api.play();
    }
    
    function Track(options){
        var self = this;
        
        this.duration = 10 || options.duration;
        this.bpm = 60 || options.bpm;
        this.sound = $scope.availableSounds[0];
        this.beats = 0;
        this.percent = 0;
        
        this.o = options;
        
        return this.init(options);
    }
    
    angular.extend(Track.prototype, {
        init: function(o){
            this.options = o;
        },
        run: function(){
            var self =...