JSFiddle - React, Tailwind, and code Playground

by blparker

HTML

<link rel="stylesheet" href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css">
<div id="player">
    <div id="container">
        <div id="controls">
            <button class="btn"><i class="icon-play"></i></button>
        </div>
        <div id="progress"><div></div></div>
        <div id="time">0:00</div>
    </div>
</div>

CSS

#player {
    overflow: hidden;
}
#container {
    background: #fafafa;
    border: 1px solid #ccc;
    border-radius: 4px;
    overflow: hidden;
    padding: 20px;
    display: inline-block;
}
#progress {
    width: 300px;
    background: #ddd;
    margin: 5px 20px 0 20px;
    background-color: #f7f7f7;
    background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);
    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));
    background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);
    background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);
    background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9);
    background-repeat: repeat-x;
    -webkit-border-radius: 4px;
    -moz-border-radius: 4px;
    border-radius: 4px;
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);
    -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
    -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
}
#progress, #progress div {
    height: 20px;
}
#progress div {
    width: 0px;
    background-color: #439EE8;
    color: #fff;
    text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
    background-color: #0e90d2;
    background-image: -moz-linear-gradient(top, #149bdf, #0480be);
    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));
    background-image: -webkit-linear-gradient(top, #149bdf, #0480be);
    background-image: -o-linear-gradient(top, #149bdf, #0480be);
    background-image: linear-gradient(to bottom, #149bdf, #0480be);
    background-repeat: repeat-x;
    -webkit-border-radius: 4px;
    -moz-border-radius: 4px;
    border-radius: 4px;
}
#player #controls, #player #progress, #player #time {
    float: left;
}
#player #time {
    height: 30px;
    line-height: 30px;
}

JavaScript

function Player(options) {
    this.player = options.player;
    this.totalTime = options.time;
    this.progress = $('#progress', this.player);
    this.indicator = $('div', this.progress);
    this.time = $('#time', this.player);
    this.controls = $('#controls button', this.player);
    this.state = 0;
    this.currentTime = 0;
    this.playedToEnd = false;
    
    this.init();
}

Player.prototype = {
    init : function() {
        this.playerWidth = this.progress.width();
        this.incWidth = (this.playerWidth / this.totalTime);
        this.controls.on('click', $.proxy(this.toggleState, this));
        this.progress.on('click', $.proxy(this.seek, this));
        
        this.toggleState();
    },
    updateTime : function(seconds) {
        var ts = '';

        if(seconds >= 60) {
            var minutes = Math.floor(seconds / 60);
            ts += minutes + ':';
            seconds -= (minutes * 60);
        }
        else {
            ts += '0:';
        }
        
        if(seconds < 10) {
            ts += '0';
        }
        
        ts += seconds;
        this.time.text(ts);
    },
    toggleState : function(e) {
        $('i', this.controls).toggleClass('icon-play icon-pause');
        
        if(this.state === 0) {    // Currently paused
            this.play();
        }
        else {               // Currently playing
            this.pause();
        }
    },
    pause : function() {
        this.state = 0;
        clearInterval(this.timeInterval);
    },
    play : function() {
        this.state = 1;
        
        if(this.playedToEnd) {
            this.reset();
            this.playedToEnd = false;
        }

        this.timeInterval = setInterval($.proxy(function() {

            this.indicator.animate({
                width : (++this.currentTime * this.incWidth)
            }, 1000, 'linear');
            
            //this.indicator.width(++this.currentTime * this.incWidth);
           ...