/public/js/MusicPlayer.js
JavaScript | 326 lines | 233 code | 82 blank | 11 comment | 11 complexity | 22175a44a56f48e40cf31850ae108c8c MD5 | raw file
- (function($) {
-
- // Prepare 'namespace'
- MusicPlayer = {};
- MusicPlayer.Track = Backbone.Model.extend({ }); // model
-
- MusicPlayer.Library = Backbone.Collection.extend({ // this is collection
- model: MusicPlayer.Track,
- url: '/musiclibrary'
- });
-
- MusicPlayer.Playlist = MusicPlayer.Library.extend({ // this is playlist collection (notice extend from Library collection)
- isFirstTrack: function(index) {
- return (index == 0);
- },
-
- isLastTrack: function(index) {
- return (index == (this.models.length - 1)); // 'models' method on collection is legit - returns array of all models
- },
-
- lastTrack: function() {
- return this.models.length - 1;
- },
-
- trackUrlAtIndex: function (index) {
- return this.models[index].attributes.url;
- }
-
- });
-
-
- MusicPlayer.Player = Backbone.Model.extend({ //this model uses playlist as a global object
- defaults: {
- 'currentTrackIndex': 0,
- 'state': 'stop'
- },
-
- initialize: function() {
- //this.thePlaylist = playlist;
- },
-
- play: function() {
- this.set({'state': 'play'});
- },
-
- pause: function() {
- this.set({'state': 'pause'});
- },
-
- isPlaying: function() {
- return (this.get('state') == 'play');
- },
-
- isStopped: function() {
- return (!this.isPlaying());
- },
-
- currentTrack: function() {
- return playlist.at(this.get('currentTrackIndex'));
- },
-
- currentTrackUrl: function() {
- return playlist.trackUrlAtIndex(this.get('currentTrackIndex'));
- },
-
- nextTrack: function() {
- var currentTrackIndex = this.get('currentTrackIndex');
-
- if(playlist.isLastTrack(currentTrackIndex)){
- this.set({'currentTrackIndex': 0});
- } else {
- this.set({'currentTrackIndex': currentTrackIndex + 1});
- }
- this.logCurrentTrack();
- },
-
- prevTrack: function() {
- var currentTrackIndex = this.get('currentTrackIndex');
-
- if(playlist.isFirstTrack(currentTrackIndex)){
- this.set({'currentTrackIndex': playlist.lastTrack()});
- } else {
- this.set({'currentTrackIndex': currentTrackIndex - 1});
- }
- this.logCurrentTrack();
- },
-
- logCurrentTrack: function() {
- console.log("Player track is: " + this.get('currentTrackIndex'), this);
- }
-
- });
-
-
-
- // views
-
- MusicPlayer.TrackView = Backbone.View.extend({
- initialize: function () {
- this.template = _.template($('#track-template').html()); // initializes the jQuery template
- },
-
- render: function () {
- var renderedContent = this.template (this.model.toJSON()); // fills the template with values
- $(this.el).html(renderedContent); // attachs to parent? => [TC] attaches rendered HTML to the view's top-level DOM element
- return this; // enables chaining
- },
-
- events: {
- 'click .queue.add': 'select', // calls select method on click event
- 'click .queue.remove': 'removeFromPlaylist'
- },
-
- select: function () { //?? how does the view know what is the collection of its model?
- this.collection.trigger('select', this.model); // triggers select, passes this model as an argument
- //console.log("I just triggered a select", this.model);
- },
-
- removeFromPlaylist: function () {
- this.options.playlist.remove(this.model); //remove is triggered directly on playlist collection that is passed as a parameter to TrackView
- //console.log("I just triggered a remove", this.model);
- }
-
-
- })
-
-
- MusicPlayer.LibraryView = Backbone.View.extend({
- initialize: function () {
- _.bindAll(this,'render'); // this binds context to always be this view (not ajax something that calls it)
- this.template = _.template($('#library-template').html());
- //this.collection.bind('reset', this.render); // this should be commented when running tests, because this causes an error
- },
-
- render: function () {
- var $tracks,
- collection = this.collection;
- $(this.el).html(this.template({})); // fills template with no data
- $tracks = this.$(".tracks"); // sets the place for model instances
- // => [TC] more precisely, it fetches a reference to the DOM element into which rendered child views HTML will be appended to
- // this.$() is a Backbone view's convenience method that says search for ".tracks" within my template only, not the whole DOM
- collection.each(function(track) {
- var view = new MusicPlayer.TrackView({
- model: track,
- collection: collection // now track view can pass select trigger to collection
- });
-
- $tracks.append(view.render().el)
- })
- return this;
- }
-
- })
-
-
- MusicPlayer.PlaylistView = Backbone.View.extend({
- // tagName: 'section',
- // className: 'playlist', // taken from video but not necessary adds section tag with 'playlist' class
-
- initialize: function () {
- _.bindAll(this, 'render', 'renderTrack', 'queueTrack', 'renderWithObjects', 'updateTrack');
- this.template = _.template($('#playlist-template').html());
- this.collection.bind('reset', this.render);
- this.collection.bind('add', this.renderTrack); // on collection add event, execute method
- this.collection.bind('remove', this.renderWithObjects); // calls a method to re-render the whole playlist with the rest of models in it
-
- this.library = this.options.library; // library is given as a property of param object
- this.library.bind('select', this.queueTrack); // on library 'select' event, execute given method
-
- this.player = this.options.player;
- this.player.bind('change:currentTrackIndex', this.updateTrack);
- this.player.bind('change:state', this.updateTrack);
- },
-
- render: function () {
- $(this.el).html(this.template());
- return this;
- },
-
- renderTrack: function(track) { // track is passed as a param, see queueTrack method
- var view = new MusicPlayer.TrackView({
- model: track,
- playlist: this.collection // playlist is passed to this class as a parameter
- });
- this.$('ul').append(view.render().el); // after track view is made, append it to playlist
- },
-
- queueTrack: function(track) { // this method adds to playlist collection (and triggers the add event)
- this.collection.add(track);
- },
-
- renderWithObjects: function() { // re - renders the whole playlist
- var $tracks,
- collection = this.collection;
- $(this.el).html(this.template({}));
- $tracks = this.$(".tracks");
- collection.each(function(track) {
- var view = new MusicPlayer.TrackView({
- model: track,
- playlist: collection
- });
- $tracks.append(view.render().el);
- });
-
- return this;
- },
-
- updateTrack: function() {
- var currentTrackIndex = this.player.get('currentTrackIndex');
- this.$("li").each(function(index, el) {
- $(el).toggleClass('current', index == currentTrackIndex);
- });
- console.log("TrackUpdated");
- }
-
- })
-
- MusicPlayer.PlayerView = Backbone.View.extend({
- initialize: function () {
- _.bindAll(this, 'render', 'updateTrack', 'updateState');
- this.template = _.template($('#player-template').html());
- this.createAudio();
-
- this.player = this.options.player;
- this.player.bind('change:state', this.updateState);
- this.player.bind('change:currentTrackIndex', this.updateTrack);
-
- },
-
- render: function () {
- $(this.el).html(this.template());
-
- this.$('button.play').toggle(this.player.isStopped()); // shows the play button if the player is stopped
- this.$('button.pause').toggle(this.player.isPlaying());
- return this;
- },
-
- createAudio: function() {
- this.audio = new Audio();
- },
-
- updateState: function() {
- this.updateTrack();
- this.$("button.play").toggle(this.player.isStopped());
- this.$('button.pause').toggle(this.player.isPlaying());
- },
-
- updateTrack: function() {
- this.audio.src = this.player.currentTrackUrl();
- if (this.player.get('state') == 'play') {
- this.audio.play();
- } else {
- this.audio.pause();
- }
- },
-
- events: {
- 'click .play': 'play',
- 'click .pause': 'pause',
- 'click .next': 'nextTrack',
- 'click .prev': 'prevTrack'
- },
-
- play: function() {
- this.player.play();
- },
-
- pause: function() {
- this.player.pause();
- },
-
- nextTrack: function() {
- this.player.nextTrack();
- },
-
- prevTrack: function() {
- this.player.prevTrack();
- }
- })
-
-
- MusicPlayer.Router = Backbone.Router.extend({
- routes: {
- '': 'home'
- },
-
- initialize: function(){
- library = new MusicPlayer.Library(); // new collection
- libraryView = new MusicPlayer.LibraryView({collection: library}); // instantiates view (collection is a param)
- player = new MusicPlayer.Player();
- playerView = new MusicPlayer.PlayerView({player: player});
- playlist = new MusicPlayer.Playlist();
- playlistView = new MusicPlayer.PlaylistView({collection: playlist, library: library, player: player});
- },
- home: function(){
- $('#music-library').append(libraryView.render().el); // sticks collection view to hard coded html
- $('#playlist').append(playlistView.render().el); // this adds playlist view to hardcoded html
- $('#player').append(playerView.render().el); // adds player controls to view
- }
-
- });
- $(function(){
- window.App = new MusicPlayer.Router();
- Backbone.history.start();
- });
- // this runs on page load and bootstraps the app
- $(document).ready(function() {
-
- library.fetch(); // fetches elements and triggers collection view 'reset'
- });
-
- })(jQuery);